| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | #pragma once#include <atomic>#include <functional>#include <memory>#include <string>#include <unordered_map>#include <vector>#include "BellTask.h"#include "Logger.h"#include "NanoPBHelper.h"#include "Packet.h"#include "Queue.h"#include "Session.h"#include "TimeProvider.h"#include "Utils.h"#include "protobuf/mercury.pb.h"namespace cspot { class MercurySession : public bell::Task, public cspot::Session { public:  MercurySession(std::shared_ptr<cspot::TimeProvider> timeProvider);  ~MercurySession();  typedef std::vector<std::vector<uint8_t>> DataParts;  struct Response {    Header mercuryHeader;    uint8_t flags;    DataParts parts;    uint64_t sequenceId;    bool fail;  };  typedef std::function<void(Response&)> ResponseCallback;  typedef std::function<void(bool, const std::vector<uint8_t>&)> AudioKeyCallback;  typedef std::function<void()> ConnectionEstabilishedCallback;  enum class RequestType : uint8_t {    SUB = 0xb3,    UNSUB = 0xb4,    SUBRES = 0xb5,    SEND = 0xb2,    GET = 0xFF,  // Shitty workaround, it's value is actually same as SEND    PING = 0x04,    PONG_ACK = 0x4a,    AUDIO_CHUNK_REQUEST_COMMAND = 0x08,    AUDIO_CHUNK_SUCCESS_RESPONSE = 0x09,    AUDIO_CHUNK_FAILURE_RESPONSE = 0x0A,    AUDIO_KEY_REQUEST_COMMAND = 0x0C,    AUDIO_KEY_SUCCESS_RESPONSE = 0x0D,    AUDIO_KEY_FAILURE_RESPONSE = 0x0E,    COUNTRY_CODE_RESPONSE = 0x1B,  };  std::unordered_map<RequestType, std::string> RequestTypeMap = {      {RequestType::GET, "GET"},      {RequestType::SEND, "SEND"},      {RequestType::SUB, "SUB"},      {RequestType::UNSUB, "UNSUB"},  };  void handlePacket();  uint64_t executeSubscription(RequestType type, const std::string& uri,                               ResponseCallback callback,                               ResponseCallback subscription, DataParts& parts);  uint64_t executeSubscription(RequestType type, const std::string& uri,                               ResponseCallback callback,                               ResponseCallback subscription) {    DataParts parts = {};    return this->executeSubscription(type, uri, callback, subscription, parts);  }  uint64_t execute(RequestType type, const std::string& uri,                   ResponseCallback callback) {    return this->executeSubscription(type, uri, callback, nullptr);  }  uint64_t execute(RequestType type, const std::string& uri,                   ResponseCallback callback, DataParts& parts) {    return this->executeSubscription(type, uri, callback, nullptr, parts);  }  void requestAudioKey(const std::vector<uint8_t>& trackId,                       const std::vector<uint8_t>& fileId,                       AudioKeyCallback audioCallback);  std::string getCountryCode();  void disconnect();  void setConnectedHandler(ConnectionEstabilishedCallback callback);  bool triggerTimeout() override; private:  const int PING_TIMEOUT_MS = 2 * 60 * 1000 + 5000;  std::shared_ptr<cspot::TimeProvider> timeProvider;  Header tempMercuryHeader = {};  ConnectionEstabilishedCallback connectionReadyCallback = nullptr;  bell::Queue<cspot::Packet> packetQueue;  void runTask() override;  void reconnect();  std::unordered_map<uint64_t, ResponseCallback> callbacks;  std::unordered_map<std::string, ResponseCallback> subscriptions;  AudioKeyCallback audioKeyCallback;  uint64_t sequenceId = 1;  uint32_t audioKeySequence = 1;  unsigned long long timestampDiff;  unsigned long long lastPingTimestamp = -1;  std::string countryCode = "";  std::mutex isRunningMutex;  std::atomic<bool> isRunning = false;  std::atomic<bool> isReconnecting = false;  std::atomic<bool> executeEstabilishedCallback = false;  void failAllPending();  Response decodeResponse(const std::vector<uint8_t>& data);};}  // namespace cspot
 |