#pragma once #include #include #include #include #include #include #include #include #include namespace erebos { using std::function; using std::future; using std::map; using std::mutex; using std::promise; using std::string; using std::variant; using std::vector; /** * Template-less base class for the paring functionality that does not depend * on the result parameter. */ class PairingServiceBase : public Service { public: virtual ~PairingServiceBase(); typedef function RequestInitHook; void onRequestInit(RequestInitHook); typedef function(const Peer &, string, future &&)> ConfirmHook; void onResponse(ConfirmHook); void onRequest(ConfirmHook); typedef function RequestNonceFailedHook; void onRequestNonceFailed(RequestNonceFailedHook); protected: void requestPairing(UUID serviceId, const Peer & peer); virtual void handle(Context &) override; virtual Ref handlePairingCompleteRef(const Peer &) = 0; virtual void handlePairingResult(Context &) = 0; private: static vector nonceDigest(const Identity & id1, const Identity & id2, const vector & nonce1, const vector & nonce2); static string confirmationNumber(const vector &); RequestInitHook requestInitHook; ConfirmHook responseHook; ConfirmHook requestHook; RequestNonceFailedHook requestNonceFailedHook; optional result; enum class StatePhase { NoPairing, OurRequest, OurRequestConfirm, OurRequestReady, PeerRequest, PeerRequestConfirm, PairingDone, PairingFailed }; struct State { mutex lock; StatePhase phase; vector nonce; vector peerCheck; promise success; }; map> peerStates; mutex stateLock; void waitForConfirmation(Peer peer, weak_ptr state, string confirm, ConfirmHook hook); }; template class PairingService : public PairingServiceBase { protected: virtual Stored handlePairingComplete(const Peer &) = 0; virtual void handlePairingResult(Context &, Stored) = 0; virtual Ref handlePairingCompleteRef(const Peer &) override final; virtual void handlePairingResult(Context &) override final; }; template Ref PairingService::handlePairingCompleteRef(const Peer & peer) { return handlePairingComplete(peer).ref(); } template void PairingService::handlePairingResult(Context & ctx) { handlePairingResult(ctx, Stored::load(ctx.ref())); } }