Skip to content

Commit 51c1f1c

Browse files
committed
Use IRC client's reconnect feature and emitted events
- Switch User model nicks from `string[]` to `Set<string>` - Share connection status and reconnection info from IRC client
1 parent c77f938 commit 51c1f1c

6 files changed

Lines changed: 62 additions & 23 deletions

File tree

src/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<BApp>
3-
<h1>You are {{ irc.isConnected ? 'connected' : 'not connected' }}</h1>
3+
<h1>Connection status: {{ irc.connectionStatus }}</h1>
44

55
<ChatApp v-if="irc.isConnected" />
66
<LoginForm v-else @login="irc.signIn" />

src/models/connection-status.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnect failed';
2+
export interface ReconnectionStatus {
3+
isReconnecting: boolean;
4+
retryCount: number;
5+
maxRetryCount: number;
6+
}

src/models/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './ban';
22
export * from './ban-status';
33
export * from './channel';
4+
export * from './connection-status';
45
export * from './message';
56
export * from './user';

src/models/user.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ export interface User {
22
username: string;
33
/** User ID */
44
uid: string;
5-
nicks: string[];
5+
/** Tracks multiple opened clients for the same user */
6+
nicks: Set<string>;
67
away: boolean;
78
awayReason: string;
89
}

src/stores/irc.ts

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import type { User } from '#models';
1+
import type { ConnectionStatus, ReconnectionStatus, User } from '#models';
22
import { createNick } from '#utils';
3-
import { useLocalStorage } from '@vueuse/core';
3+
import { useCountdown, useLocalStorage } from '@vueuse/core';
44
import { Client } from 'irc-framework';
55
import Connection from 'irc-framework/src/transports/websocket';
66
import log from 'loglevel';
77
import { defineStore } from 'pinia';
8-
import { computed, markRaw, ref, shallowRef } from 'vue';
8+
import { computed, markRaw, reactive, readonly, ref, shallowRef } from 'vue';
99

1010
export interface InitClientConfig {
1111
username: string;
@@ -22,15 +22,22 @@ const useIrcStore = defineStore('irc', () => {
2222
const client = shallowRef<Client | null>(null);
2323
const savedUser = useLocalStorage<Record<'username' | 'uid', string> | null>('chat_user', null);
2424

25-
const currentUser = ref<User>({
25+
const currentUser = reactive<User>({
2626
username: '',
2727
uid: '',
2828
away: false,
2929
awayReason: '',
30-
nicks: [],
30+
nicks: new Set<string>(),
3131
});
3232
const currentNick = ref('');
3333
const isRegistered = ref(false);
34+
const connectionStatus = ref<ConnectionStatus>('disconnected');
35+
const reconnectCountdown = useCountdown(0);
36+
const reconnectStatus = reactive<ReconnectionStatus>({
37+
isReconnecting: false,
38+
retryCount: 0,
39+
maxRetryCount: 0,
40+
});
3441

3542
function initClient(username: string, uid: string) {
3643
if (client.value) {
@@ -39,9 +46,9 @@ const useIrcStore = defineStore('irc', () => {
3946

4047
const nick = createNick(username);
4148
currentNick.value = nick;
42-
currentUser.value.nicks.push(nick);
43-
currentUser.value.username = username;
44-
currentUser.value.uid = uid;
49+
currentUser.nicks.add(nick);
50+
currentUser.username = username;
51+
currentUser.uid = uid;
4552

4653
const ircClient = new Client({
4754
host: import.meta.env.VITE_APP_SERVER_URL!,
@@ -53,16 +60,33 @@ const useIrcStore = defineStore('irc', () => {
5360
})
5461
.on('nick in use', (event) => {
5562
// Remove used nick
56-
currentUser.value.nicks.splice(currentUser.value.nicks.indexOf(event.nick));
63+
currentUser.nicks.delete(event.nick);
5764
currentNick.value = '';
5865

5966
// Retry connection with new nickname
6067
quit();
6168
initClient(username, uid);
6269
})
70+
.on('connecting', () => {
71+
connectionStatus.value = 'connecting';
72+
})
6373
.on('registered', () => {
6474
isRegistered.value = true;
65-
console.log(ircClient);
75+
})
76+
.on('connected', () => {
77+
connectionStatus.value = 'connected';
78+
reconnectStatus.isReconnecting = false;
79+
reconnectCountdown.stop();
80+
})
81+
.on('reconnecting', (event) => {
82+
reconnectStatus.isReconnecting = true;
83+
reconnectStatus.retryCount = event.attempt;
84+
reconnectStatus.maxRetryCount = event.max_retries;
85+
reconnectCountdown.start(event.wait / 1_000);
86+
})
87+
.on('close', () => {
88+
connectionStatus.value = 'reconnect failed';
89+
reconnectStatus.isReconnecting = false;
6690
})
6791
.on('debug', (message) => {
6892
log.debug(message);
@@ -73,6 +97,7 @@ const useIrcStore = defineStore('irc', () => {
7397

7498
ircClient.connect();
7599
client.value = markRaw(ircClient);
100+
console.log('IRC Client:', ircClient);
76101
}
77102

78103
/** Sign in with saved login (if remembered) */
@@ -89,22 +114,27 @@ const useIrcStore = defineStore('irc', () => {
89114
initClient(login.username, login.uid);
90115
}
91116

92-
function signOut() {
93-
savedUser.value = null;
94-
quit();
95-
}
96-
97117
function quit() {
98118
isRegistered.value = false;
119+
connectionStatus.value = 'disconnected';
99120
client.value?.quit();
100121
client.value = null;
101122
}
102123

124+
function signOut() {
125+
savedUser.value = null;
126+
quit();
127+
}
128+
103129
return {
104130
client: computed(() => (isRegistered.value ? client.value : null)),
105-
isConnected: computed(() => isRegistered.value && client.value !== null),
106-
currentUser: computed(() => currentUser.value),
107-
initClient,
131+
isConnected: computed(
132+
() => isRegistered.value && client.value !== null && connectionStatus.value === 'connected',
133+
),
134+
connectionStatus: readonly(connectionStatus),
135+
reconnectStatus: readonly(reconnectStatus),
136+
reconnectCountdown: readonly(reconnectCountdown.remaining),
137+
currentUser: readonly(currentUser),
108138
quit,
109139
autoSignIn,
110140
signIn,

src/stores/user-list.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ const useUserListStore = defineStore('userList', () => {
1414
function addUser(nick: string, uid: string) {
1515
const username = parseNick(nick);
1616
if (connectedUsers.has(username)) {
17+
connectedUsers.get(username)?.nicks.add(nick);
1718
return;
1819
}
1920

2021
connectedUsers.set(username, {
2122
username,
2223
uid,
23-
nicks: [nick],
24+
nicks: new Set([nick]),
2425
away: false,
2526
awayReason: '',
2627
});
@@ -34,8 +35,8 @@ const useUserListStore = defineStore('userList', () => {
3435
return;
3536
}
3637

37-
user.nicks = user.nicks.filter((n) => n !== nick);
38-
if (user.nicks.length === 0) {
38+
user.nicks.delete(nick);
39+
if (user.nicks.size === 0) {
3940
connectedUsers.delete(username);
4041
}
4142
}

0 commit comments

Comments
 (0)