Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tech] Make IPC typing simpler & more expandable #3819

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,19 @@
"single",
{ "avoidEscape": true, "allowTemplateLiterals": true }
],
"import/no-duplicates": ["error"]
"import/no-duplicates": ["error"],
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "electron",
"importNames": ["ipcMain", "ipcRenderer"],
"message": "Use the helper functions declared in src/common/ipc instead."
}
]
}
]
},
"overrides": [
{
Expand Down
3 changes: 2 additions & 1 deletion src/backend/__tests__/main_window.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createMainWindow, sendFrontendMessage } from '../main_window'
import { createMainWindow } from '../main_window'
import { sendFrontendMessage } from 'common/ipc/backend'
import { BrowserWindow, Display, screen } from 'electron'
import { configStore } from '../constants'
import { overrideProcessPlatform } from './constants.test'
Expand Down
4 changes: 2 additions & 2 deletions src/backend/anticheat/ipc_handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ipcMain } from 'electron'
import { addHandler } from 'common/ipc/backend'
import { gameAnticheatInfo } from './utils'

// we use the game's `namespace` value here, it's the value that can be easily fetch by AreWeAnticheatYet
ipcMain.handle('getAnticheatInfo', (e, appNamespace) =>
addHandler('getAnticheatInfo', (e, appNamespace) =>
gameAnticheatInfo(appNamespace)
)
88 changes: 13 additions & 75 deletions src/backend/api/downloadmanager.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,21 @@
import { DownloadManagerState } from './../../common/types'
import { ipcRenderer } from 'electron'
import { DMQueueElement, InstallParams, UpdateParams } from 'common/types'
import {
makeListenerCaller as lc,
makeHandlerInvoker as hi,
frontendListenerSlot as fls
} from 'common/ipc/frontend'

export const install = async (args: InstallParams) => {
const dmQueueElement: DMQueueElement = {
params: args,
type: 'install',
addToQueueTime: Date.now(),
endTime: 0,
startTime: 0
}
export const install = lc('install')

ipcRenderer.invoke('addToDMQueue', dmQueueElement)
export const updateGame = lc('update')

// Add Dlcs to the queue
if (
Array.isArray(args.installDlcs) &&
args.installDlcs.length > 0 &&
args.runner === 'legendary'
) {
args.installDlcs.forEach(async (dlc) => {
const dlcArgs: InstallParams = {
...args,
appName: dlc
}
const dlcQueueElement: DMQueueElement = {
params: dlcArgs,
type: 'install',
addToQueueTime: Date.now(),
endTime: 0,
startTime: 0
}
ipcRenderer.invoke('addToDMQueue', dlcQueueElement)
})
}
}
export const getDMQueueInformation = hi('getDMQueueInformation')

export const updateGame = (args: UpdateParams) => {
const {
gameInfo: {
install: { platform, install_path }
}
} = args
export const removeFromDMQueue = lc('removeFromDMQueue')

const dmQueueElement: DMQueueElement = {
params: { ...args, path: install_path!, platformToInstall: platform! },
type: 'update',
addToQueueTime: Date.now(),
endTime: 0,
startTime: 0
}
export const handleDMQueueInformation = fls('changedDMQueueInformation')

ipcRenderer.invoke('addToDMQueue', dmQueueElement)
}
export const cancelDownload = lc('cancelDownload')

export const getDMQueueInformation = async () =>
ipcRenderer.invoke('getDMQueueInformation')
export const resumeCurrentDownload = lc('resumeCurrentDownload')

export const removeFromDMQueue = (appName: string) =>
ipcRenderer.send('removeFromDMQueue', appName)

export const handleDMQueueInformation = (
onChange: (
e: Electron.IpcRendererEvent,
elements: DMQueueElement[],
state: DownloadManagerState
) => void
) => {
ipcRenderer.on('changedDMQueueInformation', onChange)
return () => {
ipcRenderer.removeListener('changedDMQueueInformation', onChange)
}
}

export const cancelDownload = (removeDownloaded: boolean) =>
ipcRenderer.send('cancelDownload', removeDownloaded)

export const resumeCurrentDownload = () =>
ipcRenderer.send('resumeCurrentDownload')

export const pauseCurrentDownload = () =>
ipcRenderer.send('pauseCurrentDownload')
export const pauseCurrentDownload = lc('pauseCurrentDownload')
214 changes: 68 additions & 146 deletions src/backend/api/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,149 +1,71 @@
import { ipcRenderer, TitleBarOverlay } from 'electron'
import {
Runner,
InstallPlatform,
WineCommandArgs,
ConnectivityStatus,
AppSettings,
GameSettings,
RunWineCommandArgs
} from 'common/types'
import { GOGCloudSavesLocation } from 'common/types/gog'

export const notify = (args: { title: string; body: string }) =>
ipcRenderer.send('notify', args)
export const openLoginPage = () => ipcRenderer.send('openLoginPage')
export const openSidInfoPage = () => ipcRenderer.send('openSidInfoPage')
export const openSupportPage = () => ipcRenderer.send('openSupportPage')
export const quit = () => ipcRenderer.send('quit')
export const showAboutWindow = () => ipcRenderer.send('showAboutWindow')
export const openDiscordLink = () => ipcRenderer.send('openDiscordLink')
export const openWinePrefixFAQ = () => ipcRenderer.send('openWinePrefixFAQ')
export const openCustomThemesWiki = () =>
ipcRenderer.send('openCustomThemesWiki')
export const createNewWindow = (url: string) =>
ipcRenderer.send('createNewWindow', url)

export const readConfig = async (file: 'library' | 'user') =>
ipcRenderer.invoke('readConfig', file)

export const isLoggedIn = async () => ipcRenderer.invoke('isLoggedIn')

export const writeConfig = async (data: {
appName: string
config: Partial<AppSettings>
}) => ipcRenderer.invoke('writeConfig', data)

export const kill = async (appName: string, runner: Runner) =>
ipcRenderer.invoke('kill', appName, runner)

export const abort = (id: string) => ipcRenderer.send('abort', id)

export const getUserInfo = async () => ipcRenderer.invoke('getUserInfo')

export const getAmazonUserInfo = async () =>
ipcRenderer.invoke('getAmazonUserInfo')

export const syncSaves = async (args: {
arg: string | undefined
path: string
appName: string
runner: Runner
}) => ipcRenderer.invoke('syncSaves', args)

export const getDefaultSavePath = async (
appName: string,
runner: Runner,
alreadyDefinedGogSaves: GOGCloudSavesLocation[] = []
) =>
ipcRenderer.invoke(
'getDefaultSavePath',
appName,
runner,
alreadyDefinedGogSaves
)
export const getGameInfo = async (appName: string, runner: Runner) =>
ipcRenderer.invoke('getGameInfo', appName, runner)
export const getExtraInfo = async (appName: string, runner: Runner) =>
ipcRenderer.invoke('getExtraInfo', appName, runner)

export const getLaunchOptions = async (appName: string, runner: Runner) =>
ipcRenderer.invoke('getLaunchOptions', appName, runner)

export const getPrivateBranchPassword = async (appName: string) =>
ipcRenderer.invoke('getPrivateBranchPassword', appName)
export const setPrivateBranchPassword = async (
appName: string,
password: string
) => ipcRenderer.invoke('setPrivateBranchPassword', appName, password)
makeListenerCaller as lc,
makeHandlerInvoker as hi,
frontendListenerSlot as fls
} from 'common/ipc/frontend'

