Fix config typing and make Client easier to test

This commit is contained in:
Reto Brunner 2023-03-17 11:03:50 +01:00
commit eb509f7100
8 changed files with 70 additions and 17 deletions

View File

@ -15,7 +15,7 @@ import inputs from "./plugins/inputs";
import PublicClient from "./plugins/packages/publicClient"; import PublicClient from "./plugins/packages/publicClient";
import SqliteMessageStorage from "./plugins/messageStorage/sqlite"; import SqliteMessageStorage from "./plugins/messageStorage/sqlite";
import TextFileMessageStorage from "./plugins/messageStorage/text"; import TextFileMessageStorage from "./plugins/messageStorage/text";
import Network, {IgnoreListItem, NetworkWithIrcFramework} from "./models/network"; import Network, {IgnoreListItem, NetworkConfig, NetworkWithIrcFramework} from "./models/network";
import ClientManager from "./clientManager"; import ClientManager from "./clientManager";
import {MessageStorage, SearchQuery, SearchResponse} from "./plugins/messageStorage/types"; import {MessageStorage, SearchQuery, SearchResponse} from "./plugins/messageStorage/types";
@ -78,6 +78,7 @@ export type UserConfig = {
hostname?: string; hostname?: string;
isSecure?: boolean; isSecure?: boolean;
}; };
networks?: NetworkConfig[];
}; };
export type Mention = { export type Mention = {
@ -95,9 +96,7 @@ class Client {
attachedClients!: { attachedClients!: {
[socketId: string]: {token: string; openChannel: number}; [socketId: string]: {token: string; openChannel: number};
}; };
config!: UserConfig & { config!: UserConfig;
networks?: Network[];
};
id!: number; id!: number;
idMsg!: number; idMsg!: number;
idChan!: number; idChan!: number;
@ -176,8 +175,16 @@ class Client {
this.registerPushSubscription(session, session.pushSubscription, true); this.registerPushSubscription(session, session.pushSubscription, true);
} }
}); });
}
(client.config.networks || []).forEach((network) => client.connect(network, true)); connect() {
const client = this;
if (client.networks.length !== 0) {
throw new Error(`${client.name} is already connected`);
}
(client.config.networks || []).forEach((network) => client.connectToNetwork(network, true));
// Networks are stored directly in the client object // Networks are stored directly in the client object
// We don't need to keep it in the config object // We don't need to keep it in the config object
@ -188,7 +195,7 @@ class Client {
// Networks are created instantly, but to reduce server load on startup // Networks are created instantly, but to reduce server load on startup
// We randomize the IRC connections and channel log loading // We randomize the IRC connections and channel log loading
let delay = manager.clients.length * 500; let delay = client.manager.clients.length * 500;
client.networks.forEach((network) => { client.networks.forEach((network) => {
setTimeout(() => { setTimeout(() => {
network.channels.forEach((channel) => channel.loadMessages(client, network)); network.channels.forEach((channel) => channel.loadMessages(client, network));
@ -201,7 +208,7 @@ class Client {
delay += 1000 + Math.floor(Math.random() * 1000); delay += 1000 + Math.floor(Math.random() * 1000);
}); });
client.fileHash = manager.getDataToSave(client).newHash; client.fileHash = client.manager.getDataToSave(client).newHash;
} }
} }
@ -238,12 +245,10 @@ class Client {
return false; return false;
} }
connect(args: Record<string, any>, isStartup = false) { networkFromConfig(args: Record<string, any>): Network {
const client = this; const client = this;
let channels: Chan[] = [];
// Get channel id for lobby before creating other channels for nicer ids let channels: Chan[] = [];
const lobbyChannelId = client.idChan++;
if (Array.isArray(args.channels)) { if (Array.isArray(args.channels)) {
let badName = false; let badName = false;
@ -291,7 +296,7 @@ class Client {
} }
// TODO; better typing for args // TODO; better typing for args
const network = new Network({ return new Network({
uuid: args.uuid, uuid: args.uuid,
name: String( name: String(
args.name || (Config.values.lockNetwork ? Config.values.defaults.name : "") || "" args.name || (Config.values.lockNetwork ? Config.values.defaults.name : "") || ""
@ -319,6 +324,15 @@ class Client {
proxyUsername: String(args.proxyUsername || ""), proxyUsername: String(args.proxyUsername || ""),
proxyPassword: String(args.proxyPassword || ""), proxyPassword: String(args.proxyPassword || ""),
}); });
}
connectToNetwork(args: Record<string, any>, isStartup = false) {
const client = this;
// Get channel id for lobby before creating other channels for nicer ids
const lobbyChannelId = client.idChan++;
const network = this.networkFromConfig(args);
// Set network lobby channel id // Set network lobby channel id
network.getLobby().id = lobbyChannelId; network.getLobby().id = lobbyChannelId;
@ -359,7 +373,7 @@ class Client {
if (!isStartup) { if (!isStartup) {
client.save(); client.save();
channels.forEach((channel) => channel.loadMessages(client, network)); network.channels.forEach((channel) => channel.loadMessages(client, network));
} }
} }

View File

@ -7,6 +7,7 @@ import path from "path";
import Auth from "./plugins/auth"; import Auth from "./plugins/auth";
import Client, {UserConfig} from "./client"; import Client, {UserConfig} from "./client";
import Config from "./config"; import Config from "./config";
import {NetworkConfig} from "./models/network";
import WebPush from "./plugins/webpush"; import WebPush from "./plugins/webpush";
import log from "./log"; import log from "./log";
import {Server} from "socket.io"; import {Server} from "socket.io";
@ -144,6 +145,7 @@ class ClientManager {
} }
} else { } else {
client = new Client(this, name, userConfig); client = new Client(this, name, userConfig);
client.connect();
this.clients.push(client); this.clients.push(client);
} }

View File

@ -33,6 +33,13 @@ export type FilteredChannel = Chan & {
totalMessages: number; totalMessages: number;
}; };
export type ChanConfig = {
name: string;
key?: string;
muted?: boolean;
type?: string;
};
class Chan { class Chan {
id: number; id: number;
messages: Msg[]; messages: Msg[];

View File

@ -1,7 +1,7 @@
import _ from "lodash"; import _ from "lodash";
import {v4 as uuidv4} from "uuid"; import {v4 as uuidv4} from "uuid";
import IrcFramework, {Client as IRCClient} from "irc-framework"; import IrcFramework, {Client as IRCClient} from "irc-framework";
import Chan, {Channel, ChanType} from "./chan"; import Chan, {ChanConfig, Channel, ChanType} from "./chan";
import Msg, {MessageType} from "./msg"; import Msg, {MessageType} from "./msg";
import Prefix from "./prefix"; import Prefix from "./prefix";
import Helper, {Hostmask} from "../helper"; import Helper, {Hostmask} from "../helper";
@ -67,6 +67,34 @@ export type NetworkWithIrcFramework = Network & {
}; };
}; };
export type NetworkConfig = {
nick: string;
name: string;
host: string;
port: number;
tls: boolean;
userDisconnected: boolean;
rejectUnauthorized: boolean;
password: string;
awayMessage: string;
commands: any[];
username: string;
realname: string;
leaveMessage: string;
sasl: string;
saslAccount: string;
saslPassword: string;
channels: ChanConfig[];
uuid: string;
proxyHost: string;
proxyPort: number;
proxyUsername: string;
proxyPassword: string;
proxyEnabled: boolean;
highlightRegex?: string;
ignoreList: any[];
};
class Network { class Network {
nick: string; nick: string;
name: string; name: string;

View File

@ -39,7 +39,7 @@ const input: PluginInputHandler = function (network, chan, cmd, args) {
} }
const host = args[0]; const host = args[0];
this.connect({host, port, tls}); this.connectToNetwork({host, port, tls});
return true; return true;
}; };

View File

@ -485,7 +485,7 @@ function initializeClient(
data.commands = null; data.commands = null;
data.ignoreList = null; data.ignoreList = null;
client.connect(data); client.connectToNetwork(data);
} }
}); });
@ -948,6 +948,7 @@ function performAuthentication(this: Socket, data) {
if (Config.values.public) { if (Config.values.public) {
client = new Client(manager!); client = new Client(manager!);
client.connect();
manager!.clients.push(client); manager!.clients.push(client);
socket.on("disconnect", function () { socket.on("disconnect", function () {

View File

@ -30,7 +30,7 @@ describe("Network", function () {
expect(network1.uuid).to.not.equal(network2.uuid); expect(network1.uuid).to.not.equal(network2.uuid);
}); });
it("lobby should be at the top", function () { it("should keep the lobby at the top", function () {
const network = new Network({ const network = new Network({
name: "Super Nice Network", name: "Super Nice Network",
channels: [ channels: [

View File

@ -27,6 +27,7 @@ describe("Custom highlights", function () {
}, },
} as any } as any
); );
client.connect();
logInfoStub.restore(); logInfoStub.restore();
expect(userLoadedLog).to.equal("User test loaded\n"); expect(userLoadedLog).to.equal("User test loaded\n");