Skip to content

Commit

Permalink
untangle client and server
Browse files Browse the repository at this point in the history
Our project was quite confused as to the boundaries between client and
server code.
This false sharing meant that it was quite hard to tell what was actually
sent to the client and what was uniquely scoped to either side.

Further, this meant that our compilation and build pipelines were very
confused and pulled in files they should not have.

This commit series tries to untangle the two. This also entails fixing
quite some typing issues.
It's hard to make this in sane, small, commits that still build at each
step (it's impossible, as fixing one type error / any type immediately lead
to further errors in a game of whack a mole).
So you'll get my actual progress in small commits that can each be reviewed,
however the earlier ones are in fact sometimes wrong and get cleaned up later
once the picture is a bit clearer.
  • Loading branch information
brunnre8 committed Apr 26, 2024
2 parents 549c445 + 8eb398c commit f792626
Show file tree
Hide file tree
Showing 101 changed files with 1,365 additions and 1,123 deletions.
4 changes: 2 additions & 2 deletions client/components/ChatUserList.vue
Expand Up @@ -59,7 +59,7 @@
<script lang="ts">
import {filter as fuzzyFilter} from "fuzzy";
import {computed, defineComponent, nextTick, PropType, ref} from "vue";
import type {UserInMessage} from "../../server/models/msg";
import type {UserInMessage} from "../../shared/types/msg";
import type {ClientChan, ClientUser} from "../js/types";
import Username from "./Username.vue";
Expand Down Expand Up @@ -104,7 +104,7 @@ export default defineComponent({
const result = filteredUsers.value;
for (const user of result) {
const mode = user.original.modes[0] || "";
const mode: string = user.original.modes[0] || "";
if (!groups[mode]) {
groups[mode] = [];
Expand Down
8 changes: 4 additions & 4 deletions client/components/ImageViewer.vue
Expand Up @@ -41,9 +41,9 @@
<script lang="ts">
import Mousetrap from "mousetrap";
import {computed, defineComponent, ref, watch} from "vue";
import {onBeforeRouteLeave, onBeforeRouteUpdate} from "vue-router";
import eventbus from "../js/eventbus";
import {ClientChan, ClientMessage, ClientLinkPreview} from "../js/types";
import {ClientChan, ClientLinkPreview} from "../js/types";
import {SharedMsg} from "../../shared/types/msg";
export default defineComponent({
name: "ImageViewer",
Expand Down Expand Up @@ -104,9 +104,9 @@ export default defineComponent({
}
const links = channel.value.messages
.map((msg) => msg.previews)
.map((msg: SharedMsg) => msg.previews)
.flat()
.filter((preview) => preview.thumb);
.filter((preview) => preview && preview.thumb);
const currentIndex = links.indexOf(link.value);
Expand Down
6 changes: 5 additions & 1 deletion client/components/Message.vue
Expand Up @@ -150,10 +150,14 @@ export default defineComponent({
});
const messageComponent = computed(() => {
return "message-" + props.message.type;
return "message-" + (props.message.type || "invalid"); // TODO: force existence of type in sharedmsg
});
const isAction = () => {
if (!props.message.type) {
return false;
}
return typeof MessageTypes["message-" + props.message.type] !== "undefined";
};
Expand Down
6 changes: 3 additions & 3 deletions client/components/MessageList.vue
Expand Up @@ -79,7 +79,7 @@ import {
} from "vue";
import {useStore} from "../js/store";
import {ClientChan, ClientMessage, ClientNetwork, ClientLinkPreview} from "../js/types";
import Msg from "../../server/models/msg";
import {SharedMsg} from "../../shared/types/msg";
type CondensedMessageContainer = {
type: "condensed";
Expand Down Expand Up @@ -242,7 +242,7 @@ export default defineComponent({
});
const shouldDisplayDateMarker = (
message: Msg | ClientMessage | CondensedMessageContainer,
message: SharedMsg | ClientMessage | CondensedMessageContainer,
id: number
) => {
const previousMessage = condensedMessages.value[id - 1];
Expand Down Expand Up @@ -270,7 +270,7 @@ export default defineComponent({
return false;
};
const isPreviousSource = (currentMessage: ClientMessage | Msg, id: number) => {
const isPreviousSource = (currentMessage: ClientMessage | SharedMsg, id: number) => {
const previousMessage = condensedMessages.value[id - 1];
return !!(
previousMessage &&
Expand Down
29 changes: 18 additions & 11 deletions client/components/MessageTypes/error.vue
Expand Up @@ -26,36 +26,43 @@ export default defineComponent({
},
setup(props) {
const errorMessage = computed(() => {
// TODO: enforce chan and nick fields so that we can get rid of that
const chan = props.message.channel || "!UNKNOWN_CHAN";
const nick = props.message.nick || "!UNKNOWN_NICK";
switch (props.message.error) {
case "bad_channel_key":
return `Cannot join ${props.message.channel} - Bad channel key.`;
return `Cannot join ${chan} - Bad channel key.`;
case "banned_from_channel":
return `Cannot join ${props.message.channel} - You have been banned from the channel.`;
return `Cannot join ${chan} - You have been banned from the channel.`;
case "cannot_send_to_channel":
return `Cannot send to channel ${props.message.channel}`;
return `Cannot send to channel ${chan}`;
case "channel_is_full":
return `Cannot join ${props.message.channel} - Channel is full.`;
return `Cannot join ${chan} - Channel is full.`;
case "chanop_privs_needed":
return "Cannot perform action: You're not a channel operator.";
case "invite_only_channel":
return `Cannot join ${props.message.channel} - Channel is invite only.`;
return `Cannot join ${chan} - Channel is invite only.`;
case "no_such_nick":
return `User ${props.message.nick} hasn't logged in or does not exist.`;
return `User ${nick} hasn't logged in or does not exist.`;
case "not_on_channel":
return "Cannot perform action: You're not on the channel.";
case "password_mismatch":
return "Password mismatch.";
case "too_many_channels":
return `Cannot join ${props.message.channel} - You've already reached the maximum number of channels allowed.`;
return `Cannot join ${chan} - You've already reached the maximum number of channels allowed.`;
case "unknown_command":
return `Unknown command: ${props.message.command}`;
// TODO: not having message.command should never happen, so force existence
return `Unknown command: ${props.message.command || "!UNDEFINED_COMMAND_BUG"}`;
case "user_not_in_channel":
return `User ${props.message.nick} is not on the channel.`;
return `User ${nick} is not on the channel.`;
case "user_on_channel":
return `User ${props.message.nick} is already on the channel.`;
return `User ${nick} is already on the channel.`;
default:
if (props.message.reason) {
return `${props.message.reason} (${props.message.error})`;
return `${props.message.reason} (${
props.message.error || "!UNDEFINED_ERR"
})`;
}
return props.message.error;
Expand Down
2 changes: 2 additions & 0 deletions client/components/NetworkForm.vue
Expand Up @@ -498,6 +498,7 @@ export default defineComponent({
};
watch(
// eslint-disable-next-line
() => props.defaults?.commands,
() => {
void nextTick(() => {
Expand All @@ -507,6 +508,7 @@ export default defineComponent({
);
watch(
// eslint-disable-next-line
() => props.defaults?.tls,
(isSecureChecked) => {
const ports = [6667, 6697];
Expand Down
8 changes: 3 additions & 5 deletions client/components/NetworkList.vue
Expand Up @@ -309,8 +309,7 @@ export default defineComponent({
moveItemInArray(store.state.networks, oldIndex, newIndex);
socket.emit("sort", {
type: "networks",
socket.emit("sort:networks", {
order: store.state.networks.map((n) => n.uuid),
});
};
Expand Down Expand Up @@ -341,9 +340,8 @@ export default defineComponent({
moveItemInArray(netChan.network.channels, oldIndex, newIndex);
socket.emit("sort", {
type: "channels",
target: netChan.network.uuid,
socket.emit("sort:channel", {
network: netChan.network.uuid,
order: netChan.network.channels.map((c) => c.id),
});
};
Expand Down
4 changes: 2 additions & 2 deletions client/components/Username.vue
Expand Up @@ -12,10 +12,10 @@

<script lang="ts">
import {computed, defineComponent, PropType} from "vue";
import {UserInMessage} from "../../server/models/msg";
import {UserInMessage} from "../../shared/types/msg";
import eventbus from "../js/eventbus";
import colorClass from "../js/helpers/colorClass";
import type {ClientChan, ClientNetwork, ClientUser} from "../js/types";
import type {ClientChan, ClientNetwork} from "../js/types";
import {useStore} from "../js/store";
type UsernameUser = Partial<UserInMessage> & {
Expand Down
2 changes: 1 addition & 1 deletion client/components/Windows/SearchResults.vue
Expand Up @@ -106,7 +106,7 @@ import type {ClientMessage} from "../../js/types";
import {useStore} from "../../js/store";
import {useRoute, useRouter} from "vue-router";
import {switchToChannel} from "../../js/router";
import {SearchQuery} from "../../../server/plugins/messageStorage/types";
import {SearchQuery} from "../../../shared/types/storage";
export default defineComponent({
name: "SearchResults",
Expand Down
35 changes: 35 additions & 0 deletions client/js/chan.ts
@@ -0,0 +1,35 @@
import {ClientChan, ClientMessage} from "./types";
import {SharedNetworkChan} from "../../shared/types/network";
import {SharedMsg} from "../../shared/types/msg";

export function toClientChan(shared: SharedNetworkChan): ClientChan {
const history: string[] = [""].concat(
shared.messages
.filter((m) => m.self && m.text && m.type === "message")
// TS is too stupid to see the nil guard on filter... so we monkey patch it
.map((m): string => (m.text ? m.text : ""))
.reverse()
.slice(0, 99)
);
// filter the unused vars
const {messages, totalMessages: _, ...props} = shared;
const channel: ClientChan = {
...props,
editTopic: false,
pendingMessage: "",
inputHistoryPosition: 0,
historyLoading: false,
scrolledToBottom: true,
users: [],
usersOutdated: shared.type === "channel" ? true : false,
moreHistoryAvailable: shared.totalMessages > shared.messages.length,
inputHistory: history,
messages: sharedMsgToClientMsg(messages),
};
return channel;
}

function sharedMsgToClientMsg(shared: SharedMsg[]): ClientMessage[] {
// TODO: this is a stub for now, we will want to populate client specific stuff here
return shared;
}
2 changes: 1 addition & 1 deletion client/js/commands/collapse.ts
Expand Up @@ -11,7 +11,7 @@ function input() {
for (const message of store.state.activeChannel.channel.messages) {
let toggled = false;

for (const preview of message.previews) {
for (const preview of message.previews || []) {
if (preview.shown) {
preview.shown = false;
toggled = true;
Expand Down
2 changes: 1 addition & 1 deletion client/js/commands/expand.ts
Expand Up @@ -11,7 +11,7 @@ function input() {
for (const message of store.state.activeChannel.channel.messages) {
let toggled = false;

for (const preview of message.previews) {
for (const preview of message.previews || []) {
if (!preview.shown) {
preview.shown = true;
toggled = true;
Expand Down

0 comments on commit f792626

Please sign in to comment.