Skip to content

Commit 0cbe1ec

Browse files
authored
[Tech] Type-check Backend & Frontend events (#3649)
* Typechecking for backendEvents * Typechecking for sendFrontendMessage
1 parent c62820d commit 0cbe1ec

File tree

18 files changed

+150
-67
lines changed

18 files changed

+150
-67
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
"ts-jest": "29.0.5",
143143
"ts-prune": "0.10.3",
144144
"type-fest": "3.6.1",
145+
"typed-emitter": "^2.1.0",
145146
"typescript": "4.9.4",
146147
"unimported": "1.26.0",
147148
"vite": "3.2.8",

src/backend/api/helpers.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
Runner,
44
InstallPlatform,
55
WineCommandArgs,
6-
ConnectivityChangedCallback,
76
ConnectivityStatus,
87
AppSettings,
98
GameSettings,
@@ -115,7 +114,13 @@ export const runWineCommandForGame = async (args: RunWineCommandArgs) =>
115114
ipcRenderer.invoke('runWineCommandForGame', args)
116115

117116
export const onConnectivityChanged = async (
118-
callback: ConnectivityChangedCallback
117+
callback: (
118+
event: Electron.IpcRendererEvent,
119+
status: {
120+
status: ConnectivityStatus
121+
retryIn: number
122+
}
123+
) => void
119124
) => ipcRenderer.on('connectivity-changed', callback)
120125

121126
export const getConnectivityStatus = async () =>

src/backend/api/library.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ipcRenderer } from 'electron'
22
import {
33
Runner,
4-
InstallParams,
54
LaunchParams,
65
ImportGameArgs,
76
GameStatus,
@@ -74,11 +73,15 @@ export const handleLaunchGame = (
7473
) => ipcRenderer.on('launchGame', callback)
7574

7675
export const handleInstallGame = (
77-
callback: (event: Electron.IpcRendererEvent, args: InstallParams) => void
76+
callback: (
77+
event: Electron.IpcRendererEvent,
78+
appName: string,
79+
runner: Runner
80+
) => void
7881
) => ipcRenderer.on('installGame', callback)
7982

8083
export const handleRefreshLibrary = (
81-
callback: (event: Electron.IpcRendererEvent, runner: Runner) => void
84+
callback: (event: Electron.IpcRendererEvent, runner?: Runner) => void
8285
) => ipcRenderer.on('refreshLibrary', callback)
8386

8487
export const handleGamePush = (

src/backend/api/misc.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ export const pathExists = async (path: string) =>
127127
export const processShortcut = async (combination: string) =>
128128
ipcRenderer.send('processShortcut', combination)
129129

130-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
131-
export const handleGoToScreen = (callback: any) => {
130+
export const handleGoToScreen = (
131+
callback: (e: Electron.IpcRendererEvent, screen: string) => void
132+
) => {
132133
ipcRenderer.on('openScreen', callback)
133134
return () => {
134135
ipcRenderer.removeListener('openScreen', callback)

src/backend/api/wine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const refreshWineVersionInfo = async (fetch?: boolean): Promise<void> =>
3838
export const handleProgressOfWinetricks = (
3939
onProgress: (
4040
e: Electron.IpcRendererEvent,
41-
payload: { messages: string[]; installingComponent: '' }
41+
payload: { messages: string[]; installingComponent: string }
4242
) => void
4343
): (() => void) => {
4444
ipcRenderer.on('progressOfWinetricks', onProgress)

src/backend/backend_events.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import EventEmitter from 'events'
22

3+
import type TypedEventEmitter from 'typed-emitter'
4+
import type { GameStatus, RecentGame } from 'common/types'
5+
6+
type BackendEvents = {
7+
gameStatusUpdate: (payload: GameStatus) => void
8+
recentGamesChanged: (recentGames: RecentGame[]) => void
9+
settingChanged: (obj: {
10+
key: string
11+
oldValue: unknown
12+
newValue: unknown
13+
}) => void
14+
[key: `progressUpdate-${string}`]: (progress: GameStatus) => void
15+
}
16+
317
// This can be used to emit/listen to events to decouple components
418
// For example:
519
// When the list of recent games changes, a `recentGamesChanged` event is emitted.
@@ -9,4 +23,5 @@ import EventEmitter from 'events'
923
// Usage:
1024
// Emit events with `backendEvents.emit("eventName", arg1, arg2)
1125
// Listen to events with `backendEvents.on("eventName", (arg1, arg2) => { ... })
12-
export const backendEvents = new EventEmitter()
26+
export const backendEvents =
27+
new EventEmitter() as TypedEventEmitter<BackendEvents>

src/backend/logger/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export function initLogger() {
121121
)
122122

123123
if (key === 'disableLogs') {
124-
logsDisabled = newValue
124+
logsDisabled = newValue as boolean
125125
}
126126
})
127127
}

src/backend/main_window.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AppSettings, WindowProps } from 'common/types'
22
import { BrowserWindow, screen } from 'electron'
33
import path from 'path'
44
import { configStore } from './constants'
5+
import type { FrontendMessages } from 'common/types/frontend_messages'
56

67
let mainWindow: BrowserWindow | null = null
78

@@ -18,7 +19,10 @@ export const isFrameless = () => {
1819
// send a message to the main window's webContents if available
1920
// returns `false` if no mainWindow or no webContents
2021
// returns `true` if the message was sent to the webContents
21-
export const sendFrontendMessage = (message: string, ...payload: unknown[]) => {
22+
export const sendFrontendMessage = <MessageName extends keyof FrontendMessages>(
23+
message: MessageName,
24+
...payload: Parameters<FrontendMessages[MessageName]>
25+
) => {
2226
// get the first BrowserWindow if for some reason we don't have a webContents
2327
if (!mainWindow?.webContents) {
2428
mainWindow = BrowserWindow.getAllWindows()[0]

src/backend/progress_bar.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { InstallProgress } from 'common/types'
1+
import { GameStatus } from 'common/types'
22
import { backendEvents } from './backend_events'
33
import { getMainWindow } from './main_window'
44

5-
const handleProgressUpdate = ({ progress }: { progress: InstallProgress }) => {
6-
if (progress.percent) {
5+
const handleProgressUpdate = ({ progress }: GameStatus) => {
6+
if (progress?.percent) {
77
getMainWindow()?.setProgressBar(progress.percent / 100)
88
}
99
}

src/backend/protocol.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,15 @@ async function handleLaunch(
135135
icon: icon
136136
})
137137
if (response === 0) {
138-
return sendFrontendMessage('installGame', {
139-
appName: app_name,
140-
runner: gameRunner
141-
})
138+
return sendFrontendMessage('installGame', app_name, gameRunner)
142139
}
143140
if (response === 1) {
144141
return logInfo('Not installing game', LogPrefix.ProtocolHandler)
145142
}
146143
}
147144

148145
mainWindow?.hide()
149-
sendFrontendMessage('launchGame', arg, gameRunner)
146+
sendFrontendMessage('launchGame', app_name, gameRunner)
150147
}
151148

152149
/**

0 commit comments

Comments
 (0)