export const notify = lc('notify')
export const openLoginPage = lc('openLoginPage')
export const openSidInfoPage = lc('openSidInfoPage')
export const openSupportPage = lc('openSupportPage')
export const quit = lc('quit')
export const showAboutWindow = lc('showAboutWindow')
export const openDiscordLink = lc('openDiscordLink')
export const openWinePrefixFAQ = lc('openWinePrefixFAQ')
export const openCustomThemesWiki = lc('openCustomThemesWiki')
export const createNewWindow = lc('createNewWindow')

export const readConfig = hi('readConfig')

export const isLoggedIn = hi('isLoggedIn')

export const writeConfig = hi('writeConfig')

export const kill = hi('kill')

export const abort = lc('abort')

export const getUserInfo = hi('getUserInfo')

export const getAmazonUserInfo = hi('getAmazonUserInfo')

export const syncSaves = hi('syncSaves')

export const getDefaultSavePath = hi('getDefaultSavePath')
export const getGameInfo = hi('getGameInfo')
export const getExtraInfo = hi('getExtraInfo')

export const getLaunchOptions = hi('getLaunchOptions')

export const getPrivateBranchPassword = hi('getPrivateBranchPassword')
export const setPrivateBranchPassword = hi('setPrivateBranchPassword')

// REDmod integration
export const getAvailableCyberpunkMods = async () =>
ipcRenderer.invoke('getAvailableCyberpunkMods')
export const setCyberpunModConfig = async (props: {
enabled: boolean
modsToLoad: string[]
}) => ipcRenderer.invoke('setCyberpunkModConfig', props)

