/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppOS.h"
#include "Vlpp.h"

/***********************************************************************
.\ASYNCSOCKET\ASYNCSOCKET.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Windows implementation of IAsyncSocket(Server|Client)

***********************************************************************/

#ifndef VCZH_INTERPROCESS_ASYNCSOCKET_WINDOWS
#define VCZH_INTERPROCESS_ASYNCSOCKET_WINDOWS

// Winsock must precede every include that can include windows.h.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <WinSock2.h>
#include <MSWSock.h>
#define _WINSOCKAPI_
#include <Windows.h>


namespace vl::inter_process::async_tcp_socket::windows_socket
{
	class AsyncSocketServer : public Object, public virtual IAsyncSocketServer
	{
	private:
		class Impl;
		Impl*								impl = nullptr;

	public:
		AsyncSocketServer(vint port);
		~AsyncSocketServer();

		vint								GetPort() override;
		void								Start(IAsyncSocketServerCallback* callback) override;
		void								Stop() override;
		bool								IsStopped() override;
	};

	class AsyncSocketClient : public Object, public virtual IAsyncSocketClient
	{
	private:
		class Impl;
		Impl*								impl = nullptr;

	public:
		AsyncSocketClient(vint port);
		~AsyncSocketClient();

		vint								GetPort() override;
		Ptr<IAsyncSocketClient>				CreateSameEndpointClient() override;
		IAsyncSocketConnection*				GetConnection() override;
		void								WaitForServer() override;
		ClientStatus						GetStatus() override;
	};
}

#endif


/***********************************************************************
.\WINDOWS\NETWORKPROTOCOL.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Interfaces:
***********************************************************************/

#ifndef VCZH_INTERPROCESS_WINDOWS_NETWORKPROTOCOL
#define VCZH_INTERPROCESS_WINDOWS_NETWORKPROTOCOL

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define _WINSOCKAPI_
#include <windows.h>
#include <http.h>
#define RPC_USE_NATIVE_WCHAR
#include <rpc.h>
#include <winhttp.h>


#endif


/***********************************************************************
.\WINDOWS\HTTPCLIENTAPI.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Interfaces:
	HttpClientApi

***********************************************************************/

#ifndef VCZH_INTERPROCESS_WINDOWS_HTTPCLIENTAPI
#define VCZH_INTERPROCESS_WINDOWS_HTTPCLIENTAPI


namespace vl::inter_process::windows_http
{

/// <summary>A Windows-only async HTTP client for a single host and port.</summary>
class HttpClientApi : public Object
{
	static constexpr vint32_t							HttpRespondBodyStep = 65536;

	class HttpRequestContext : public Object
	{
	public:
		HttpClientApi*									api = nullptr;
		HINTERNET										httpRequest = NULL;
		Func<void(Variant<HttpResponse, HttpError>)>	callback;
		collections::Array<char>						requestBody;
		HttpResponse									response;
		DWORD											bodyBufferWriting = 0;
		DWORD											bodyBufferWritingAvailable = 0;
		bool											keepAliveOnStop = false;
		bool											completed = false;
		bool											closing = false;
		SpinLock										lockContext;
	};

	WString												server;
	vint												port = 0;
	HINTERNET											httpSession = NULL;
	HINTERNET											httpConnection = NULL;

	SpinLock											lockActiveRequests;
	collections::List<Ptr<HttpRequestContext>>			activeRequests;
	bool												stopping = false;
	atomic_vint											pendingCallbacks = 0;
	EventObject											eventPendingCallbacks;

	static void CALLBACK								HttpStatusCallback(HINTERNET httpRequest, DWORD_PTR context, DWORD status, LPVOID statusInformation, DWORD statusInformationLength);
	static HttpError									MakeError(const WString& operation, DWORD errorCode);

	bool												IsStopping();
	void												BeginPendingCallback();
	void												EndPendingCallback();
	void												AttachRequestUnsafe(Ptr<HttpRequestContext> context);
	void												RemoveRequestUnsafe(Ptr<HttpRequestContext> context);
	void												CloseRequest(Ptr<HttpRequestContext> context);
	void												OnRequestHandleClosing(Ptr<HttpRequestContext> context);
	void												CompleteRequest(Ptr<HttpRequestContext> context, HttpResponse&& response);
	void												CompleteRequest(Ptr<HttpRequestContext> context, HttpError&& error);
	void												CompleteRequestWithLastError(Ptr<HttpRequestContext> context, const WString& operation, DWORD errorCode);

public:
	HttpClientApi(const WString& _server, vint _port);
	~HttpClientApi();

