mirror of
https://github.com/thelounge/thelounge.git
synced 2024-06-04 06:42:36 +02:00
socket-events: fix up init
This commit is contained in:
parent
0660a8772c
commit
9ab9ad0f56
|
@ -12,7 +12,7 @@ export function toClientChan(shared: SharedNetworkChan): ClientChan {
|
||||||
.slice(0, 99)
|
.slice(0, 99)
|
||||||
);
|
);
|
||||||
// filter the unused vars
|
// filter the unused vars
|
||||||
const {messages, totalMessages: __, ...props} = shared;
|
const {messages, totalMessages: _, ...props} = shared;
|
||||||
const channel: ClientChan = {
|
const channel: ClientChan = {
|
||||||
...props,
|
...props,
|
||||||
editTopic: false,
|
editTopic: false,
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import socket from "../socket";
|
import socket from "../socket";
|
||||||
import storage from "../localStorage";
|
import storage from "../localStorage";
|
||||||
|
import {toClientChan} from "../chan";
|
||||||
import {router, switchToChannel, navigate} from "../router";
|
import {router, switchToChannel, navigate} from "../router";
|
||||||
import {store} from "../store";
|
import {store} from "../store";
|
||||||
import parseIrcUri from "../helpers/parseIrcUri";
|
import parseIrcUri from "../helpers/parseIrcUri";
|
||||||
import {ClientNetwork, InitClientChan} from "../types";
|
import {ClientNetwork, ClientChan} from "../types";
|
||||||
|
import {SharedNetwork, SharedNetworkChan} from "../../../shared/types/network";
|
||||||
|
|
||||||
socket.on("init", async function (data) {
|
socket.on("init", async function (data) {
|
||||||
store.commit("networks", mergeNetworkData(data.networks));
|
store.commit("networks", mergeNetworkData(data.networks));
|
||||||
|
@ -30,54 +32,54 @@ socket.on("init", async function (data) {
|
||||||
window.g_TheLoungeRemoveLoading();
|
window.g_TheLoungeRemoveLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handledQuery = await handleQueryParams();
|
if (await handleQueryParams()) {
|
||||||
|
// If we handled query parameters like irc:// links or just general
|
||||||
|
// connect parameters in public mode, then nothing to do here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we handled query parameters like irc:// links or just general
|
// If we are on an unknown route or still on SignIn component
|
||||||
// connect parameters in public mode, then nothing to do here
|
// then we can open last known channel on server, or Connect window if none
|
||||||
if (!handledQuery) {
|
if (!router.currentRoute?.value?.name || router.currentRoute?.value?.name === "SignIn") {
|
||||||
// If we are on an unknown route or still on SignIn component
|
const channel = store.getters.findChannel(data.active);
|
||||||
// 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) {
|
if (channel) {
|
||||||
switchToChannel(channel.channel);
|
switchToChannel(channel.channel);
|
||||||
} else if (store.state.networks.length > 0) {
|
} else if (store.state.networks.length > 0) {
|
||||||
// Server is telling us to open a channel that does not exist
|
// 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
|
// For example, it can be unset if you first open the page after server start
|
||||||
switchToChannel(store.state.networks[0].channels[0]);
|
switchToChannel(store.state.networks[0].channels[0]);
|
||||||
} else {
|
} else {
|
||||||
await navigate("Connect");
|
await navigate("Connect");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function mergeNetworkData(newNetworks: ClientNetwork[]) {
|
function mergeNetworkData(newNetworks: SharedNetwork[]): ClientNetwork[] {
|
||||||
const stored = storage.get("thelounge.networks.collapsed");
|
const stored = storage.get("thelounge.networks.collapsed");
|
||||||
const collapsedNetworks = stored ? new Set(JSON.parse(stored)) : new Set();
|
const collapsedNetworks = stored ? new Set(JSON.parse(stored)) : new Set();
|
||||||
|
const result: ReturnType<typeof mergeNetworkData> = [];
|
||||||
|
|
||||||
for (let n = 0; n < newNetworks.length; n++) {
|
for (const sharedNet of newNetworks) {
|
||||||
const network = newNetworks[n];
|
const currentNetwork = store.getters.findNetwork(sharedNet.uuid);
|
||||||
const currentNetwork = store.getters.findNetwork(network.uuid);
|
|
||||||
|
|
||||||
// If this network is new, set some default variables and initalize channel variables
|
// If this network is new, set some default variables and initalize channel variables
|
||||||
if (!currentNetwork) {
|
if (!currentNetwork) {
|
||||||
network.isJoinChannelShown = false;
|
const newNet: ClientNetwork = {
|
||||||
network.isCollapsed = collapsedNetworks.has(network.uuid);
|
...sharedNet,
|
||||||
network.channels.forEach(store.getters.initChannel);
|
channels: sharedNet.channels.map(toClientChan),
|
||||||
|
isJoinChannelShown: false,
|
||||||
|
isCollapsed: collapsedNetworks.has(sharedNet.uuid),
|
||||||
|
};
|
||||||
|
result.push(newNet);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge received network object into existing network object on the client
|
// Merge received network object into existing network object on the client
|
||||||
// so the object reference stays the same (e.g. for currentChannel state)
|
// so the object reference stays the same (e.g. for currentChannel state)
|
||||||
for (const key in network) {
|
for (const key in sharedNet) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(network, key)) {
|
if (!Object.prototype.hasOwnProperty.call(sharedNet, key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,81 +87,82 @@ function mergeNetworkData(newNetworks: ClientNetwork[]) {
|
||||||
if (key === "channels") {
|
if (key === "channels") {
|
||||||
currentNetwork.channels = mergeChannelData(
|
currentNetwork.channels = mergeChannelData(
|
||||||
currentNetwork.channels,
|
currentNetwork.channels,
|
||||||
network.channels as InitClientChan[]
|
sharedNet.channels
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
currentNetwork[key] = network[key];
|
currentNetwork[key] = sharedNet[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newNetworks[n] = currentNetwork;
|
result.push(currentNetwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newNetworks;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeChannelData(oldChannels: InitClientChan[], newChannels: InitClientChan[]) {
|
function mergeChannelData(
|
||||||
for (let c = 0; c < newChannels.length; c++) {
|
oldChannels: ClientChan[],
|
||||||
const channel = newChannels[c];
|
newChannels: SharedNetworkChan[]
|
||||||
const currentChannel = oldChannels.find((chan) => chan.id === channel.id);
|
): ClientChan[] {
|
||||||
|
const result: ReturnType<typeof mergeChannelData> = [];
|
||||||
|
|
||||||
|
for (const newChannel of newChannels) {
|
||||||
|
const currentChannel = oldChannels.find((chan) => chan.id === newChannel.id);
|
||||||
|
|
||||||
// This is a new channel that was joined while client was disconnected, initialize it
|
|
||||||
if (!currentChannel) {
|
if (!currentChannel) {
|
||||||
store.getters.initChannel(channel);
|
// This is a new channel that was joined while client was disconnected, initialize it
|
||||||
|
const current = toClientChan(newChannel);
|
||||||
|
result.push(current);
|
||||||
|
emitNamesOrMarkUsersOudated(current); // TODO: this should not carry logic like that
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge received channel object into existing currentChannel
|
// Merge received channel object into existing currentChannel
|
||||||
// so the object references are exactly the same (e.g. in store.state.activeChannel)
|
// so the object references are exactly the same (e.g. in store.state.activeChannel)
|
||||||
for (const key in channel) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(channel, key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server sends an empty users array, client requests it whenever needed
|
emitNamesOrMarkUsersOudated(currentChannel); // TODO: this should not carry logic like that
|
||||||
if (key === "users") {
|
|
||||||
if (channel.type === "channel") {
|
|
||||||
if (
|
|
||||||
store.state.activeChannel &&
|
|
||||||
store.state.activeChannel.channel === currentChannel
|
|
||||||
) {
|
|
||||||
// For currently open channel, request the user list straight away
|
|
||||||
socket.emit("names", {
|
|
||||||
target: channel.id,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// For all other channels, mark the user list as outdated
|
|
||||||
// so an update will be requested whenever user switches to these channels
|
|
||||||
currentChannel.usersOutdated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
// Reconnection only sends new messages, so merge it on the client
|
||||||
}
|
// Only concat if server sent us less than 100 messages so we don't introduce gaps
|
||||||
|
if (currentChannel.messages && newChannel.messages.length < 100) {
|
||||||
// Server sends total count of messages in memory, we compare it to amount of messages
|
currentChannel.messages = currentChannel.messages.concat(newChannel.messages);
|
||||||
// on the client, and decide whether theres more messages to load from server
|
} else {
|
||||||
if (key === "totalMessages") {
|
currentChannel.messages = newChannel.messages;
|
||||||
currentChannel.moreHistoryAvailable =
|
|
||||||
channel.totalMessages! > currentChannel.messages.length;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconnection only sends new messages, so merge it on the client
|
|
||||||
// Only concat if server sent us less than 100 messages so we don't introduce gaps
|
|
||||||
if (key === "messages" && currentChannel.messages && channel.messages.length < 100) {
|
|
||||||
currentChannel.messages = currentChannel.messages.concat(channel.messages);
|
|
||||||
} else {
|
|
||||||
currentChannel[key] = channel[key];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newChannels[c] = currentChannel;
|
// TODO: this is copies more than what the compiler knows about
|
||||||
|
for (const key in newChannel) {
|
||||||
|
if (!Object.hasOwn(currentChannel, key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === "messages") {
|
||||||
|
// already handled
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentChannel[key] = newChannel[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(currentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newChannels;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitNamesOrMarkUsersOudated(chan: ClientChan) {
|
||||||
|
if (store.state.activeChannel && store.state.activeChannel.channel === chan) {
|
||||||
|
// For currently open channel, request the user list straight away
|
||||||
|
socket.emit("names", {
|
||||||
|
target: chan.id,
|
||||||
|
});
|
||||||
|
chan.usersOutdated = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For all other channels, mark the user list as outdated
|
||||||
|
// so an update will be requested whenever user switches to these channels
|
||||||
|
chan.usersOutdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleQueryParams() {
|
async function handleQueryParams() {
|
||||||
|
@ -169,30 +172,28 @@ async function handleQueryParams() {
|
||||||
|
|
||||||
const params = new URLSearchParams(document.location.search);
|
const params = new URLSearchParams(document.location.search);
|
||||||
|
|
||||||
const cleanParams = () => {
|
|
||||||
// Remove query parameters from url without reloading the page
|
|
||||||
const cleanUri = window.location.origin + window.location.pathname + window.location.hash;
|
|
||||||
window.history.replaceState({}, document.title, cleanUri);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (params.has("uri")) {
|
if (params.has("uri")) {
|
||||||
// Set default connection settings from IRC protocol links
|
// Set default connection settings from IRC protocol links
|
||||||
const uri = params.get("uri");
|
const uri = params.get("uri");
|
||||||
const queryParams = parseIrcUri(String(uri));
|
const queryParams = parseIrcUri(String(uri));
|
||||||
|
removeQueryParams();
|
||||||
cleanParams();
|
|
||||||
await router.push({name: "Connect", query: queryParams});
|
await router.push({name: "Connect", query: queryParams});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (document.body.classList.contains("public") && document.location.search) {
|
}
|
||||||
|
|
||||||
|
if (document.body.classList.contains("public") && document.location.search) {
|
||||||
// Set default connection settings from url params
|
// Set default connection settings from url params
|
||||||
const queryParams = Object.fromEntries(params.entries());
|
const queryParams = Object.fromEntries(params.entries());
|
||||||
|
removeQueryParams();
|
||||||
cleanParams();
|
|
||||||
await router.push({name: "Connect", query: queryParams});
|
await router.push({name: "Connect", query: queryParams});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove query parameters from url without reloading the page
|
||||||
|
function removeQueryParams() {
|
||||||
|
const cleanUri = window.location.origin + window.location.pathname + window.location.hash;
|
||||||
|
window.history.replaceState(null, "", cleanUri);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue