aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver-test/projectclient.cpp
blob: cb493be770623bf4402029d8201ac37fb6ec8181 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright Epic Games, Inc. All Rights Reserved.

#include "projectclient.h"

#if 0

#	include <zencore/compactbinary.h>
#	include <zencore/logging.h>
#	include <zencore/sharedbuffer.h>
#	include <zencore/string.h>
#	include <zencore/zencore.h>

#	include <asio.hpp>
#	include <gsl/gsl-lite.hpp>

namespace zen {

struct ProjectClientConnection
{
	ProjectClientConnection(int BasePort) { Connect(BasePort); }

	void Connect(int BasePort)
	{
		ZEN_UNUSED(BasePort);

		WideStringBuilder<64> PipeName;
		PipeName << "\\\\.\\pipe\\zenprj";	// TODO: this should use an instance-specific identifier!

		HANDLE hPipe = CreateFileW(PipeName.c_str(),
								   GENERIC_READ | GENERIC_WRITE,
								   0,			   // Sharing doesn't make any sense
								   nullptr,		   // No security attributes
								   OPEN_EXISTING,  // Open existing pipe
								   0,			   // Attributes
								   nullptr		   // Template file
		);

		if (hPipe == INVALID_HANDLE_VALUE)
		{
			ZEN_WARN("failed while creating named pipe {}", WideToUtf8(PipeName));

			throw std::system_error(GetLastError(), std::system_category(), fmt::format("Failed to open named pipe '{}'", WideToUtf8(PipeName)));
		}

		// Change to message mode
		DWORD dwMode  = PIPE_READMODE_MESSAGE;
		BOOL  Success = SetNamedPipeHandleState(hPipe, &dwMode, nullptr, nullptr);

		if (!Success)
		{
			throw std::system_error(GetLastError(),
									std::system_category(),
									fmt::format("Failed to change named pipe '{}' to message mode", WideToUtf8(PipeName)));
		}

		m_hPipe.Attach(hPipe);	// This now owns the handle and will close it
	}

	~ProjectClientConnection() {}

	CbObject MessageTransaction(CbObject Request)
	{
		DWORD dwWrittenBytes = 0;

		MemoryView View = Request.GetView();

		BOOL Success = ::WriteFile(m_hPipe, View.GetData(), gsl::narrow_cast<DWORD>(View.GetSize()), &dwWrittenBytes, nullptr);

		if (!Success)
		{
			throw std::system_error(GetLastError(), std::system_category(), "Failed to write pipe message");
		}

		ZEN_ASSERT(dwWrittenBytes == View.GetSize());

		DWORD dwReadBytes = 0;

		Success = ReadFile(m_hPipe, m_Buffer, sizeof m_Buffer, &dwReadBytes, nullptr);

		if (!Success)
		{
			DWORD ErrorCode = GetLastError();

			if (ERROR_MORE_DATA == ErrorCode)
			{
				// Response message is larger than our buffer - handle it by allocating a larger
				// buffer on the heap and read the remainder into that buffer

				DWORD dwBytesAvail = 0, dwLeftThisMessage = 0;

				Success = PeekNamedPipe(m_hPipe, nullptr, 0, nullptr, &dwBytesAvail, &dwLeftThisMessage);

				if (Success)
				{
					UniqueBuffer MessageBuffer = UniqueBuffer::Alloc(dwReadBytes + dwLeftThisMessage);

					memcpy(MessageBuffer.GetData(), m_Buffer, dwReadBytes);

					Success = ReadFile(m_hPipe,
									   reinterpret_cast<uint8_t*>(MessageBuffer.GetData()) + dwReadBytes,
									   dwLeftThisMessage,
									   &dwReadBytes,
									   nullptr);

					if (Success)
					{
						return CbObject(SharedBuffer(std::move(MessageBuffer)));
					}
				}
			}

			throw std::system_error(GetLastError(), std::system_category(), "Failed to read pipe message");
		}

		return CbObject(SharedBuffer::MakeView(MakeMemoryView(m_Buffer)));
	}

private:
	static const int kEmbeddedBufferSize = 512 - 16;

	CHandle m_hPipe;
	uint8_t m_Buffer[kEmbeddedBufferSize];
};

struct LocalProjectClient::ClientImpl
{
	ClientImpl(int BasePort) : m_BasePort(BasePort) {}
	~ClientImpl() {}

	void Start() {}
	void Stop() {}

	inline int BasePort() const { return m_BasePort; }

private:
	int m_BasePort = 0;
};

LocalProjectClient::LocalProjectClient(int BasePort)
{
	m_Impl = std::make_unique<ClientImpl>(BasePort);
	m_Impl->Start();
}

LocalProjectClient::~LocalProjectClient()
{
	m_Impl->Stop();
}

CbObject
LocalProjectClient::MessageTransaction(CbObject Request)
{
	ProjectClientConnection Cx(m_Impl->BasePort());

	return Cx.MessageTransaction(Request);
}

}  // namespace zen

#endif	// 0