Skip to content

Commit 644e8f3

Browse files
committed
Fix output buffer handling for the backend servers.
1 parent ad5635f commit 644e8f3

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

PIMELauncher/BackendServer.cpp

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ void BackendServer::startProcess() {
9797
stdoutPipe_ = new uv_pipe_t{};
9898
stdoutPipe_->data = this;
9999
uv_pipe_init(uv_default_loop(), stdoutPipe_, 0);
100+
stdoutReadBuf_.clear();
100101

101102
stderrPipe_ = new uv_pipe_t{};
102103
stderrPipe_->data = this;
@@ -202,13 +203,23 @@ void BackendServer::onProcessDataReceived(uv_stream_t * stream, ssize_t nread, c
202203
return;
203204
}
204205
if (buf->base) {
206+
// print to debug log if there is any
207+
logger()->debug("RECV: {}", std::string(buf->base, buf->len));
208+
205209
// initial ready message from the backend server
206-
if (buf->base[0] == '\0') {
210+
if (!ready_ && buf->base[0] == '\0') {
207211
ready_ = true;
212+
// skip the first byte, and add the received data to our buffer
213+
// FIXME: this is not very reliable
214+
stdoutReadBuf_.append(buf->base + 1, buf->len - 1);
208215
}
209216
else {
210-
handleBackendReply(buf->base, nread);
217+
// add the received data to our buffer
218+
stdoutReadBuf_.append(buf->base, buf->len);
211219
}
220+
221+
handleBackendReply();
222+
212223
delete[]buf->base;
213224
}
214225
}
@@ -258,6 +269,7 @@ void BackendServer::closeStdioPipes() {
258269
delete reinterpret_cast<uv_pipe_t*>(handle);
259270
});
260271
stdoutPipe_ = nullptr;
272+
stdoutReadBuf_.clear();
261273
}
262274

263275
if (stderrPipe_ != nullptr) {
@@ -268,44 +280,49 @@ void BackendServer::closeStdioPipes() {
268280
}
269281
}
270282

271-
void BackendServer::handleBackendReply(const char * readBuf, size_t len) {
272-
// print to debug log if there is any
273-
logger()->debug("RECV: {}", std::string(readBuf, len));
283+
void BackendServer::handleBackendReply() {
284+
// each output message should be a full line ends with \n or \r\n, so we need to do buffering and
285+
// handle the messages line by line.
286+
auto lineStartPos = 0;
287+
for (;;) {
288+
auto lineEndPos = stdoutReadBuf_.find('\n', lineStartPos);
289+
if (lineEndPos != stdoutReadBuf_.npos) {
290+
auto lineLen = lineEndPos - lineStartPos;
291+
auto line = stdoutReadBuf_.c_str() + lineStartPos;
292+
auto lineEnd = line + lineLen;
274293

275-
// pass the response back to the clients
276-
auto line = readBuf;
277-
auto buf_end = readBuf + len;
278-
while (line < buf_end) {
279-
// Format of each line: "PIMG_MSG|<client_id>|<reply JSON string>\n"
280-
if (auto line_end = strchr(line, '\n')) {
281294
// only handle lines prefixed with "PIME_MSG|" since other lines
282295
// might be debug messages printed by the backend.
296+
// Format of each message: "PIMG_MSG|<client_id>|<reply JSON string>\n"
283297
if (strncmp(line, "PIME_MSG|", 9) == 0) {
284298
line += 9; // Skip the "PIME_MSG|" prefix
285-
286299
if (auto sep = strchr(line, '|')) {
287300
// split the client_id from the remaining json reply
288301
string clientId(line, sep - line);
289302
auto msg = sep + 1;
290-
auto msg_len = line_end - msg;
303+
auto msgLen = lineEnd - msg;
291304
// because Windows uses CRLF "\r\n" for new lines, python and node.js
292305
// try to convert "\n" to "\r\n" sometimes. Let's remove the additional '\r'
293-
if (msg_len > 0 && msg[msg_len - 1] == '\r') {
294-
--msg_len;
306+
if (msgLen > 0 && msg[msgLen - 1] == '\r') {
307+
--msgLen;
295308
}
296309

297310
// send the reply message back to the client
298311
if (auto client = pipeServer_->clientFromId(clientId)) {
299-
client->writePipe(msg, len);
312+
client->writePipe(msg, msgLen);
300313
}
301314
}
302315
}
303-
line = line_end + 1;
316+
317+
// skip empty lines or additional CRLF, and go to the next non-empty line
318+
lineStartPos = lineEndPos + 1;
304319
}
305320
else {
306321
break;
307322
}
308323
}
324+
// Leave remaining data not processed in the buffer, waiting for the next \n so it becomes a full line.
325+
stdoutReadBuf_ = stdoutReadBuf_.substr(lineStartPos);
309326
}
310327

311328
void BackendServer::startReadOutputPipe() {

PIMELauncher/BackendServer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class BackendServer {
8888
void onProcessTerminated(int64_t exit_status, int term_signal);
8989
void closeStdioPipes();
9090

91-
void handleBackendReply(const char* readBuf, size_t len);
91+
void handleBackendReply();
9292

9393
private:
9494
PipeServer* pipeServer_;
@@ -98,6 +98,7 @@ class BackendServer {
9898
uv_pipe_t* stdoutPipe_;
9999
uv_pipe_t* stderrPipe_;
100100
bool ready_;
101+
std::string stdoutReadBuf_;
101102

102103
bool needRestart_;
103104
// command to launch the server process

0 commit comments

Comments
 (0)