Skip to content

Commit 52bc8e6

Browse files
committed
Typechecking for sendFrontendMessage
1 parent 8a27b95 commit 52bc8e6

File tree

13 files changed

+115
-62
lines changed

13 files changed

+115
-62
lines changed

src/backend/api/helpers.ts

+7-2
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

+6-3
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

+3-2
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

+1-1
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/main_window.ts

+5-1
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/protocol.ts

+2-5
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
/**

src/backend/tools/ipc_handler.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,9 @@ ipcMain.handle('callTool', async (event, { tool, exe, appName, runner }) => {
5353
if (runner === 'gog') {
5454
// Check if game was modified by offline installer / wine uninstaller
5555
await GOGLibraryManager.checkForOfflineInstallerChanges(appName)
56-
sendFrontendMessage(
57-
'pushGameToLibrary',
58-
GOGLibraryManager.getGameInfo(appName)
59-
)
56+
const maybeNewGameInfo = GOGLibraryManager.getGameInfo(appName)
57+
if (maybeNewGameInfo)
58+
sendFrontendMessage('pushGameToLibrary', maybeNewGameInfo)
6059
}
6160

6261
sendGameStatusUpdate({ appName, runner, status: 'done' })

src/backend/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ export async function downloadDefaultWine() {
870870

871871
// download the latest version
872872
const onProgress = (state: State, progress?: ProgressInfo) => {
873-
sendFrontendMessage('progressOfWineManager' + release.version, {
873+
sendFrontendMessage(`progressOfWineManager${release.version}`, {
874874
state,
875875
progress
876876
})

src/backend/wine/manager/ipc_handler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { sendFrontendMessage } from '../../main_window'
1010

1111
ipcMain.handle('installWineVersion', async (e, release) => {
1212
const onProgress = (state: State, progress?: ProgressInfo) => {
13-
sendFrontendMessage('progressOfWineManager' + release.version, {
13+
sendFrontendMessage(`progressOfWineManager${release.version}`, {
1414
state,
1515
progress
1616
})

src/common/types.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
GameMetadataInner,
99
LegendaryInstallInfo
1010
} from './types/legendary'
11-
import { IpcRendererEvent, TitleBarOverlay } from 'electron'
11+
import { TitleBarOverlay } from 'electron'
1212
import { ChildProcess } from 'child_process'
1313
import type { HowLongToBeatEntry } from 'backend/wiki_game_info/howlongtobeat/utils'
1414
import { NileInstallInfo, NileInstallPlatform } from './types/nile'
@@ -541,11 +541,6 @@ export type InstallPlatform =
541541
| NileInstallPlatform
542542
| 'Browser'
543543

544-
export type ConnectivityChangedCallback = (
545-
event: IpcRendererEvent,
546-
status: ConnectivityStatus
547-
) => void
548-
549544
export type ConnectivityStatus = 'offline' | 'check-online' | 'online'
550545

551546
export interface Tools {

src/common/types/frontend_messages.ts

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import type {
2+
ButtonOptions,
3+
ConnectivityStatus,
4+
DialogType,
5+
DMQueueElement,
6+
DownloadManagerState,
7+
GameInfo,
8+
GameStatus,
9+
ProgressInfo,
10+
RecentGame,
11+
Runner,
12+
State
13+
} from 'common/types'
14+
15+
type FrontendMessages = {
16+
gameStatusUpdate: (status: GameStatus) => void
17+
wineVersionsUpdated: () => void
18+
showDialog: (
19+
title: string,
20+
message: string,
21+
type: DialogType,
22+
buttons?: Array<ButtonOptions>
23+
) => void
24+
changedDMQueueInformation: (
25+
elements: DMQueueElement[],
26+
state: DownloadManagerState
27+
) => void
28+
maximized: () => void
29+
unmaximized: () => void
30+
fullscreen: (status: boolean) => void
31+
refreshLibrary: (runner?: Runner) => void
32+
openScreen: (screen: string) => void
33+
'connectivity-changed': (status: {
34+
status: ConnectivityStatus
35+
retryIn: number
36+
}) => void
37+
launchGame: (appName: string, runner: Runner) => void
38+
installGame: (appName: string, runner: Runner) => void
39+
recentGamesChanged: (newRecentGames: RecentGame[]) => void
40+
pushGameToLibrary: (info: GameInfo) => void
41+
progressOfWinetricks: (payload: {
42+
messages: string[]
43+
installingComponent: string
44+
}) => void
45+
'installing-winetricks-component': (component: string) => void
46+
47+
[key: `progressUpdate${string}`]: (progress: GameStatus) => void
48+
[key: `progressOfWineManager${string}`]: (progress: {
49+
state: State
50+
progress?: ProgressInfo
51+
}) => void
52+
53+
// Used inside tests, so we can be a bit lenient with the type checking here
54+
message: (...params: unknown[]) => void
55+
}
56+
57+
export type { FrontendMessages }

src/frontend/components/UI/Sidebar/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default React.memo(function Sidebar() {
4949
}, [sidebarEl])
5050

5151
useEffect(() => {
52-
window.api.handleGoToScreen((e: Event, screen: string) => {
52+
window.api.handleGoToScreen((e, screen) => {
5353
// handle navigate to screen
5454
navigate(screen, { state: { fromGameCard: false } })
5555
})

src/frontend/state/GlobalState.tsx

+27-35
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
RefreshOptions,
1010
Runner,
1111
WineVersionInfo,
12-
InstallParams,
1312
LibraryTopSectionOptions,
1413
ExperimentalFeatures
1514
} from 'common/types'
@@ -773,44 +772,37 @@ class GlobalState extends PureComponent<Props> {
773772
}
774773
)
775774

776-
window.api.handleInstallGame(
777-
async (e: IpcRendererEvent, args: InstallParams) => {
778-
const currentApp = libraryStatus.filter(
779-
(game) => game.appName === appName
780-
)[0]
781-
const { appName, runner } = args
782-
if (!currentApp || (currentApp && currentApp.status !== 'installing')) {
783-
const gameInfo = await getGameInfo(appName, runner)
784-
if (!gameInfo || gameInfo.runner === 'sideload') {
785-
return
786-
}
787-
return this.setState({
788-
showInstallModal: {
789-
show: true,
790-
appName,
791-
runner,
792-
gameInfo
793-
}
794-
})
775+
window.api.handleInstallGame(async (e, appName, runner) => {
776+
const currentApp = libraryStatus.filter(
777+
(game) => game.appName === appName
778+
)[0]
779+
if (!currentApp || (currentApp && currentApp.status !== 'installing')) {
780+
const gameInfo = await getGameInfo(appName, runner)
781+
if (!gameInfo || gameInfo.runner === 'sideload') {
782+
return
795783
}
784+
return this.setState({
785+
showInstallModal: {
786+
show: true,
787+
appName,
788+
runner,
789+
gameInfo
790+
}
791+
})
796792
}
797-
)
793+
})
798794

799-
window.api.handleGameStatus(
800-
async (e: IpcRendererEvent, args: GameStatus) => {
801-
return this.handleGameStatus({ ...args })
802-
}
803-
)
795+
window.api.handleGameStatus((e, args) => {
796+
this.handleGameStatus({ ...args })
797+
})
804798

805-
window.api.handleRefreshLibrary(
806-
async (e: IpcRendererEvent, runner: Runner) => {
807-
this.refreshLibrary({
808-
checkForUpdates: false,
809-
runInBackground: true,
810-
library: runner
811-
})
812-
}
813-
)
799+
window.api.handleRefreshLibrary((e, runner) => {
800+
this.refreshLibrary({
801+
checkForUpdates: false,
802+
runInBackground: true,
803+
library: runner
804+
})
805+
})
814806

815807
window.api.handleGamePush((e: IpcRendererEvent, args: GameInfo) => {
816808
if (!args.app_name) return

0 commit comments

Comments
 (0)