2022-04-23 23:07:46 +03:00
|
|
|
import logging from "./logging";
|
2022-04-14 02:12:38 +03:00
|
|
|
import { getAuthToken, getItem } from "./storage";
|
|
|
|
|
2022-04-26 22:45:40 +03:00
|
|
|
export const GatewayErrors = {
|
|
|
|
BAD_PAYLOAD: 4001,
|
|
|
|
BAD_AUTH: 4002,
|
|
|
|
AUTHENTICATION_TIMEOUT: 4003,
|
|
|
|
NO_PING: 4004,
|
|
|
|
FLOODING: 4005,
|
|
|
|
ALREADY_AUTHENTICATED: 4006,
|
|
|
|
PAYLOAD_TOO_LARGE: 4007,
|
|
|
|
TOO_MANY_SESSIONS: 4008,
|
|
|
|
};
|
|
|
|
|
2022-04-14 02:12:38 +03:00
|
|
|
export const GatewayPayloadType = {
|
|
|
|
Hello: 0,
|
|
|
|
Authenticate: 1,
|
|
|
|
Ready: 2,
|
|
|
|
Ping: 3,
|
|
|
|
|
|
|
|
ChannelCreate: 110,
|
|
|
|
ChannelUpdate: 111,
|
|
|
|
ChannelDelete: 112,
|
|
|
|
|
|
|
|
MessageCreate: 120,
|
|
|
|
MessageUpdate: 121,
|
|
|
|
MessageDelete: 122,
|
|
|
|
}
|
|
|
|
|
2022-04-17 04:08:40 +03:00
|
|
|
export const GatewayEventType = {
|
|
|
|
...GatewayPayloadType,
|
|
|
|
|
|
|
|
Open: -5,
|
2022-04-26 22:45:40 +03:00
|
|
|
Close: -4,
|
|
|
|
BadAuth: -3,
|
2022-04-17 04:08:40 +03:00
|
|
|
}
|
|
|
|
|
2022-04-25 18:47:27 +03:00
|
|
|
const log = logging.logger("Gateway", true);
|
2022-04-23 23:07:46 +03:00
|
|
|
|
2022-04-14 02:12:38 +03:00
|
|
|
export default {
|
|
|
|
ws: null,
|
|
|
|
authenticated: false,
|
2022-04-17 20:23:20 +03:00
|
|
|
open: false,
|
2022-04-14 02:12:38 +03:00
|
|
|
heartbeatInterval: null,
|
|
|
|
user: null,
|
|
|
|
channels: null,
|
2022-04-14 16:56:01 +03:00
|
|
|
reconnectDelay: 400,
|
|
|
|
reconnectTimeout: null,
|
2022-04-17 04:08:40 +03:00
|
|
|
handlers: new Map(),
|
2022-04-27 22:03:51 +03:00
|
|
|
disableReconnect: false,
|
2022-04-26 22:45:40 +03:00
|
|
|
init(token) {
|
2022-04-14 16:56:01 +03:00
|
|
|
if (!token) {
|
2022-04-25 18:47:27 +03:00
|
|
|
log("no auth token, skipping connection");
|
2022-04-26 22:45:40 +03:00
|
|
|
this.dispatch(GatewayEventType.BadAuth, 0);
|
2022-04-14 16:56:01 +03:00
|
|
|
return false;
|
|
|
|
}
|
2022-04-25 18:47:27 +03:00
|
|
|
log(`connecting to gateway - gatewayBase: ${getItem("gatewayBase")}`);
|
2022-04-14 02:12:38 +03:00
|
|
|
this.ws = new WebSocket(getItem("gatewayBase"));
|
2022-04-14 16:56:01 +03:00
|
|
|
this.ws.onopen = () => {
|
|
|
|
if (this.reconnectTimeout) {
|
|
|
|
clearTimeout(this.reconnectTimeout);
|
|
|
|
}
|
2022-04-27 22:03:51 +03:00
|
|
|
this.disableReconnect = false;
|
2022-04-17 20:23:20 +03:00
|
|
|
this.open = true;
|
2022-04-17 04:08:40 +03:00
|
|
|
this.dispatch(GatewayEventType.Open, null);
|
2022-04-23 23:07:46 +03:00
|
|
|
log("open");
|
2022-04-14 16:56:01 +03:00
|
|
|
};
|
|
|
|
this.ws.onmessage = (event) => {
|
|
|
|
const payload = JSON.parse(event.data);
|
2022-04-14 02:12:38 +03:00
|
|
|
|
|
|
|
switch (payload.t) {
|
|
|
|
case GatewayPayloadType.Hello: {
|
|
|
|
this.send({
|
|
|
|
t: GatewayPayloadType.Authenticate,
|
2022-04-14 16:56:01 +03:00
|
|
|
d: token
|
2022-04-14 02:12:38 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
this.heartbeatInterval = setInterval(() => {
|
|
|
|
this.send({
|
|
|
|
t: GatewayPayloadType.Ping,
|
|
|
|
d: 0
|
|
|
|
});
|
|
|
|
}, payload.d.pingInterval);
|
2022-04-14 22:08:08 +03:00
|
|
|
|
2022-04-23 23:07:46 +03:00
|
|
|
log("hello");
|
2022-04-14 02:12:38 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GatewayPayloadType.Ready: {
|
|
|
|
this.user = payload.d.user;
|
|
|
|
this.channels = payload.d.channels;
|
2022-04-14 22:04:41 +03:00
|
|
|
|
|
|
|
this.reconnectDelay = 400;
|
2022-04-14 22:08:08 +03:00
|
|
|
|
2022-04-23 23:07:46 +03:00
|
|
|
log("ready");
|
2022-04-14 02:12:38 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-04-17 04:08:40 +03:00
|
|
|
|
|
|
|
this.dispatch(payload.t, payload.d);
|
2022-04-14 02:12:38 +03:00
|
|
|
};
|
2022-04-26 22:45:40 +03:00
|
|
|
this.ws.onclose = ({ code }) => {
|
2022-04-14 02:12:38 +03:00
|
|
|
this.authenticated = false;
|
|
|
|
this.user = null;
|
|
|
|
this.channels = null;
|
2022-04-17 20:23:20 +03:00
|
|
|
this.open = false;
|
2022-04-14 02:12:38 +03:00
|
|
|
if (this.heartbeatInterval) {
|
|
|
|
clearInterval(this.heartbeatInterval);
|
|
|
|
}
|
2022-04-14 22:08:08 +03:00
|
|
|
|
2022-04-26 22:45:40 +03:00
|
|
|
if (code === GatewayErrors.BAD_AUTH) {
|
|
|
|
this.dispatch(GatewayEventType.BadAuth, 1);
|
|
|
|
if (this.reconnectTimeout)
|
|
|
|
clearTimeout(this.reconnectTimeout);
|
2022-04-27 22:03:51 +03:00
|
|
|
} else if (this.disableReconnect) {
|
|
|
|
if (this.reconnectTimeout)
|
|
|
|
clearTimeout(this.reconnectTimeout);
|
2022-04-26 22:45:40 +03:00
|
|
|
} else {
|
|
|
|
if (this.reconnectDelay < 60000) {
|
|
|
|
this.reconnectDelay *= 2;
|
|
|
|
}
|
|
|
|
this.reconnectTimeout = setTimeout(() => {
|
2022-04-27 17:08:19 +03:00
|
|
|
this.init(token);
|
2022-04-26 22:45:40 +03:00
|
|
|
}, this.reconnectDelay);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.dispatch(GatewayEventType.Close, code);
|
2022-04-17 04:08:40 +03:00
|
|
|
|
2022-04-23 23:07:46 +03:00
|
|
|
log("close");
|
2022-04-14 02:12:38 +03:00
|
|
|
};
|
2022-04-14 16:56:01 +03:00
|
|
|
|
|
|
|
return true;
|
2022-04-14 02:12:38 +03:00
|
|
|
},
|
|
|
|
send(data) {
|
|
|
|
return this.ws.send(JSON.stringify(data));
|
2022-04-17 04:08:40 +03:00
|
|
|
},
|
|
|
|
dispatch(event, payload) {
|
|
|
|
const eventHandlers = this.handlers.get(event);
|
|
|
|
if (!eventHandlers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
eventHandlers.forEach((e) => {
|
|
|
|
e(payload);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
subscribe(event, handler) {
|
|
|
|
if (!this.handlers.get(event)) {
|
|
|
|
this.handlers.set(event, new Set());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.handlers.get(event).add(handler);
|
|
|
|
return handler; // can later be used for unsubscribe()
|
|
|
|
},
|
|
|
|
unsubscribe(event, handler) {
|
|
|
|
const eventHandlers = this.handlers.get(event);
|
|
|
|
if (!eventHandlers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
eventHandlers.delete(handler);
|
|
|
|
|
|
|
|
if (eventHandlers.size < 1) {
|
|
|
|
this.handlers.delete(event);
|
|
|
|
}
|
2022-04-27 22:03:51 +03:00
|
|
|
},
|
|
|
|
close() {
|
|
|
|
this.disableReconnect = true;
|
|
|
|
if (this.ws)
|
|
|
|
this.ws.close();
|
2022-04-14 02:12:38 +03:00
|
|
|
}
|
|
|
|
};
|