1/**
2 * Copyright 2018 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import {
17  helper,
18  debugError,
19  PuppeteerEventListener,
20} from '../common/helper.js';
21import { ConnectionTransport } from '../common/ConnectionTransport.js';
22
23export class PipeTransport implements ConnectionTransport {
24  _pipeWrite: NodeJS.WritableStream;
25  _pendingMessage: string;
26  _eventListeners: PuppeteerEventListener[];
27
28  onclose?: () => void;
29  onmessage?: () => void;
30
31  constructor(
32    pipeWrite: NodeJS.WritableStream,
33    pipeRead: NodeJS.ReadableStream
34  ) {
35    this._pipeWrite = pipeWrite;
36    this._pendingMessage = '';
37    this._eventListeners = [
38      helper.addEventListener(pipeRead, 'data', (buffer) =>
39        this._dispatch(buffer)
40      ),
41      helper.addEventListener(pipeRead, 'close', () => {
42        if (this.onclose) this.onclose.call(null);
43      }),
44      helper.addEventListener(pipeRead, 'error', debugError),
45      helper.addEventListener(pipeWrite, 'error', debugError),
46    ];
47    this.onmessage = null;
48    this.onclose = null;
49  }
50
51  send(message: string): void {
52    this._pipeWrite.write(message);
53    this._pipeWrite.write('\0');
54  }
55
56  _dispatch(buffer: Buffer): void {
57    let end = buffer.indexOf('\0');
58    if (end === -1) {
59      this._pendingMessage += buffer.toString();
60      return;
61    }
62    const message = this._pendingMessage + buffer.toString(undefined, 0, end);
63    if (this.onmessage) this.onmessage.call(null, message);
64
65    let start = end + 1;
66    end = buffer.indexOf('\0', start);
67    while (end !== -1) {
68      if (this.onmessage)
69        this.onmessage.call(null, buffer.toString(undefined, start, end));
70      start = end + 1;
71      end = buffer.indexOf('\0', start);
72    }
73    this._pendingMessage = buffer.toString(undefined, start);
74  }
75
76  close(): void {
77    this._pipeWrite = null;
78    helper.removeEventListeners(this._eventListeners);
79  }
80}
81