#pragma once #include "dtcore/inc/dtdefinitions.h" #include "dtcore/inc/dtconnectiondescriptor.h" #include "dtcore/inc/dtmessage.h" #include "dtcore/inc/dtfunctor.h" #include "dtcore/inc/dtmutex.h" namespace dt { class ByteBuffer; class ClientService; class ServerService; class Service; class WebResponse; class Task; template class Promise; class PromiseBase; // Common Headers const char* const g_HttpHeaderUserAgent = "User-Agent"; const char* const g_HttpHeaderUserAgentVersion = "User-Agent-Version"; const char* const g_HttpHeaderUserAgentPid = "User-Agent-Pid"; const char* const g_HttpHeaderUserAgentComputer = "User-Agent-Computer"; const char* const g_HttpHeaderUser = "User"; const char* const g_HttpHeaderSessionRenew = "Session-Renew"; // Common Cookies const char* const g_HttpCookieSession = "Session"; enum class HttpCode : int { None = 0, Continue = 100, SwitchingProtocols = 101, Processing = 102, Ok = 200, Created = 201, Accepted = 202, NonAuthoritativeInformation = 203, NoContent = 204, ResetContent = 205, PartialContent = 206, MultiStatus = 207, MultipleChoices = 300, MovedPermanently = 301, Found = 302, SeeOther = 303, NotModified = 304, UseProxy = 305, SwitchProxy = 306, TemporaryRedirect = 307, BadRequest = 400, Unauthorized = 401, PaymentRequired = 402, Forbidden = 403, NotFound = 404, MethodNotAllowed = 405, NotAcceptable = 406, ProxyAuthenticationRequired = 407, RequestTimeout = 408, Conflict = 409, Gone = 410, LengthRequired = 411, PreconditionFailed = 412, RequestEntityTooLarge = 413, RequestUriTooLong = 414, UnsupportedMediaType = 415, RequestedRangeNotSatisfiable = 416, ExpectationFailed = 417, UnprocessableEntity = 422, Locked = 423, FailedDependency = 424, UnorderedCollection = 425, UpgradeRequired = 426, NoResponse = 444, RetryWith = 449, BlockedByWindowsParentalControls = 450, UnavailableForLegalReasons = 451, InternalServerError = 500, NotImplemented = 501, BadGateway = 502, ServiceUnavailable = 503, GatewayTimeout = 504, HttpVersionNotSupported = 505, VariantAlsoNegotiates = 506, InsufficientStorage = 507, BandwidthLimitExceeded = 509, NotExtended = 510, // local send/receive errors InternalError = 1000, InternalSocketError = 1001, InternalHostInvalid = 1002, InternalTimeout = 1003, InternalDisconnect = 1004, InternalCancel = 1005 }; String HttpCodeToString(HttpCode code); ////////////////////////////////////////////////////////////////////////// class MessageEmpty : public Message { DT_DECLARE_TYPE(MessageEmpty, Message); public: MessageEmpty(){} static Message* Create() { return DT_NEW(MessageEmpty); } virtual void Serialize(U8 , Stream& ) override {}; private: }; ////////////////////////////////////////////////////////////////////////// class Service { DT_DECLARE_ROOT_TYPE(Service) public: virtual ~Service() {}; virtual const char* GetHttpId() const = 0; virtual void Update() {} MessageFactory& GetMessageFactory() { return m_MessageFactory; } protected: MessageFactory m_MessageFactory; }; ////////////////////////////////////////////////////////////////////////// class ClientSessionInterface { public: virtual ~ClientSessionInterface() {}; virtual Promise PostAsync(ClientService& service, const Message& msg, MilliSeconds timeoutMs) = 0; virtual void Join(const PromiseBase& promise) = 0; virtual void RequestShutdown() = 0; virtual void Connect(const ConnectionDescriptor& connection, const String& userName, const String& computerName, const String& moduleName, int processId, ByteBuffer& attachment) = 0; virtual void DisconnectQuery(const ConnectionDescriptor& connection, bool& canDisconnect) = 0; virtual void DisconnectAll() = 0; virtual void Disconnect(const ConnectionDescriptor& connection) = 0; }; ////////////////////////////////////////////////////////////////////////// class ClientService : public Service { DT_DECLARE_TYPE(ClientService, Service) public: // override as needed virtual void OnConnect(bool renew) { DT_UNUSED(renew); } virtual void OnDisconnect(bool remoteDisconnect) { DT_UNUSED(remoteDisconnect); } virtual void OnDisconnectQuery(bool& canDisconnect) { canDisconnect = true; } // service method void Disconnect(); Promise PostAsync(const Message& msg, MilliSeconds timeoutMs = MilliSeconds(INVALID_VALUE)); void Join(const PromiseBase& promise); void RequestShutdown(); const ConnectionDescriptor& GetConnectionDescriptor() const { return m_ConnectionDescriptor; } const ConnectionDescriptor& GetLocalConnectionDescriptor() const { return m_LocalConnectionDescriptor; } public: // internal API void InternalBind(ClientSessionInterface* session, const ConnectionDescriptor& descriptor, const ConnectionDescriptor& localDescriptor); void InternalUnbind(); void InternalOnConnect(const ConnectionDescriptor& descriptor, const ConnectionDescriptor& localDescriptor, bool renew); void InternalOnMessage(const String& route, Message* msg); private: ConnectionDescriptor m_ConnectionDescriptor; ConnectionDescriptor m_LocalConnectionDescriptor; ClientSessionInterface* m_Session = nullptr; }; ////////////////////////////////////////////////////////////////////////// class ServerSessionInterface { public: virtual ~ServerSessionInterface() {} virtual void Reply(const ConnectionDescriptor& descriptor, const Message& msg, HttpCode code) = 0; virtual void Download(const ConnectionDescriptor& descriptor, const String& filename, const ByteBuffer& data, HttpCode code) = 0; virtual void Notify(const ConnectionDescriptor& descriptor, const Service& service, const Message& msg) = 0; virtual void OnLoggedIn(const ConnectionDescriptor& descriptor, const String& userName, const Strings& roles) = 0; virtual void OnLoggedOut(const ConnectionDescriptor& descriptor) = 0; virtual int GetNumberOfConnections() const = 0; }; ////////////////////////////////////////////////////////////////////////// class ServerService : public Service { DT_DECLARE_TYPE(ServerService, Service) public: // override as needed virtual void OnBind() {} virtual void OnConnect(const ConnectionDescriptor& descriptor, bool renew) { DT_UNUSED(descriptor); DT_UNUSED(renew); } virtual void OnDisconnect(const ConnectionDescriptor&, bool remoteDisconnect) { DT_UNUSED(remoteDisconnect); } virtual void OnDisconnectQuery(const ConnectionDescriptor&, bool& canDisconnect) { canDisconnect = true; } // service methods void Reply(const ConnectionDescriptor& descriptor, const Message& msg = MessageEmpty(), HttpCode code = HttpCode::Ok); void Download(const ConnectionDescriptor& descriptor, const String& filename, const ByteBuffer& data, HttpCode code = HttpCode::Ok); void Notify(const ConnectionDescriptor& descriptor, const Message& msg); int GetNumberOfConnections() const; const ConnectionDescriptor& GetLocalHttpConnectionDescriptor() const { return m_LocalHttpConnectionDescriptor; } public: // internal API void InternalOnMessage(const ConnectionDescriptor& descriptor, const String& route, Message* msg); void InternalBind(ServerSessionInterface* session, const ConnectionDescriptor& localDescriptor); ServerSessionInterface* InternalGetHttpSession() const { return m_HttpSession; } private: ConnectionDescriptor m_LocalHttpConnectionDescriptor; ServerSessionInterface* m_HttpSession = nullptr; }; }