Add more socketio types

This commit is contained in:
Max Leiter 2022-05-31 14:42:00 -07:00
parent 4f41d80b88
commit ade6269de9
No known key found for this signature in database
GPG key ID: A3512F2F2F17EBDA
30 changed files with 204 additions and 102 deletions

View file

@ -28,7 +28,7 @@
<div
v-for="(users, mode) in groupedUsers"
:key="mode"
:class="['user-mode', getModeClass(mode as string)]"
:class="['user-mode', getModeClass(String(mode))]"
>
<template v-if="userSearchInput.length > 0">
<!-- eslint-disable -->

View file

@ -106,12 +106,12 @@ export default defineComponent({
watch(route, (newValue) => {
if (newValue.query.q) {
searchInput.value = newValue.query.q as string;
searchInput.value = String(newValue.query.q);
}
});
onMounted(() => {
searchInput.value = route.query.q as string;
searchInput.value = String(route.query.q);
searchOpened.value = onSearchPage.value;
if (searchInputField.value && !searchInput.value && searchOpened.value) {

View file

@ -3,7 +3,7 @@
v-if="activeChannel"
:network="activeChannel.network"
:channel="activeChannel.channel"
:focused="(route.query.focused as string)"
:focused="String(route.query.focused)"
@channel-changed="channelChanged"
/>
</template>
@ -27,7 +27,7 @@ export default defineComponent({
const store = useStore();
const activeChannel = computed(() => {
const chanId = parseInt(route.params.id as string, 10);
const chanId = parseInt(String(route.params.id), 10);
const channel = store.getters.findChannel(chanId);
return channel;
});

View file

@ -29,7 +29,7 @@ export default defineComponent({
const setNetworkData = () => {
socket.emit("network:get", String(route.params.uuid));
networkData.value = store.getters.findNetwork(route.params.uuid as string);
networkData.value = store.getters.findNetwork(String(route.params.uuid));
};
const handleSubmit = (data: {uuid: string; name: string}) => {
@ -38,9 +38,12 @@ export default defineComponent({
// TODO: move networks to vuex and update state when the network info comes in
const network = store.getters.findNetwork(data.uuid);
network.name = network.channels[0].name = data.name;
switchToChannel(network.channels[0]);
if (network) {
network.name = network.channels[0].name = data.name;
switchToChannel(network.channels[0]);
}
};
watch(

View file

@ -141,7 +141,7 @@ export default defineComponent({
});
const chan = computed(() => {
const chanId = parseInt(route.params.id as string, 10);
const chanId = parseInt(String(route.params.id), 10);
return store.getters.findChannel(chanId);
});

View file

@ -22,10 +22,10 @@ const emojiStrategy = {
callback(fuzzyGrep(term, emojiSearchTerms));
},
template([string, original]: [string, string]) {
return `<span class="emoji">${emojiMap[original] as string}</span> ${string}`;
return `<span class="emoji">${String(emojiMap[original])}</span> ${string}`;
},
replace([, original]) {
return "$1" + (emojiMap[original] as string);
return "$1" + String(emojiMap[original]);
},
index: 2,
};
@ -195,7 +195,7 @@ function enableAutocomplete(input: HTMLTextAreaElement) {
const position = input.selectionStart - lastMatch.length;
const newMatch = replaceNick(
// TODO: type this properly
currentMatches[tabCount % currentMatches.length] as string,
String(currentMatches[tabCount % currentMatches.length]),
position
);
const remainder = text.substring(input.selectionStart);
@ -317,13 +317,13 @@ function getCommands() {
return cmds;
}
function completeCommands(word) {
function completeCommands(word: string) {
const commands = getCommands();
return fuzzyGrep(word, commands);
}
function completeChans(word) {
const words = [];
function completeChans(word: string) {
const words: string[] = [];
for (const channel of store.state.activeChannel.network.channels) {
// Push all channels that start with the same CHANTYPE

View file

@ -200,7 +200,7 @@ export function generateChannelContextMenu(
});
}
const humanFriendlyChanTypeMap = {
const humanFriendlyChanTypeMap: Record<string, string> = {
lobby: "network",
channel: "channel",
query: "conversation",
@ -210,7 +210,7 @@ export function generateChannelContextMenu(
const mutableChanTypes = Object.keys(humanFriendlyChanTypeMap);
if (mutableChanTypes.includes(channel.type)) {
const chanType = humanFriendlyChanTypeMap[channel.type] as string;
const chanType = humanFriendlyChanTypeMap[channel.type];
items.push({
label: channel.muted ? `Unmute ${chanType}` : `Mute ${chanType}`,

View file

@ -3,7 +3,7 @@ import storage from "../localStorage";
import {router, navigate} from "../router";
import {store} from "../store";
import location from "../location";
let lastServerHash: string | null = null;
let lastServerHash: number | null = null;
declare global {
interface Window {
@ -16,17 +16,17 @@ socket.on("auth:success", function () {
updateLoadingMessage();
});
socket.on("auth:failed", function () {
socket.on("auth:failed", async function () {
storage.remove("token");
if (store.state.appLoaded) {
return reloadPage("Authentication failed, reloading…");
}
showSignIn();
await showSignIn();
});
socket.on("auth:start", function (serverHash) {
socket.on("auth:start", async function (serverHash) {
// If we reconnected and serverHash differs, that means the server restarted
// And we will reload the page to grab the latest version
if (lastServerHash && serverHash !== lastServerHash) {
@ -74,18 +74,18 @@ socket.on("auth:start", function (serverHash) {
hasConfig: store.state.serverConfiguration !== null,
});
} else {
showSignIn();
await showSignIn();
}
});
function showSignIn() {
async function showSignIn() {
// TODO: this flashes grey background because it takes a little time for vue to mount signin
if (window.g_TheLoungeRemoveLoading) {
window.g_TheLoungeRemoveLoading();
}
if (router.currentRoute.name !== "SignIn") {
navigate("SignIn");
if (router.currentRoute.value.name !== "SignIn") {
await navigate("SignIn");
}
}

View file

@ -26,7 +26,7 @@ socket.on("connect", function () {
});
function handleDisconnect(data) {
const message = (data.message || data) as string;
const message = String(data.message || data);
store.commit("isConnected", false);

View file

@ -2,11 +2,13 @@ import socket from "../socket";
import {store} from "../store";
socket.on("history:clear", function (data) {
const {channel} = store.getters.findChannel(data.target);
const netChan = store.getters.findChannel(data.target);
channel.messages = [];
channel.unread = 0;
channel.highlight = 0;
channel.firstUnread = 0;
channel.moreHistoryAvailable = false;
if (netChan?.channel) {
netChan.channel.messages = [];
netChan.channel.unread = 0;
netChan.channel.highlight = 0;
netChan.channel.firstUnread = 0;
netChan.channel.moreHistoryAvailable = false;
}
});

View file

@ -6,7 +6,7 @@ import {store} from "../store";
import parseIrcUri from "../helpers/parseIrcUri";
import {ClientNetwork, InitClientChan} from "../types";
socket.on("init", function (data) {
socket.on("init", async function (data) {
store.commit("networks", mergeNetworkData(data.networks));
store.commit("isConnected", true);
store.commit("currentUserVisibleError", null);
@ -24,30 +24,27 @@ socket.on("init", function (data) {
window.g_TheLoungeRemoveLoading();
}
void nextTick(() => {
// If we handled query parameters like irc:// links or just general
// connect parameters in public mode, then nothing to do here
if (!handleQueryParams()) {
// If we are on an unknown route or still on SignIn component
// then we can open last known channel on server, or Connect window if none
if (
!router.currentRoute.value.name ||
router.currentRoute.value.name === "SignIn"
) {
const channel = store.getters.findChannel(data.active);
await nextTick();
if (channel) {
switchToChannel(channel.channel);
} else if (store.state.networks.length > 0) {
// Server is telling us to open a channel that does not exist
// For example, it can be unset if you first open the page after server start
switchToChannel(store.state.networks[0].channels[0]);
} else {
navigate("Connect");
}
// If we handled query parameters like irc:// links or just general
// connect parameters in public mode, then nothing to do here
if (!handleQueryParams()) {
// If we are on an unknown route or still on SignIn component
// then we can open last known channel on server, or Connect window if none
if (!router.currentRoute.value.name || router.currentRoute.value.name === "SignIn") {
const channel = store.getters.findChannel(data.active);
if (channel) {
switchToChannel(channel.channel);
} else if (store.state.networks.length > 0) {
// Server is telling us to open a channel that does not exist
// For example, it can be unset if you first open the page after server start
switchToChannel(store.state.networks[0].channels[0]);
} else {
await navigate("Connect");
}
}
});
}
}
});
@ -172,7 +169,7 @@ function handleQueryParams() {
if (params.has("uri")) {
// Set default connection settings from IRC protocol links
const uri = params.get("uri");
const queryParams = parseIrcUri(uri as string);
const queryParams = parseIrcUri(String(uri));
cleanParams();
router.push({name: "Connect", query: queryParams}).catch(() => {

View file

@ -18,5 +18,12 @@ socket.on("join", function (data) {
return;
}
switchToChannel(store.getters.findChannel(data.chan.id).channel);
const chan = store.getters.findChannel(data.chan.id);
if (chan) {
switchToChannel(chan.channel);
} else {
// eslint-disable-next-line no-console
console.error("Could not find channel", data.chan.id);
}
});

View file

@ -1,7 +1,9 @@
/* eslint-disable @typescript-eslint/restrict-plus-operands */
import socket from "../socket";
import cleanIrcMessage from "../helpers/ircmessageparser/cleanIrcMessage";
import {store} from "../store";
import {switchToChannel} from "../router";
import {ClientChan, ClientMention, ClientMessage, NetChan} from "../types";
let pop;
@ -10,6 +12,7 @@ try {
pop.src = "audio/pop.wav";
} catch (e) {
pop = {
// eslint-disable-next-line @typescript-eslint/no-empty-function
play() {},
};
}
@ -92,7 +95,12 @@ socket.on("msg", function (data) {
}
});
function notifyMessage(targetId, channel, activeChannel, msg) {
function notifyMessage(
targetId: number,
channel: ClientChan,
activeChannel: NetChan,
msg: ClientMessage
) {
if (channel.muted) {
return;
}
@ -132,19 +140,23 @@ function notifyMessage(targetId, channel, activeChannel, msg) {
body = cleanIrcMessage(msg.text);
}
const timestamp = Date.parse(msg.time);
const timestamp = Date.parse(String(msg.time));
try {
if (store.state.hasServiceWorker) {
navigator.serviceWorker.ready.then((registration) => {
registration.active.postMessage({
type: "notification",
chanId: targetId,
timestamp: timestamp,
title: title,
body: body,
navigator.serviceWorker.ready
.then((registration) => {
registration.active?.postMessage({
type: "notification",
chanId: targetId,
timestamp: timestamp,
title: title,
body: body,
});
})
.catch(() => {
// no-op
});
});
} else {
const notify = new Notification(title, {
tag: `chan-${targetId}`,
@ -160,7 +172,7 @@ function notifyMessage(targetId, channel, activeChannel, msg) {
const channelTarget = store.getters.findChannel(targetId);
if (channelTarget) {
switchToChannel(channelTarget);
switchToChannel(channelTarget.channel);
}
});
}

View file

@ -2,8 +2,8 @@ import socket from "../socket";
import {store} from "../store";
socket.on("msg:preview", function (data) {
const {channel} = store.getters.findChannel(data.chan);
const message = channel.messages.find((m) => m.id === data.id);
const netChan = store.getters.findChannel(data.chan);
const message = netChan?.channel.messages.find((m) => m.id === data.id);
if (!message) {
return;

View file

@ -3,7 +3,9 @@ import {store} from "../store";
import {switchToChannel} from "../router";
socket.on("msg:special", function (data) {
const channel = store.getters.findChannel(data.chan);
channel.channel.data = data.data;
switchToChannel(channel.channel);
const netChan = store.getters.findChannel(data.chan);
// @ts-ignore
netChan.channel.data = data.data;
// @ts-ignore
switchToChannel(netChan.channel);
});

View file

@ -3,15 +3,16 @@ import {store} from "../store";
socket.on("mute:changed", (response) => {
const {target, status} = response;
const {channel, network} = store.getters.findChannel(target);
if (channel.type === "lobby") {
for (const chan of network.channels) {
const netChan = store.getters.findChannel(target);
if (netChan?.channel.type === "lobby") {
for (const chan of netChan.network.channels) {
if (chan.type !== "special") {
chan.muted = status;
}
}
} else {
channel.muted = status;
} else if (netChan) {
netChan.channel.muted = status;
}
});

View file

@ -2,9 +2,9 @@ import socket from "../socket";
import {store} from "../store";
socket.on("names", function (data) {
const channel = store.getters.findChannel(data.id);
const netChan = store.getters.findChannel(data.id);
if (channel) {
channel.channel.users = data.users;
if (netChan) {
netChan.channel.users = data.users;
}
});

View file

@ -19,7 +19,7 @@ socket.on("network:options", function (data) {
const network = store.getters.findNetwork(data.network);
if (network) {
network.serverOptions = data.serverOptions;
network.serverOptions = data.serverOptions as typeof network.serverOptions;
}
});
@ -63,5 +63,8 @@ socket.on("network:info", function (data) {
socket.on("network:name", function (data) {
const network = store.getters.findNetwork(data.uuid);
network.name = network.channels[0].name = data.name;
if (network) {
network.name = network.channels[0].name = data.name;
}
});

View file

@ -2,7 +2,7 @@ import socket from "../socket";
import {store} from "../store";
import {switchToChannel} from "../router";
socket.on("part", function (data) {
socket.on("part", async function (data) {
// When parting from the active channel/query, jump to the network's lobby
if (store.state.activeChannel && store.state.activeChannel.channel.id === data.chan) {
switchToChannel(store.state.activeChannel.network.channels[0]);
@ -19,5 +19,5 @@ socket.on("part", function (data) {
1
);
store.dispatch("partChannel", channel);
await store.dispatch("partChannel", channel);
});

View file

@ -6,7 +6,10 @@ socket.on("sync_sort", function (data) {
switch (data.type) {
case "networks":
store.commit("sortNetworks", (a, b) => order.indexOf(a.uuid) - order.indexOf(b.uuid));
store.commit(
"sortNetworks",
(a, b) => (order as string[]).indexOf(a.uuid) - (order as string[]).indexOf(b.uuid)
);
break;
@ -17,7 +20,9 @@ socket.on("sync_sort", function (data) {
return;
}
network.channels.sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
network.channels.sort(
(a, b) => (order as number[]).indexOf(a.id) - (order as number[]).indexOf(b.id)
);
break;
}

View file

@ -131,7 +131,7 @@ type Getters = {
network: ClientNetwork;
channel: ClientChan;
} | null;
findNetwork: (state: State) => (uuid: string) => any;
findNetwork: (state: State) => (uuid: string) => ClientNetwork | null;
highlightCount(state: State): number;
title(state: State, getters: Omit<Getters, "title">): string;
initChannel: () => (channel: InitClientChan) => ClientChan;

View file

@ -200,7 +200,7 @@ class Uploader {
}, file.type);
};
img.src = fileReader.result as string;
img.src = String(fileReader.result);
};
fileReader.readAsDataURL(file);

View file

@ -76,7 +76,7 @@ VueApp.config.errorHandler = function (e) {
if (e instanceof Error) {
store.commit("currentUserVisibleError", `Vue error: ${e.message}`);
} else {
store.commit("currentUserVisibleError", `Vue error: ${e as string}`);
store.commit("currentUserVisibleError", `Vue error: ${String(e)}`);
}
// eslint-disable-next-line no-console

View file

@ -95,6 +95,7 @@ function generate() {
// Set notAfter 100 years into the future just in case
// the server actually validates this field
cert.validity.notAfter = new Date();
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 100);
const attrs = [

View file

@ -98,7 +98,7 @@ const input: PluginInputHandler = function (network, chan, cmd, args) {
targetGroup = parsedTarget.target_group;
}
const channel = network.getChannel(targetName);
const channel = network.getChannel(String(targetName));
if (typeof channel !== "undefined") {
network.irc.emit("privmsg", {

View file

@ -118,7 +118,7 @@ export default <IrcEventHandler>function (irc, network) {
client,
new Msg({
type: MessageType.ERROR,
text: `Connection closed unexpectedly: ${error}`,
text: `Connection closed unexpectedly: ${String(error)}`,
}),
true
);

View file

@ -143,7 +143,7 @@ declare module "irc-framework" {
use(a: any): any;
connect(connect_options?: Object): void;
connect(connect_options?: Record<string, unknown>): void;
/**
* Proxy the command handler events onto the client object, with some added sugar
@ -291,7 +291,7 @@ declare module "irc-framework" {
reply(e: any): any;
tags: Object;
tags: Record<string, unknown>;
// any
time?: any;

View file

@ -1,8 +1,11 @@
import {ClientMessage, ClientNetwork} from "../../client/js/types";
import {ClientMessage, ClientNetwork, InitClientChan} from "../../client/js/types";
import {Mention} from "../client";
import {ChanState} from "../models/chan";
import Msg from "../models/msg";
import Network from "../models/network";
import User from "../models/user";
import {ChangelogData} from "../plugins/changelog";
import {LinkPreview} from "../plugins/irc-events/link";
import {ClientConfiguration} from "../server";
type Session = {
@ -24,6 +27,8 @@ interface ServerToClientEvents {
changelog: (data: ChangelogData) => void;
"changelog:newversion": () => void;
"channel:state": (data: {chan: number; state: ChanState}) => void;
"change-password": ({success, error}: {success: boolean; error?: any}) => void;
commands: (data: string[]) => void;
@ -40,6 +45,44 @@ interface ServerToClientEvents {
"setting:new": ({name: string, value: any}) => void;
"setting:all": (settings: {[key: string]: any}) => void;
"history:clear": ({target}: {target: number}) => void;
"mute:changed": (response: {target: number; status: boolean}) => void;
names: (data: {id: number; users: User[]}) => void;
network: (data: {networks: ClientNetwork[]}) => void;
"network:options": (data: {network: string; serverOptions: {[key: string]: any}}) => void;
"network:status": (data: {network: string; connected: boolean; secure: boolean}) => void;
"network:info": (data: {uuid: string}) => void;
"network:name": (data: {uuid: string; name: string}) => void;
nick: (data: {network: string; nick: string}) => void;
open: (id: number) => void;
part: (data: {chan: number}) => void;
"sign-out": () => void;
sync_sort: (
data:
| {
type: "networks";
order: string[];
target: string;
}
| {
type: "channels";
order: number[];
target: string;
}
) => void;
topic: (data: {chan: number; topic: string}) => void;
users: (data: {chan: number}) => void;
more: ({
chan,
messages,
@ -50,7 +93,9 @@ interface ServerToClientEvents {
totalMessages: number;
}) => void;
"msg:preview": ({id, chan, preview}: {id: number; chan: number; preview: string}) => void;
"msg:preview": ({id, chan, preview}: {id: number; chan: number; preview: LinkPreview}) => void;
"msg:special": (data: {chan: number}) => void;
msg: (data: {msg: ClientMessage; chan: number; highlight?: number; unread?: number}) => void;
init: ({
active,
@ -64,11 +109,35 @@ interface ServerToClientEvents {
"search:results": (response: {results: ClientMessage[]}) => void;
quit: ({network}: {network: string}) => void;
quit: (args: {network: string}) => void;
error: (error: any) => void;
connecting: () => void;
join: (args: {
shouldOpen: boolean;
index: number;
network: string;
chan: InitClientChan;
}) => void;
}
interface ClientToServerEvents {
"auth:perform": ({user: string, password: string}) => void;
"auth:perform":
| (({user, password}: {user: string; password: string}) => void)
| (({
user,
token,
lastMessage,
openChannel,
hasConfig,
}: {
user: string;
token: string;
lastMessage: number;
openChannel: number | null;
hasConfig: boolean;
}) => void);
changelog: () => void;
@ -87,9 +156,7 @@ interface ClientToServerEvents {
"upload:auth": () => void;
"upload:ping": (token: string) => void;
"history:clear": ({target}: {target: number}) => void;
"mute:change": ({target, setMutedTo}: {target: number; setMutedTo: boolean}) => void;
"mute:change": (response: {target: number; setMutedTo: boolean}) => void;
"push:register": (subscriptionJson: PushSubscriptionJSON) => void;
"push:unregister": () => void;
@ -133,6 +200,8 @@ interface ClientToServerEvents {
"sign-out": (token?: string) => void;
"history:clear": ({target}: {target: number}) => void;
search: ({
networkUuid,
channelName,

View file

@ -3,6 +3,6 @@
"host": "irc.example.com",
"port": 7000,
"duration": 3600,
"expires": 1654034491040
"expires": 1654037133192
}
]

View file

@ -18,7 +18,7 @@ const primaryKey = "uid";
const serverPort = 1389;
function normalizeDN(dn: string) {
return ldap.parseDN(dn).toString() as string;
return String(ldap.parseDN(dn).toString());
}
function startLdapServer(callback) {