MercurySession.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #pragma once
  2. #include <atomic> // for atomic
  3. #include <cstdint> // for uint8_t, uint64_t, uint32_t
  4. #include <functional> // for function
  5. #include <memory> // for shared_ptr
  6. #include <mutex> // for mutex
  7. #include <string> // for string
  8. #include <unordered_map> // for unordered_map
  9. #include <vector> // for vector
  10. #include "BellTask.h" // for Task
  11. #include "Packet.h" // for Packet
  12. #include "Queue.h" // for Queue
  13. #include "Session.h" // for Session
  14. #include "protobuf/mercury.pb.h" // for Header
  15. namespace cspot {
  16. class TimeProvider;
  17. class MercurySession : public bell::Task, public cspot::Session {
  18. public:
  19. MercurySession(std::shared_ptr<cspot::TimeProvider> timeProvider);
  20. ~MercurySession();
  21. typedef std::vector<std::vector<uint8_t>> DataParts;
  22. struct Response {
  23. Header mercuryHeader;
  24. uint8_t flags;
  25. DataParts parts;
  26. uint64_t sequenceId;
  27. bool fail;
  28. };
  29. typedef std::function<void(Response&)> ResponseCallback;
  30. typedef std::function<void(bool, const std::vector<uint8_t>&)>
  31. AudioKeyCallback;
  32. typedef std::function<void()> ConnectionEstabilishedCallback;
  33. enum class RequestType : uint8_t {
  34. SUB = 0xb3,
  35. UNSUB = 0xb4,
  36. SUBRES = 0xb5,
  37. SEND = 0xb2,
  38. GET = 0xFF, // Shitty workaround, it's value is actually same as SEND
  39. PING = 0x04,
  40. PONG_ACK = 0x4a,
  41. AUDIO_CHUNK_REQUEST_COMMAND = 0x08,
  42. AUDIO_CHUNK_SUCCESS_RESPONSE = 0x09,
  43. AUDIO_CHUNK_FAILURE_RESPONSE = 0x0A,
  44. AUDIO_KEY_REQUEST_COMMAND = 0x0C,
  45. AUDIO_KEY_SUCCESS_RESPONSE = 0x0D,
  46. AUDIO_KEY_FAILURE_RESPONSE = 0x0E,
  47. COUNTRY_CODE_RESPONSE = 0x1B,
  48. };
  49. std::unordered_map<RequestType, std::string> RequestTypeMap = {
  50. {RequestType::GET, "GET"},
  51. {RequestType::SEND, "SEND"},
  52. {RequestType::SUB, "SUB"},
  53. {RequestType::UNSUB, "UNSUB"},
  54. };
  55. void handlePacket();
  56. uint64_t executeSubscription(RequestType type, const std::string& uri,
  57. ResponseCallback callback,
  58. ResponseCallback subscription, DataParts& parts);
  59. uint64_t executeSubscription(RequestType type, const std::string& uri,
  60. ResponseCallback callback,
  61. ResponseCallback subscription) {
  62. DataParts parts = {};
  63. return this->executeSubscription(type, uri, callback, subscription, parts);
  64. }
  65. uint64_t execute(RequestType type, const std::string& uri,
  66. ResponseCallback callback) {
  67. return this->executeSubscription(type, uri, callback, nullptr);
  68. }
  69. uint64_t execute(RequestType type, const std::string& uri,
  70. ResponseCallback callback, DataParts& parts) {
  71. return this->executeSubscription(type, uri, callback, nullptr, parts);
  72. }
  73. void unregister(uint64_t sequenceId);
  74. void unregisterAudioKey(uint32_t sequenceId);
  75. uint32_t requestAudioKey(const std::vector<uint8_t>& trackId,
  76. const std::vector<uint8_t>& fileId,
  77. AudioKeyCallback audioCallback);
  78. std::string getCountryCode();
  79. void disconnect();
  80. void setConnectedHandler(ConnectionEstabilishedCallback callback);
  81. bool triggerTimeout() override;
  82. private:
  83. const int PING_TIMEOUT_MS = 2 * 60 * 1000 + 5000;
  84. std::shared_ptr<cspot::TimeProvider> timeProvider;
  85. Header tempMercuryHeader = {};
  86. ConnectionEstabilishedCallback connectionReadyCallback = nullptr;
  87. bell::Queue<cspot::Packet> packetQueue;
  88. void runTask() override;
  89. void reconnect();
  90. std::unordered_map<uint64_t, ResponseCallback> callbacks;
  91. std::unordered_map<std::string, ResponseCallback> subscriptions;
  92. std::unordered_map<uint32_t, AudioKeyCallback> audioKeyCallbacks;
  93. uint64_t sequenceId = 1;
  94. uint32_t audioKeySequence = 1;
  95. unsigned long long timestampDiff;
  96. unsigned long long lastPingTimestamp = -1;
  97. std::string countryCode = "";
  98. std::mutex isRunningMutex;
  99. std::atomic<bool> isRunning = false;
  100. std::atomic<bool> isReconnecting = false;
  101. std::atomic<bool> executeEstabilishedCallback = false;
  102. void failAllPending();
  103. Response decodeResponse(const std::vector<uint8_t>& data);
  104. };
  105. } // namespace cspot