189 lines
5.3 KiB
JavaScript

import EventEmitter from "@foxify/events"
import axios from "axios"
import { io } from "socket.io-client"
import remotes from "./remotes"
//import request from "./handlers/request"
import Storage from "./helpers/withStorage"
import SessionModel from "./models/session"
import { createHandlers } from "./models"
globalThis.isServerMode = typeof window === "undefined" && typeof global !== "undefined"
if (globalThis.isServerMode) {
const { Buffer } = require("buffer")
globalThis.b64Decode = (data) => {
return Buffer.from(data, "base64").toString("utf-8")
}
globalThis.b64Encode = (data) => {
return Buffer.from(data, "utf-8").toString("base64")
}
}
export async function createWebsockets() {
const instances = globalThis.__comty_shared_state.wsInstances
for (let [key, instance] of Object.entries(instances)) {
if (instance.connected) {
// disconnect first
instance.disconnect()
}
// remove current listeners
instance.removeAllListeners()
delete globalThis.__comty_shared_state.wsInstances[key]
}
for (let [key, remote] of Object.entries(remotes)) {
if (!remote.hasWebsocket) {
continue
}
let opts = {
transports: ["websocket"],
autoConnect: remote.autoConnect ?? true,
...remote.wsParams ?? {},
}
if (remote.noAuth !== true) {
opts.auth = {
token: SessionModel.token,
}
}
globalThis.__comty_shared_state.wsInstances[key] = io(remote.wsOrigin ?? remote.origin, opts)
}
// regsister events
for (let [key, instance] of Object.entries(instances)) {
instance.on("connect", () => {
console.debug(`[WS-API][${key}] Connected`)
if (remotes[key].useClassicAuth && remotes[key].noAuth !== true) {
// try to auth
instance.emit("authenticate", {
token: SessionModel.token,
})
}
globalThis.__comty_shared_state.eventBus.emit(`${key}:connected`)
})
instance.on("disconnect", () => {
console.debug(`[WS-API][${key}] Disconnected`)
globalThis.__comty_shared_state.eventBus.emit(`${key}:disconnected`)
})
instance.on("error", (error) => {
console.error(`[WS-API][${key}] Error`, error)
globalThis.__comty_shared_state.eventBus.emit(`${key}:error`, error)
})
instance.onAny((event, ...args) => {
console.debug(`[WS-API][${key}] Event (${event})`, ...args)
globalThis.__comty_shared_state.eventBus.emit(`${key}:${event}`, ...args)
})
}
}
export async function reconnectWebsockets({ force = false } = {}) {
const instances = globalThis.__comty_shared_state.wsInstances
for (let [key, instance] of Object.entries(instances)) {
if (instance.connected) {
if (!instance.auth) {
instance.disconnect()
instance.auth = {
token: SessionModel.token,
}
instance.connect()
continue
}
if (!force) {
instance.emit("reauthenticate", {
token: SessionModel.token,
})
continue
}
// disconnect first
instance.disconnect()
}
if (remotes[key].noAuth !== true) {
instance.auth = {
token: SessionModel.token,
}
}
instance.connect()
}
}
export default function createClient({
accessKey = null,
privateKey = null,
enableWs = false,
} = {}) {
const sharedState = globalThis.__comty_shared_state = {
onExpiredExceptionEvent: false,
excludedExpiredExceptionURL: ["/session/regenerate"],
eventBus: new EventEmitter(),
mainOrigin: remotes.default.origin,
instances: Object(),
wsInstances: Object(),
rest: null,
}
if (globalThis.isServerMode) {
sharedState.rest = createHandlers()
}
if (privateKey && accessKey && globalThis.isServerMode) {
Storage.engine.set("token", `${accessKey}:${privateKey}`)
}
// create instances for every remote
for (const [key, remote] of Object.entries(remotes)) {
sharedState.instances[key] = axios.create({
baseURL: remote.origin,
headers: {
"Content-Type": "application/json",
}
})
// create a interceptor to attach the token every request
sharedState.instances[key].interceptors.request.use((config) => {
// check if current request has no Authorization header, if so, attach the token
if (!config.headers["Authorization"]) {
const sessionToken = SessionModel.token
if (sessionToken) {
config.headers["Authorization"] = `${globalThis.isServerMode ? "Server" : "Bearer"} ${sessionToken}`
} else {
console.warn("Making a request with no session token")
}
}
return config
})
}
if (enableWs) {
createWebsockets()
}
return sharedState
}