waffle/frontend/src/gateway.js

183 lines
4.8 KiB
JavaScript
Raw Normal View History

2022-05-05 20:52:35 +03:00
import logger from "./logging";
2022-05-05 16:31:10 +03:00
import { 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,
};
export const GatewayPayloadType = {
Hello: 0,
Authenticate: 1,
Ready: 2,
Ping: 3,
ChannelCreate: 110,
ChannelUpdate: 111,
ChannelDelete: 112,
MessageCreate: 120,
MessageUpdate: 121,
MessageDelete: 122,
2022-08-07 03:00:14 +03:00
TypingStart: 130,
2022-08-08 05:12:31 +03:00
PresenceUpdate: 140
}
export const GatewayEventType = {
...GatewayPayloadType,
Open: -5,
2022-04-26 22:45:40 +03:00
Close: -4,
BadAuth: -3,
}
2022-08-08 05:12:31 +03:00
export const GatewayPresenceStatus = {
Offline: 0,
Online: 1
}
2022-05-05 20:52:35 +03:00
const log = logger("Gateway");
2022-04-23 23:07:46 +03:00
export default {
ws: null,
authenticated: false,
open: false,
heartbeatInterval: null,
user: null,
channels: null,
reconnectDelay: 400,
reconnectTimeout: null,
handlers: new Map(),
2022-04-27 22:03:51 +03:00
disableReconnect: false,
2022-04-26 22:45:40 +03:00
init(token) {
if (!token) {
log("no auth token, skipping connection");
this.dispatch(GatewayEventType.Close, GatewayErrors.BAD_AUTH);
2022-04-26 22:45:40 +03:00
this.dispatch(GatewayEventType.BadAuth, 0);
return false;
}
log(`connecting to gateway - gatewayBase: ${getItem("server:gatewayBase")}`);
this.ws = new WebSocket(getItem("server:gatewayBase"));
this.ws.onopen = () => {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
2022-04-27 22:03:51 +03:00
this.disableReconnect = false;
this.open = true;
this.dispatch(GatewayEventType.Open, null);
2022-04-23 23:07:46 +03:00
log("open");
};
this.ws.onmessage = (event) => {
const payload = JSON.parse(event.data);
switch (payload.t) {
case GatewayPayloadType.Hello: {
this.send({
t: GatewayPayloadType.Authenticate,
d: token
});
this.heartbeatInterval = setInterval(() => {
this.send({
t: GatewayPayloadType.Ping,
d: 0
});
}, payload.d.pingInterval);
2022-04-23 23:07:46 +03:00
log("hello");
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-23 23:07:46 +03:00
log("ready");
break;
}
}
this.dispatch(payload.t, payload.d);
};
2022-04-26 22:45:40 +03:00
this.ws.onclose = ({ code }) => {
this.authenticated = false;
this.user = null;
this.channels = null;
this.open = false;
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
}
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-23 23:07:46 +03:00
log("close");
};
2022-05-05 15:33:22 +03:00
this.ws.onerror = (e) => {
log("websocket: onerror", e);
};
return true;
},
send(data) {
return this.ws.send(JSON.stringify(data));
},
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();
}
};