All files / ethers.js/src.ts/providers provider-ipcsocket.ts

23.45% Statements 19/81
0% Branches 0/1
0% Functions 0/2
23.45% Lines 19/81

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 821x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                           1x 1x 1x 1x 1x 1x 1x                                                                                                    
 
import { connect } from "net";
import { SocketProvider } from "./provider-socket.js";
 
import type { Socket } from "net";
 
import type { JsonRpcApiProviderOptions } from "./provider-jsonrpc.js";
import type { Networkish } from "./network.js";
 
 
// @TODO: Is this sufficient? Is this robust? Will newlines occur between
// all payloads and only between payloads?
function splitBuffer(data: Buffer): { messages: Array<string>, remaining: Buffer } {
    const messages: Array<string> = [ ];

    let lastStart = 0;
    while (true) {
        const nl = data.indexOf(10, lastStart);
        if (nl === -1) { break; }
        messages.push(data.subarray(lastStart, nl).toString().trim());
        lastStart = nl + 1;
    }

    return { messages, remaining: data.subarray(lastStart) };
}
 
/**
 *  An **IpcSocketProvider** connects over an IPC socket on the host
 *  which provides fast access to the node, but requires the node and
 *  the script run on the same machine.
 */
export class IpcSocketProvider extends SocketProvider {
    #socket: Socket;

    /**
     *  The connected socket.
     */
    get socket(): Socket { return this.#socket; }

    constructor(path: string, network?: Networkish, options?: JsonRpcApiProviderOptions) {
        super(network, options);
        this.#socket = connect(path);

        this.socket.on("ready", async () => {
            try {
                await this._start();
            } catch (error) {
                console.log("failed to start IpcSocketProvider", error);
                // @TODO: Now what? Restart?
            }
        });

        let response = Buffer.alloc(0);
        this.socket.on("data", (data) => {
            response = Buffer.concat([ response, data ]);
            const { messages, remaining } = splitBuffer(response);
            messages.forEach((message) => {
                this._processMessage(message);
            });
            response = remaining;
        });

        this.socket.on("end", () => {
            this.emit("close");
            this.socket.destroy();
            this.socket.end();
        });
    }

    destroy(): void {
        this.socket.destroy();
        this.socket.end();

        super.destroy();
    }

    async _write(message: string): Promise<void> {
        if (!message.endsWith("\n")) { message += "\n"; }
        this.socket.write(message);
    }
}