	HttpClientApi(const HttpClientApi&) = delete;
	HttpClientApi(HttpClientApi&&) = delete;
	HttpClientApi& operator=(const HttpClientApi&) = delete;
	HttpClientApi& operator=(HttpClientApi&&) = delete;

	void												HttpQuery(const HttpRequest& request, Func<void(Variant<HttpResponse, HttpError>)> callback);
	void												Stop();

	static WString										UrlEncodeQuery(const WString& query);
	static WString										UrlDecodeQuery(const WString& query);
};

}

#endif


/***********************************************************************
.\WINDOWS\HTTPCLIENT.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Interfaces:
	HttpClient

***********************************************************************/

#ifndef VCZH_INTERPROCESS_WINDOWS_HTTPCLIENT
#define VCZH_INTERPROCESS_WINDOWS_HTTPCLIENT


namespace vl::inter_process::windows_http
{

class HttpClient : public Object, public virtual INetworkProtocolConnection, public virtual INetworkProtocolClient
{
protected:
	static constexpr vint							HttpRequestMaxAttempts = 3;

	enum class State
	{
		Ready,
		WaitForServerConnection,
		Running,
		Stopping,
	};

	State											state = State::Ready;
	INetworkProtocolCallback*						callback = nullptr;
	WString											baseUrl;
	Ptr<HttpClientApi>								httpClientApi;
	WString											urlConnect;
	WString											urlRequest;
	WString											urlResponse;
	SpinLock										lockState;

/***********************************************************************
HttpClient (Reading)
***********************************************************************/

protected:
	void											RaiseLocalError(WString errorMessage, bool fatal);
	bool											IsStopping();
public:

	void											BeginReadingLoopUnsafe() override;

/***********************************************************************
HttpClient (WaitForServer)
***********************************************************************/

protected:

	EventObject										eventWaitForServer;
	SpinLock										lockConnectResult;
	bool											connectCompleted = false;
	WString											connectResponse;
	WString											connectError;
	void											CompleteConnectRequest(const WString& response, const WString& error);

public:
	
	INetworkProtocolConnection*						GetConnection() override;
	void											WaitForServer() override;
	ClientStatus									GetStatus() override;

/***********************************************************************
HttpClient (Writing)
***********************************************************************/

protected:
	enum class HttpRequestType
	{
		Connect,
		Request,
		Response,
	};

	bool											SendHttpRequest(HttpRequestType requestType, const WString& url, const WString& body, vint attempt = 1);
	void											OnHttpRequestCompleted(HttpRequestType requestType, WString body, vint attempt, Variant<HttpResponse, HttpError> result);
	void											OnHttpRequestFailed(HttpRequestType requestType, const WString& body, vint attempt, const WString& errorMessage);

public:

	void											SendString(const WString& str) override;

/***********************************************************************
HttpClient
***********************************************************************/

public:
	HttpClient(const WString _baseUrl, vint port);
	~HttpClient();

	void											InstallCallback(INetworkProtocolCallback* _callback) override;
	void											Stop() override;
};

}

#endif


/***********************************************************************
.\WINDOWS\HTTPSERVERAPI.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Interfaces:
	HttpServerApi

***********************************************************************/

#ifndef VCZH_INTERPROCESS_WINDOWS_HTTPSERVERAPI
#define VCZH_INTERPROCESS_WINDOWS_HTTPSERVERAPI


namespace vl::inter_process::windows_http
{

/// <summary>A response to be sent by <see cref="HttpServerApi"/>.</summary>
struct HttpServerResponse
{
	vint											statusCode = 200;
	WString											reason;
	WString											body;
	WString											contentType;
};

/// <summary>A Windows-only async HTTP server for a single URL prefix.</summary>
class HttpServerApi : public Object
{
	static constexpr vint32_t						HttpRequestBufferInitSize = 1024;

protected:
	enum class State
	{
		Ready,
		Running,
		Stopping,
	};

	WString											urlPrefix;
	bool											respondToOptions = false;

	HANDLE											httpRequestQueue = INVALID_HANDLE_VALUE;
	HTTP_SERVER_SESSION_ID							httpSessionId = HTTP_NULL_ID;
	HTTP_URL_GROUP_ID								httpUrlGroupId = HTTP_NULL_ID;

	State											state = State::Ready;

	collections::Array<BYTE>						bufferRequest;
	HANDLE											hWaitHandleRequest = INVALID_HANDLE_VALUE;
	OVERLAPPED										overlappedRequest;
	HANDLE											hEventRequest = INVALID_HANDLE_VALUE;
	EventObject										eventPendingCallbacks;
	atomic_vint										pendingCallbacks = 0;

