diff --git a/src/discord/core/client.ts b/src/discord/core/client.ts index b2d899b..8dcefd4 100644 --- a/src/discord/core/client.ts +++ b/src/discord/core/client.ts @@ -1,13 +1,18 @@ import { TypedEmitter } from 'tiny-typed-emitter'; import { WebSocket } from 'ws'; import { Gateway } from '../ws/gateway'; -import { GatewayReadyDispatchData, GatewaySocketEvent } from '../ws/types'; +import { + GatewayDispatchEvents, + GatewayReadyDispatchData, + GatewaySocketEvent, +} from '../ws/types'; import { debug, setDebugging } from './logger'; import { GuildManager } from '../managers/GuildManager'; import { ChannelManager } from '../managers/ChannelManager'; import MainGuild from '../structures/guild/MainGuild'; import MainChannel from '../structures/channel/MainChannel'; import MainUser from '../structures/user/MainUser'; +import { Message } from '../structures/Message'; export interface ClientEvents { ready: () => void; @@ -70,6 +75,15 @@ export class Client extends TypedEmitter { ); this.emit('ready'); } + + if (event.event === GatewayDispatchEvents.MessageCreate) { + const message = event.data as Message; + const channel = this.channels.cache.get(message.channel_id); + + if (channel !== undefined) { + channel.messages.push(message); + } + } this.emit('dispatch', event); }); this.guilds = new GuildManager(this); diff --git a/src/discord/structures/Message.ts b/src/discord/structures/Message.ts index 5fd14a9..bea1e6f 100644 --- a/src/discord/structures/Message.ts +++ b/src/discord/structures/Message.ts @@ -6,4 +6,5 @@ export interface Message { timestamp: string; id: Snowflake; author: IUserData; + channel_id: Snowflake; } diff --git a/src/main/app.ts b/src/main/app.ts index 7a2d56e..d82b130 100644 --- a/src/main/app.ts +++ b/src/main/app.ts @@ -4,9 +4,10 @@ import fs from 'fs'; import path from 'path'; import logger, { Logger } from '../common/log/logger'; import { Client } from '../discord/core/client'; -import { GatewaySocketEvent } from '../discord/ws/types'; -import { registerHandler, registerListener } from './ipc'; +import { GatewayDispatchEvents, GatewaySocketEvent } from '../discord/ws/types'; +import { registerHandler, registerListener, sendToRenderer } from './ipc'; import { CreateMessageOptions } from '../discord/structures/channel/BaseChannel'; +import { Message } from '../discord/structures/Message'; export default class WaveCordApp { public readonly resourcesPath: string; @@ -56,6 +57,11 @@ export default class WaveCordApp { }); this.discord.on('dispatch', (event: GatewaySocketEvent) => { logger.info('Received event: ', event.event); + + if (event.event === GatewayDispatchEvents.MessageCreate) { + const message = event.data as Message; + sendToRenderer(this.window!, 'discord:gateway:message-create', message); + } }); this.discord.login(this.token); diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 1da6500..40fbfa1 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -1,4 +1,4 @@ -import { ipcMain } from 'electron'; +import { BrowserWindow, ipcMain } from 'electron'; export type IpcChannels = | 'logger:info' @@ -18,7 +18,8 @@ export type IpcChannels = | 'discord:user' | 'discord:get-last-visited-channel' | 'discord:set-last-visited-channel' - | 'discord:create-message'; + | 'discord:create-message' + | 'discord:gateway:message-create'; export function registerHandler( channel: IpcChannels, @@ -37,3 +38,11 @@ export function registerListener( func(...args); }); } + +export function sendToRenderer( + window: BrowserWindow, + channel: IpcChannels, + ...args: any[] +) { + window.webContents.send(channel, ...args); +} diff --git a/src/main/preload.ts b/src/main/preload.ts index 583d5b7..4d1cc75 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -6,11 +6,11 @@ import { IpcChannels } from './ipc'; const electronHandler = { ipcRenderer: { - sendMessage(channel: IpcChannels, ...args: unknown[]) { + sendMessage(channel: IpcChannels, ...args: any[]) { ipcRenderer.send(channel, ...args); }, - on(channel: IpcChannels, func: (...args: unknown[]) => void) { - const subscription = (_event: IpcRendererEvent, ...args: unknown[]) => + on(channel: IpcChannels, func: (...args: any[]) => void) { + const subscription = (_event: IpcRendererEvent, ...args: any[]) => func(...args); ipcRenderer.on(channel, subscription); @@ -18,10 +18,10 @@ const electronHandler = { ipcRenderer.removeListener(channel, subscription); }; }, - once(channel: IpcChannels, func: (...args: unknown[]) => void) { + once(channel: IpcChannels, func: (...args: any[]) => void) { ipcRenderer.once(channel, (_event, ...args) => func(...args)); }, - invoke(channel: IpcChannels, ...args: unknown[]): Promise { + invoke(channel: IpcChannels, ...args: any[]): Promise { return ipcRenderer.invoke(channel, ...args); }, }, diff --git a/src/renderer/pages/Guild/Channel/index.tsx b/src/renderer/pages/Guild/Channel/index.tsx index 5b3a761..4d4719d 100644 --- a/src/renderer/pages/Guild/Channel/index.tsx +++ b/src/renderer/pages/Guild/Channel/index.tsx @@ -11,27 +11,49 @@ export default function ChannelPage() { const [channel, setChannel] = useState(null); const [messages, setMessages] = useState([]); + // Live messages useEffect(() => { + window.electron.ipcRenderer.on( + 'discord:gateway:message-create', + (msg: Message) => { + if (msg.channel_id !== channelId) return; + + setMessages([msg, ...messages]); + }, + ); + }, [channel, channelId, messages]); + + // Channel loading / Page loading + useEffect(() => { + const loadChannel = () => { + window.electron.ipcRenderer + .invoke('discord:load-channel', channelId) + .then(async (data: IChannelData) => { + if (data.id !== channelId) return false; + + const chn = new RendererChannel(data); + const msgs = await chn.fetchMessages(); + setChannel(chn); + setMessages(msgs); + return true; + }) + .catch((err) => console.error(err)); + }; + + if (channel !== null) { + if (channel.id !== channelId) { + loadChannel(); + } + return; + } + const messageList = document.getElementById('channel_page_message_list'); if (messageList) { messageList.scrollTop = messageList.scrollHeight; } - window.electron.ipcRenderer - .invoke('discord:load-channel', channelId) - .then(async (data: IChannelData) => { - const chn = new RendererChannel(data); - const msgs = await chn.fetchMessages(); - setChannel(chn); - setMessages(msgs); - return true; - }) - .catch((err) => console.error(err)); - - return () => { - setMessages([]); - }; - }, [channelId]); + loadChannel(); + }, [channel, channelId]); if (channelId.length === 0 || channel === null) return null;