Quellcode durchsuchen

Добавлен класс WebSocketConnection

Book Pauk vor 5 Jahren
Ursprung
Commit
59539e7e90
1 geänderte Dateien mit 185 neuen und 0 gelöschten Zeilen
  1. 185 0
      client/api/WebSocketConnection.js

+ 185 - 0
client/api/WebSocketConnection.js

@@ -0,0 +1,185 @@
+const cleanPeriod = 60*1000;//1 минута
+
+class WebSocketConnection {
+    //messageLifeTime в минутах (cleanPeriod)
+    constructor(messageLifeTime = 5) {
+        this.ws = null;
+        this.timer = null;
+        this.listeners = [];
+        this.messageQueue = [];
+        this.messageLifeTime = messageLifeTime;
+        this.requestId = 0;
+    }
+
+    addListener(listener) {
+        if (this.listeners.indexOf(listener) < 0)
+            this.listeners.push(Object.assign({regTime: Date.now()}, listener));
+    }
+
+    //рассылаем сообщение и удаляем те обработчики, которые его получили
+    emit(mes, isError) {
+        const len = this.listeners.length;
+        if (len > 0) {
+            let newListeners = [];
+            for (const listener of this.listeners) {
+                let emitted = false;
+                if (isError) {
+                    if (listener.onError)
+                        listener.onError(mes);
+                    emitted = true;
+                } else {
+                    if (listener.onMessage) {
+                        if (listener.requestId) {
+                            if (listener.requestId === mes.requestId) {
+                                listener.onMessage(mes);
+                                emitted = true;
+                            }
+                        } else {
+                            listener.onMessage(mes);
+                            emitted = true;
+                        }
+                    } else {
+                        emitted = true;
+                    }
+                }
+
+                if (!emitted)
+                    newListeners.push(listener);
+            }
+            this.listeners = newListeners;
+        }
+        
+        return this.listeners.length != len;
+    }
+
+    open() {
+        return new Promise((resolve, reject) => {
+            if (this.ws && this.ws.readyState == WebSocket.OPEN) {
+                resolve(this.ws);
+            } else {
+                this.ws = new WebSocket(`ws://${window.location.host}`);
+
+                if (this.timer) {
+                    clearTimeout(this.timer);
+                }
+                this.timer = setTimeout(() => { this.periodicClean(); }, cleanPeriod);
+
+                let resolved = false;
+                this.ws.onopen = (e) => {
+                    resolved = true;
+                    resolve(e);
+                };
+
+                this.ws.onmessage = (e) => {
+                    try {
+                        const mes = JSON.parse(e.data);
+                        this.messageQueue.push({regTime: Date.now(), mes});
+
+                        let newMessageQueue = [];
+                        for (const message of this.messageQueue) {
+                            if (!this.emit(message.mes)) {
+                                newMessageQueue.push(message);
+                            }
+                        }
+
+                        this.messageQueue = newMessageQueue;
+                    } catch (e) {
+                        this.emit(e.message, true);
+                    }
+                };
+
+                this.ws.onerror = (e) => {
+                    this.emit(e.message, true);
+                    if (!resolved)
+                        reject(e);
+                };
+            }
+        });
+    }
+
+    //timeout в минутах (cleanPeriod)
+    message(timeout = 2) {
+        return new Promise((resolve, reject) => {
+            this.addListener({
+                timeout,
+                onMessage: (mes) => {
+                    resolve(mes);
+                },
+                onError: (e) => {
+                    reject(e);
+                }
+            });
+        });
+    }
+
+    //timeout в минутах (cleanPeriod)
+    messageId(requestId, timeout = 2) {
+        return new Promise((resolve, reject) => {
+            this.addListener({
+                requestId,
+                timeout,
+                onMessage: (mes) => {
+                    resolve(mes);
+                },
+                onError: (e) => {
+                    reject(e);
+                }
+            });
+        });
+    }
+
+    send(req) {
+        if (this.ws && this.ws.readyState == WebSocket.OPEN) {
+            this.ws.send(JSON.stringify(req));
+        } else {
+            throw new Error('WebSocket connection is not ready');
+        }
+    }
+
+    sendId(req) {
+        if (this.ws && this.ws.readyState == WebSocket.OPEN) {
+            const requestId = ++this.requestId;
+            this.ws.send(Object.assign({requestId}, JSON.stringify(req)));
+            return requestId;
+        } else {
+            throw new Error('WebSocket connection is not ready');
+        }
+    }
+
+    close() {
+        if (this.ws && this.ws.readyState == WebSocket.OPEN) {
+            this.ws.close();
+        }
+    }
+
+    periodicClean() {
+        try {
+            this.timer = null;
+
+            const now = Date.now();
+            //чистка listeners
+            let newListeners = [];
+            for (const listener of this.listeners) {
+                if (now - listener.regTime < listener.timeout*cleanPeriod - 50) {
+                    newListeners.push(listener);
+                }
+            }
+            this.listeners = newListeners;
+
+            //чистка messageQueue
+            let newMessageQueue = [];
+            for (const message of this.messageQueue) {
+                if (now - message.regTime < this.messageLifeTime*cleanPeriod - 50) {
+                    newMessageQueue.push(message);
+                }
+            }
+            this.messageQueue = newMessageQueue;
+        } finally {
+            if (this.ws.readyState == WebSocket.OPEN) {
+                this.timer = setTimeout(() => { this.periodicClean(); }, cleanPeriod);
+            }
+        }
+    }
+}
+
+export default WebSocketConnection;