export const getGameSettings = async (
appName: string,
runner: Runner
): Promise<GameSettings | null> =>
ipcRenderer.invoke('getGameSettings', appName, runner)

export const getInstallInfo = async (
appName: string,
runner: Runner,
installPlatform: InstallPlatform,
build?: string,
branch?: string
) =>
ipcRenderer.invoke(
'getInstallInfo',
appName,
runner,
installPlatform,
build,
branch
)

export const runWineCommand = async (args: WineCommandArgs) =>
ipcRenderer.invoke('runWineCommand', args)

export const runWineCommandForGame = async (args: RunWineCommandArgs) =>
ipcRenderer.invoke('runWineCommandForGame', args)

export const onConnectivityChanged = async (
callback: (
event: Electron.IpcRendererEvent,
status: {
status: ConnectivityStatus
retryIn: number
}
) => void
) => ipcRenderer.on('connectivity-changed', callback)

export const getConnectivityStatus = async () =>
ipcRenderer.invoke('get-connectivity-status')

export const setConnectivityOnline = async () =>
ipcRenderer.send('set-connectivity-online')

export const connectivityChanged = async (newStatus: ConnectivityStatus) =>
ipcRenderer.send('connectivity-changed', newStatus)

export const isNative = async (args: { appName: string; runner: Runner }) =>
ipcRenderer.invoke('isNative', args)

export const getThemeCSS = async (theme: string) =>
ipcRenderer.invoke('getThemeCSS', theme)

export const getCustomThemes = async () => ipcRenderer.invoke('getCustomThemes')

export const setTitleBarOverlay = (options: TitleBarOverlay) =>
ipcRenderer.send('setTitleBarOverlay', options)

export const isGameAvailable = async (args: {
appName: string
runner: Runner
}) => ipcRenderer.invoke('isGameAvailable', args)
export const getAvailableCyberpunkMods = hi('getAvailableCyberpunkMods')
export const setCyberpunModConfig = hi('setCyberpunkModConfig')

export const getGameSettings = hi('getGameSettings')

export const getInstallInfo = hi('getInstallInfo')

export const runWineCommand = hi('runWineCommand')

export const runWineCommandForGame = hi('runWineCommandForGame')

export const onConnectivityChanged = fls('connectivity-changed')

export const getConnectivityStatus = hi('get-connectivity-status')

export const setConnectivityOnline = lc('set-connectivity-online')

export const connectivityChanged = lc('connectivity-changed')

export const isNative = hi('isNative')

export const getThemeCSS = hi('getThemeCSS')

export const getCustomThemes = hi('getCustomThemes')

export const setTitleBarOverlay = lc('setTitleBarOverlay')

export const isGameAvailable = hi('isGameAvailable')
Loading
Loading