	void											OnHttpConnectionBrokenUnsafe();
	void											OnHttpRequestReceivedUnsafe(PHTTP_REQUEST pRequest);
	ULONG											ListenToHttpRequest_Init(OVERLAPPED* overlapped);
	ULONG											ListenToHttpRequest_InitMoreData(ULONG* bytesReturned);
	ULONG											ListenToHttpRequest_OverlappedMoreData(vint expectedBufferSize);
	void											ListenToHttpRequest();
	void											BeginPendingCallback();
	void											EndPendingCallback();

	virtual void									OnHttpRequestReceived(PHTTP_REQUEST pRequest) = 0;
	virtual void									OnHttpServerStopping();

	static void										SendOptionsResponse(HANDLE httpRequestQueue, HTTP_REQUEST_ID requestId);

public:
	HttpServerApi(const WString& _urlPrefix, bool _respondToOptions);
	~HttpServerApi();

	HttpServerApi(const HttpServerApi&) = delete;
	HttpServerApi(HttpServerApi&&) = delete;
	HttpServerApi& operator=(const HttpServerApi&) = delete;
	HttpServerApi& operator=(HttpServerApi&&) = delete;

	void											Start();
	void											Stop();
	bool											IsStopped();
	HANDLE											GetHttpRequestQueue() const;

	Nullable<WString>								GetUtf8Body(PHTTP_REQUEST pRequest);
	static ULONG									SendResponse(HANDLE httpRequestQueue, HTTP_REQUEST_ID requestId, const HttpServerResponse& response);
	static void										SendResponseUtf8(HANDLE httpRequestQueue, HTTP_REQUEST_ID requestId, WString body);
};

}

#endif


/***********************************************************************
.\WINDOWS\HTTPSERVER.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Interfaces:
	HttpServer

***********************************************************************/

#ifndef VCZH_INTERPROCESS_WINDOWS_HTTPSERVER
#define VCZH_INTERPROCESS_WINDOWS_HTTPSERVER


namespace vl::inter_process::windows_http
{

class HttpServer;

class HttpServerConnection : public Object, public virtual INetworkProtocolConnection
{
	friend class HttpServer;
protected:
	HttpServer*										server = nullptr;
	WString											guid;
	INetworkProtocolCallback*						callback = nullptr;

	SpinLock										lockQueuedStrings;
	collections::List<WString>						queuedStrings;

	SpinLock										pendingRequestLock;
	HTTP_REQUEST_ID									httpPendingRequestId = HTTP_NULL_ID;
	collections::List<WString>						pendingRequestsToSend;
	bool											submittingResponse = false;
	collections::List<WString>						responsesToSubmit;

	// All following functions must be called inside SPIN_LOCK(pendingRequestLock)
	void											OnCancelCurrentHttpRequestForPendingRequest();
	void											OnNewHttpRequestForPendingRequest(HTTP_REQUEST_ID httpRequestId);

	WString											SubmitResponse(PHTTP_REQUEST pRequest);

public:
	void											InstallCallback(INetworkProtocolCallback* _callback) override;
	void											BeginReadingLoopUnsafe() override;
	void											SendString(const WString& str) override;
	void											Stop() override;

	static WString									GenerateNewGuid();
};

class HttpServer : public HttpServerApi, public virtual INetworkProtocolServer
{
	friend class HttpServerConnection;
	using ConnectionMap = collections::Dictionary<WString, Ptr<HttpServerConnection>>;
protected:
	WString											baseUrl;
	WString											urlConnect;
	WString											urlRequestPrefix;
	WString											urlResponsePrefix;

	// covers connections
	SpinLock										lockConnections;
	ConnectionMap									connections;

/***********************************************************************
HttpServer (BeginReadingLoopUnsafe)
***********************************************************************/

protected:


/***********************************************************************
HttpServer (HttpServerApi)
***********************************************************************/

protected:

	void											OnHttpRequestReceived(PHTTP_REQUEST pRequest) override;
	void											OnHttpServerStopping() override;

/***********************************************************************
HttpServer
***********************************************************************/

public:
	HttpServer(const WString _baseUrl, vint port);
	~HttpServer();
	
	WaitForClientResult								OnClientConnected(INetworkProtocolConnection* connection) override;
	void											Start() override;
	void											Stop() override;
	bool											IsStopped() override;
};

}

#endif


/***********************************************************************
.\WINDOWS\NAMEDPIPE.WINDOWS.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)

Interfaces:
	NamedPipeServer
	NamedPipeClient

***********************************************************************/

