| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 | #pragma once#include <atomic>         // for atomic#include <cstdint>        // for uint8_t, uint64_t, uint32_t#include <functional>     // for function#include <memory>         // for shared_ptr#include <mutex>          // for mutex#include <string>         // for string#include <unordered_map>  // for unordered_map#include <vector>         // for vector#include "BellTask.h"             // for Task#include "Packet.h"               // for Packet#include "Queue.h"                // for Queue#include "Session.h"              // for Session#include "protobuf/mercury.pb.h"  // for Headernamespace cspot {class TimeProvider;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 unregister(uint64_t sequenceId);  void unregisterAudioKey(uint32_t sequenceId);  uint32_t 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;  std::unordered_map<uint32_t, AudioKeyCallback> audioKeyCallbacks;  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
 |