Refactored base structure
This commit is contained in:
204
www/res/js/modules/usimp.js
Normal file
204
www/res/js/modules/usimp.js
Normal file
@ -0,0 +1,204 @@
|
||||
"use strict";
|
||||
|
||||
export class Domain {
|
||||
name;
|
||||
id;
|
||||
servers;
|
||||
invalidServers;
|
||||
|
||||
toString() {
|
||||
return `[${this.name}]`;
|
||||
}
|
||||
|
||||
constructor(jsonData, domainServers) {
|
||||
// FIXME check values
|
||||
this.name = jsonData.name;
|
||||
this.id = jsonData.id;
|
||||
this.servers = [];
|
||||
for (let domainServer of domainServers) {
|
||||
this.servers.push(new DomainServer(domainServer));
|
||||
}
|
||||
this.invalidServers = [];
|
||||
}
|
||||
|
||||
static async fromName(domainName) {
|
||||
return fetch(`https://${domainName}/.well-known/usimp.json`, {
|
||||
redirect: "manual",
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
} else {
|
||||
throw "Invalid response";
|
||||
}
|
||||
}).then(data => {
|
||||
return new Domain(data.domain, data.domain_servers);
|
||||
});
|
||||
}
|
||||
|
||||
chooseDomainServer() {
|
||||
if (this.servers.length === 0) throw Error("No domain servers specified");
|
||||
|
||||
this.servers.filter(srv => this.invalidServers.map(srv => srv.id).includes(srv.id));
|
||||
if (this.servers.length === 0) throw Error("No domain servers reachable");
|
||||
if (this.servers.length === 1) return this.servers[0];
|
||||
|
||||
let priority = this.servers.reduce((min, srv) => Math.min(min, srv.priority), Infinity);
|
||||
let domainServers = this.servers.filter(srv => srv.priority === priority);
|
||||
if (domainServers.length === 1) return this.servers[0];
|
||||
|
||||
let totalWeight = domainServers.reduce((total, srv) => total + srv.weight, 0);
|
||||
let w = Math.floor(Math.random() * totalWeight);
|
||||
|
||||
let accumulator = 0;
|
||||
for (let srv of domainServers) {
|
||||
accumulator += srv.weight;
|
||||
if (w < accumulator) return srv;
|
||||
}
|
||||
|
||||
throw "Domain server selection did not work correctly";
|
||||
}
|
||||
}
|
||||
|
||||
export class DomainServer {
|
||||
host;
|
||||
id;
|
||||
priority;
|
||||
weight;
|
||||
protocols;
|
||||
|
||||
toString() {
|
||||
return `[${this.host}/${this.priority}/${this.weight}]`;
|
||||
}
|
||||
|
||||
constructor(jsonData) {
|
||||
// FIXME check values
|
||||
this.host = jsonData.host;
|
||||
this.id = jsonData.id;
|
||||
this.priority = jsonData.priority;
|
||||
this.weight = jsonData.weight;
|
||||
this.protocols = jsonData.protocols;
|
||||
}
|
||||
}
|
||||
|
||||
export class Account {
|
||||
|
||||
}
|
||||
|
||||
export class Member {
|
||||
|
||||
}
|
||||
|
||||
export class Room {
|
||||
|
||||
}
|
||||
|
||||
export class Event {
|
||||
|
||||
}
|
||||
|
||||
export class Session {
|
||||
domain;
|
||||
server;
|
||||
token;
|
||||
|
||||
httpBaseUrl;
|
||||
wsConnection;
|
||||
numRequests;
|
||||
|
||||
constructor(domain) {
|
||||
this.domain = domain;
|
||||
this.server = domain.chooseDomainServer();
|
||||
this.numRequests = 0;
|
||||
|
||||
const host = this.server.host;
|
||||
const protocols = this.server.protocols;
|
||||
|
||||
/*
|
||||
if ("wss" in protocols) {
|
||||
this.wsConnection = new WebSocket(`wss://${host}:${protocols.wss}/_usimp/websocket`, ["usimp"]);
|
||||
} else if ("ws" in protocols) {
|
||||
this.wsConnection = new WebSocket(`ws://${host}:${protocols.ws}/_usimp/websocket`, ["usimp"])
|
||||
}
|
||||
*/
|
||||
|
||||
if ("https" in protocols) {
|
||||
this.httpBaseUrl = `https://${host}:${protocols.https}/_usimp`;
|
||||
} else if ("http" in protocols) {
|
||||
this.httpBaseUrl = `http://${host}:${protocols.http}/_usimp`;
|
||||
} else {
|
||||
throw "Domain server provides no supported transport protocols";
|
||||
}
|
||||
}
|
||||
|
||||
send(endpoint, data) {
|
||||
this.numRequests++;
|
||||
if (this.wsConnection) {
|
||||
this.wsConnection.send(JSON.stringify({
|
||||
'request_num': this.numRequests,
|
||||
'data': data
|
||||
}));
|
||||
} else {
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'To-Domain': this.domain.id,
|
||||
'From-Domain': this.domain.id,
|
||||
};
|
||||
if (this.token) {
|
||||
headers['Authorization'] = `usimp ${this.token}`;
|
||||
}
|
||||
|
||||
return fetch(`${this.httpBaseUrl}/${endpoint}`, {
|
||||
method: "POST",
|
||||
headers: headers,
|
||||
body: JSON.stringify(data),
|
||||
}).then(response => {
|
||||
return response.json();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
authenticate(accountName, password) {
|
||||
return this.send("authenticate", {
|
||||
type: "password",
|
||||
name: accountName,
|
||||
password: password,
|
||||
}).then(response => {
|
||||
this.token = response.token;
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
sendEvent(roomId, data) {
|
||||
return this.send("send_event", {
|
||||
room_id: roomId,
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
subscribe(func) {
|
||||
this.numRequests++;
|
||||
if (this.wsConnection) {
|
||||
// TODO
|
||||
} else {
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'To-Domain': this.domain.id,
|
||||
'From-Domain': this.domain.id,
|
||||
};
|
||||
if (this.token) {
|
||||
headers['Authorization'] = `usimp ${this.token}`;
|
||||
}
|
||||
|
||||
fetch(`${this.httpBaseUrl}/subscribe`, {
|
||||
method: "POST",
|
||||
headers: headers,
|
||||
body: JSON.stringify({}),
|
||||
}).then(response => {
|
||||
return response.json();
|
||||
}).then(response => {
|
||||
func(response);
|
||||
this.subscribe(func);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user