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 Header
- namespace 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
|