#ifndef VCZH_INTERPROCESS_WINDOWS_NAMEDPIPE
#define VCZH_INTERPROCESS_WINDOWS_NAMEDPIPE


namespace vl::inter_process::named_pipe
{

class NamedPipeServer;

class NamedPipeConnection : public Object, public virtual INetworkProtocolConnection
{
	friend class NamedPipeServer;
// -----------------------------------------------------------------------
// Reading
// -----------------------------------------------------------------------

private:
	class ReadWaitContext;

	bool											firstRead = true;
	atomic_vint										stopped = 0;
	collections::Array<BYTE>						bufferReadFile;
	stream::MemoryStream							streamReadFile;
	std::atomic<ReadWaitContext*>					readWaitContext = nullptr;
	OVERLAPPED										overlappedReadFile;
	HANDLE											hEventReadFile = INVALID_HANDLE_VALUE;
	atomic_vint										pendingCallbacks = 0;
	EventObject										eventPendingCallbacks;

	void											BeginReadingUnsafe();
	void											SubmitReadBufferUnsafe(vint bytes);
	void											EndReadingUnsafe();
	void											BeginPendingCallback();
	void											EndPendingCallback();

public:
	void											BeginReadingLoopUnsafe() override;

// -----------------------------------------------------------------------
// Writing
// -----------------------------------------------------------------------
private:
	SpinLock										lockWrite;
	stream::MemoryStream							streamWriteFile;
	OVERLAPPED										overlappedWriteFile;
	HANDLE											hEventWriteFile = INVALID_HANDLE_VALUE;

	vint32_t										WriteInt32ToStream(vint32_t number);
	vint32_t										WriteStringToStream(const WString& str);
	void											BeginSendStream();
	void											EndSendStream(vint32_t bytes);

protected:
	void											SendString(const WString& str) override;

// -----------------------------------------------------------------------
// Connection
// -----------------------------------------------------------------------

protected:
	// NamedPipe doesn't support a single message that is larger than 64K
	static constexpr vint32_t						MaxMessageSize = 65536;

	NamedPipeServer*								server = nullptr;
	INetworkProtocolCallback*						callback = nullptr;
	HANDLE											hPipe = INVALID_HANDLE_VALUE;

	void											OnLocalError(const WString& errorMessage);
	void											OnDisconnected();

	NamedPipeConnection(HANDLE _hPipe);

public:
	~NamedPipeConnection();

	void											InstallCallback(INetworkProtocolCallback* _callback) override;
	void											Stop() override;
};

class NamedPipeServer : public Object, public virtual INetworkProtocolServer
{
	friend class NamedPipeConnection;
protected:
	class PendingConnection : public Object
	{
	public:
		class ConnectWaitContext;

		NamedPipeServer*							server = nullptr;
		Ptr<NamedPipeConnection>					connection;
		std::atomic<ConnectWaitContext*>			connectWaitContext = nullptr;
		OVERLAPPED									overlappedConnect;
		HANDLE										hEventConnect = INVALID_HANDLE_VALUE;
		atomic_vint									pendingCallbacks = 0;
		EventObject									eventPendingCallbacks;

		PendingConnection(NamedPipeServer* _server, Ptr<NamedPipeConnection> _connection);
		~PendingConnection();

		void										Stop();
		void										BeginPendingCallback();
		void										EndPendingCallback();
	};

	static HANDLE									ServerCreatePipe(const WString& pipeName);

	WString											pipeName;

	// covers started, stopped, connections and pendingConnections
	SpinLock										lockConnections;
	bool											started = false;
	bool											stopped = false;
	collections::List<Ptr< NamedPipeConnection>>	connections;
	collections::List<Ptr<PendingConnection>>		pendingConnections;

	void											BeginListening();
	void											CompletePendingConnection(Ptr<PendingConnection> pendingConnection, bool connected);
	void											CompletePendingConnection(PendingConnection* pendingConnection, bool connected);

public:
	NamedPipeServer(const WString& _pipeName);
	~NamedPipeServer();

	WaitForClientResult								OnClientConnected(INetworkProtocolConnection* connection) override;
	void											Start() override;
	void											Stop() override;
	bool											IsStopped() override;
};

class NamedPipeClient : public NamedPipeConnection, public virtual INetworkProtocolClient
{
protected:
	static HANDLE									ClientCreatePipe(const WString& pipeName);
	ClientStatus									status = ClientStatus::Ready;

public:
	NamedPipeClient(const WString& _pipeName);
	~NamedPipeClient();

	INetworkProtocolConnection*						GetConnection() override;
	void											WaitForServer() override;
	ClientStatus									GetStatus() override;
	void											Stop() override;
};

}

#endif

