~glacambre/firenvim

ref: 4907b8d3554aae7f7f2c298a73f7f512f0ead2ed firenvim/src/nvimproc/Stdout.ts -rw-r--r-- 2.0 KiB
4907b8d3glacambre Improve testsuite 2 years ago
                                                                                
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
import * as msgpack from "msgpack-lite";
import * as browser from "webextension-polyfill"; //lgtm [js/unused-local-variable]

export class Stdout {
    private listeners = new Map<string, Array<(...args: any[]) => any>>();
    private messageNames = new Map([[0, "request"], [1, "response"], [2, "notification"]]);
    // Holds previously-received, incomplete and unprocessed messages
    private prev = new Uint8Array(0);

    constructor(private socket: WebSocket) {
        this.socket.addEventListener("message", this.onMessage.bind(this));
    }

    public addListener(kind: string, listener: (...args: any[]) => any) {
        let arr = this.listeners.get(kind);
        if (!arr) {
            arr = [];
            this.listeners.set(kind, arr);
        }
        arr.push(listener);
    }

    private onMessage(msg: any) {
        const data = new Uint8Array(msg.data);
        const uint8arr = new Uint8Array(this.prev.length + data.length);
        uint8arr.set(this.prev);
        uint8arr.set(data, this.prev.length);
        let decoded;
        try {
            decoded = msgpack.decode(uint8arr);
        } catch (e) {
            // Buffer shortage means rpc messages are split
            if (e.message !== "BUFFER_SHORTAGE") {
                this.prev = new Uint8Array(0);
                throw e;
            }
            this.prev = uint8arr;
            return;
        }
        this.prev = new Uint8Array(0);
        const [kind, reqId, data1, data2] = decoded;
        const name = this.messageNames.get(kind);
        if (!name) {
            throw new Error(`Unhandled message kind! ${decoded}`);
        }
        const arr = this.listeners.get(name);
        if (arr) {
            arr.forEach(l => l(reqId, data1, data2));
        }

        // FIXME: This is a hack to deal with coallesced messages, there has to be a better way
        const rec = msgpack.encode(decoded);
        if (msg.data.byteLength > rec.length) {
            this.onMessage({ data: uint8arr.slice(rec.length) });
        }
    }
}