small IPC refactor

This commit is contained in:
Alexander Drozdov
2022-02-17 12:56:39 +02:00
parent 70da2bdeb2
commit 0a2c645ea5
33 changed files with 376 additions and 344 deletions
+122 -70
View File
@@ -1,73 +1,125 @@
export const GET_CONFIG = 'get-config'
export const SAVE_CONFIG = 'OVERLAY->MAIN::save-config'
import type { Config } from '@/ipc/types'
export const PRICE_CHECK_HIDE = 'OVERLAY->MAIN::price-check-hide'
export type IpcEvent =
IpcGetConfig |
IpcSaveConfig |
IpcPriceCheckHide |
IpcUpdateInfo |
IpcFocusChange |
IpcDPRChange |
IpcPriceCheck |
IpcPriceCheckCanceled |
IpcItemCheck |
IpcStashSearch |
IpcOverlayReady |
IpcCloseOverlay |
IpcShowBrowser |
IpcHideBrowser |
IpcVisibility |
IpcOpenSystemBrowser |
IpcOpenWiki |
IpcOpenCraftOfExile |
IpcImportFile |
IpcToggleDelveGrid |
IpcClientLog
export const UPDATE_AVAILABLE = 'update-available'
export interface IpcUpdateInfo {
auto: boolean
version: string
}
export const FOCUS_CHANGE = 'MAIN->OVERLAY::focus-change'
export interface IpcFocusChange {
game: boolean
overlay: boolean
usingHotkey: boolean
}
export const DPR_CHANGE = 'OVERLAY->MAIN::devicePixelRatio-change'
export const PRICE_CHECK = 'MAIN->OVERLAY::price-check'
export const PRICE_CHECK_CANCELED = 'MAIN->OVERLAY::price-check-canceled'
export interface IpcPriceCheck {
clipboard: string
position: { x: number, y: number }
lockedMode: boolean
}
export const ITEM_CHECK = 'MAIN->OVERLAY::item-check'
export interface IpcItemCheck {
clipboard: string
position: { x: number, y: number }
}
export const STASH_SEARCH = 'OVERLAY->MAIN::stash-search'
export interface IpcStashSearch {
text: string
}
export const OVERLAY_READY = 'OVERLAY->MAIN::ready'
export const CLOSE_OVERLAY = 'OVERLAY->MAIN::close-overlay'
export const SHOW_BROWSER = 'OVERLAY->MAIN::show-browser'
export interface IpcShowBrowser {
url?: string
}
export const HIDE_BROWSER = 'OVERLAY->MAIN::hide-browser'
export interface IpcHideBrowser {
close?: boolean
}
export const VISIBILITY = 'MAIN->OVERLAY::visibility'
export interface IpcVisibility {
isVisible: boolean
}
export const OPEN_SYSTEM_BROWSER = 'OVERLAY->MAIN::system-browser'
export interface IpcOpenSystemBrowser {
url: string
}
export const OPEN_WIKI = 'MAIN->OVERLAY::open-wiki'
export const OPEN_COE = 'MAIN->OVERLAY::open-craft-of-exile'
export const IMPORT_FILE = 'OVERLAY->MAIN::import-file'
export const TOGGLE_DELVE_GRID = 'MAIN->OVERLAY::delve-grid'
export const CLIENT_LOG_UPDATE = 'MAIN->OVERLAY::client-log'
export interface IpcClientLog {
lines: string[]
export type IpcEventPayload<Name extends IpcEvent['name'], T extends IpcEvent = IpcEvent> =
T extends { name: Name } ? T['payload'] : never
export type IpcGetConfig =
Event<'OVERLAY->MAIN::get-config', Config>
export type IpcSaveConfig =
Event<'OVERLAY->MAIN::save-config', Config>
export type IpcPriceCheckHide =
Event<'OVERLAY->MAIN::price-check-hide'>
export type IpcUpdateInfo =
Event<'MAIN->OVERLAY::update-available', {
auto: boolean
version: string
}>
export type IpcFocusChange =
Event<'MAIN->OVERLAY::focus-change', {
game: boolean
overlay: boolean
usingHotkey: boolean
}>
export type IpcDPRChange =
Event<'OVERLAY->MAIN::devicePixelRatio-change', number>
export type IpcPriceCheck =
Event<'MAIN->OVERLAY::price-check', {
clipboard: string
position: { x: number, y: number }
lockedMode: boolean
}>
export type IpcPriceCheckCanceled =
Event<'MAIN->OVERLAY::price-check-canceled'>
export type IpcItemCheck =
Event<'MAIN->OVERLAY::item-check', {
clipboard: string
position: { x: number, y: number }
}>
export type IpcStashSearch =
Event<'OVERLAY->MAIN::stash-search', {
text: string
}>
export type IpcOverlayReady =
Event<'OVERLAY->MAIN::ready'>
export type IpcCloseOverlay =
Event<'OVERLAY->MAIN::close-overlay'>
export type IpcShowBrowser =
Event<'OVERLAY->MAIN::show-browser', {
url?: string
}>
export type IpcHideBrowser =
Event<'OVERLAY->MAIN::hide-browser', {
close?: boolean
}>
export type IpcVisibility =
Event<'MAIN->OVERLAY::visibility', {
isVisible: boolean
}>
export type IpcOpenSystemBrowser =
Event<'OVERLAY->MAIN::system-browser', string>
export type IpcOpenWiki =
Event<'MAIN->OVERLAY::open-wiki', {
clipboard: string
position: { x: number, y: number }
}>
export type IpcOpenCraftOfExile =
Event<'MAIN->OVERLAY::open-craft-of-exile', {
clipboard: string
position: { x: number, y: number }
}>
export type IpcImportFile =
Event<'OVERLAY->MAIN::import-file', string>
export type IpcToggleDelveGrid =
Event<'MAIN->OVERLAY::delve-grid'>
export type IpcClientLog =
Event<'MAIN->OVERLAY::client-log', {
lines: string[]
}>
interface Event<TName extends string, TPayload = undefined> {
name: TName
payload: TPayload
}
-158
View File
@@ -1,158 +0,0 @@
import { Renderer } from 'electron'
import * as ipcEvent from '@/ipc/ipc-event'
import { Config, defaultConfig } from '@/ipc/types'
let electron: typeof Renderer | undefined
try {
electron = require('electron')
} catch {}
class MainProcessBinding extends EventTarget {
constructor () {
super()
if (electron) {
electron.ipcRenderer.on(ipcEvent.PRICE_CHECK, (e, data) => {
this.selfEmitPriceCheck(data)
})
electron.ipcRenderer.on(ipcEvent.ITEM_CHECK, (e, data) => {
this.dispatchEvent(new CustomEvent(ipcEvent.ITEM_CHECK, {
detail: data
}))
})
electron.ipcRenderer.on(ipcEvent.SAVE_CONFIG, (e, cfg) => {
this.dispatchEvent(new CustomEvent(ipcEvent.SAVE_CONFIG, {
detail: cfg
}))
})
electron.ipcRenderer.on(ipcEvent.FOCUS_CHANGE, (e, data) => {
this.dispatchEvent(new CustomEvent(ipcEvent.FOCUS_CHANGE, { detail: data }))
})
electron.ipcRenderer.on(ipcEvent.PRICE_CHECK_CANCELED, () => {
this.dispatchEvent(new CustomEvent(ipcEvent.PRICE_CHECK_CANCELED))
})
electron.ipcRenderer.on(ipcEvent.UPDATE_AVAILABLE, (e, updateInfo) => {
this.dispatchEvent(new CustomEvent(ipcEvent.UPDATE_AVAILABLE, {
detail: updateInfo
}))
})
electron.ipcRenderer.on(ipcEvent.VISIBILITY, (e, detail) => {
this.dispatchEvent(new CustomEvent(ipcEvent.VISIBILITY, { detail }))
})
electron.ipcRenderer.on(ipcEvent.OPEN_WIKI, (e, detail) => {
this.dispatchEvent(new CustomEvent(ipcEvent.OPEN_WIKI, { detail }))
})
electron.ipcRenderer.on(ipcEvent.OPEN_COE, (e, detail) => {
this.dispatchEvent(new CustomEvent(ipcEvent.OPEN_COE, { detail }))
})
electron.ipcRenderer.on(ipcEvent.TOGGLE_DELVE_GRID, (e) => {
this.dispatchEvent(new CustomEvent(ipcEvent.TOGGLE_DELVE_GRID))
})
electron.ipcRenderer.on(ipcEvent.CLIENT_LOG_UPDATE, (e, data: ipcEvent.IpcClientLog) => {
data.lines.forEach(line => {
this.dispatchEvent(new CustomEvent(ipcEvent.CLIENT_LOG_UPDATE, {
detail: line
}))
})
})
}
}
selfEmitPriceCheck (e: ipcEvent.IpcPriceCheck) {
this.dispatchEvent(new CustomEvent(ipcEvent.PRICE_CHECK, {
detail: e
}))
}
readyReceiveEvents () {
if (electron) {
electron.ipcRenderer.send(ipcEvent.OVERLAY_READY)
}
}
dprChanged (dpr: number) {
if (electron) {
electron.ipcRenderer.send(ipcEvent.DPR_CHANGE, dpr)
}
}
closeOverlay () {
if (electron) {
electron.ipcRenderer.send(ipcEvent.CLOSE_OVERLAY)
}
}
priceCheckWidgetIsHidden () {
if (electron) {
electron.ipcRenderer.send(ipcEvent.PRICE_CHECK_HIDE)
}
}
getConfig (): Config {
if (electron) {
return electron.ipcRenderer.sendSync(ipcEvent.GET_CONFIG)
} else {
return defaultConfig()
}
}
openSystemBrowser (url: string) {
if (electron) {
electron.ipcRenderer.send(ipcEvent.OPEN_SYSTEM_BROWSER, { url } as ipcEvent.IpcOpenSystemBrowser)
}
}
openAppBrowser (opts: ipcEvent.IpcShowBrowser) {
if (electron) {
electron.ipcRenderer.send(ipcEvent.SHOW_BROWSER, opts)
} else if (opts.url) {
window.open(opts.url)
}
}
hideAppBrowser (opts: ipcEvent.IpcHideBrowser) {
if (electron) {
electron.ipcRenderer.send(ipcEvent.HIDE_BROWSER, opts)
}
}
stashSearch (text: string) {
if (electron) {
electron.ipcRenderer.send(ipcEvent.STASH_SEARCH, { text })
}
}
saveConfig (config: Config) {
if (electron) {
electron.ipcRenderer.send(ipcEvent.SAVE_CONFIG, config)
}
}
importFile (filePath: string) {
if (electron) {
return electron.ipcRenderer.sendSync(ipcEvent.IMPORT_FILE, filePath)
}
}
get CORS () {
return (!electron)
? 'https://apt-cors.snos.workers.dev/?'
: ''
}
get isElectron () {
return (electron != null)
}
}
export const MainProcess = new MainProcessBinding()
+5 -3
View File
@@ -1,6 +1,5 @@
import { promises as fs, watchFile, unwatchFile } from 'fs'
import { overlayWindow } from './overlay-window'
import * as ipc from '@/ipc/ipc-event'
import { overlaySendEvent } from './overlay-window'
import { config } from './config'
import { logger } from './logger'
@@ -76,7 +75,10 @@ export class LogWatcher {
if (bytesRead) {
const str = this.readBuff.toString('utf8', 0, bytesRead)
const lines = str.split('\n').map(line => line.trim()).filter(line => line.length)
overlayWindow!.webContents.send(ipc.CLIENT_LOG_UPDATE, { lines } as ipc.IpcClientLog)
overlaySendEvent({
name: 'MAIN->OVERLAY::client-log',
payload: { lines }
})
}
if (bytesRead) {
+9 -4
View File
@@ -1,5 +1,4 @@
import { overlayWindow, isInteractable } from './overlay-window'
import { VISIBILITY, IpcVisibility } from '@/ipc/ipc-event'
import { isInteractable, overlaySendEvent } from './overlay-window'
import { uIOhook, UiohookKey } from 'uiohook-napi'
import { logger } from './logger'
@@ -34,7 +33,10 @@ function makeVisible () {
} else {
logger.debug('Making visible again', { source: 'alt-visibility' })
isOverlayVisible = true
overlayWindow!.webContents.send(VISIBILITY, { isVisible: isOverlayVisible } as IpcVisibility)
overlaySendEvent({
name: 'MAIN->OVERLAY::visibility',
payload: { isVisible: isOverlayVisible }
})
}
}
@@ -46,6 +48,9 @@ function makeInvisible () {
logger.debug('Delay passed, overlay is invisible', { source: 'alt-visibility' })
timerId = undefined
isOverlayVisible = false
overlayWindow!.webContents.send(VISIBILITY, { isVisible: isOverlayVisible } as IpcVisibility)
overlaySendEvent({
name: 'MAIN->OVERLAY::visibility',
payload: { isVisible: isOverlayVisible }
})
}, isInteractable ? 85 : 275)
}
+3 -3
View File
@@ -1,9 +1,9 @@
import { protocol, app, ipcMain } from 'electron'
import { IMPORT_FILE } from '@/ipc/ipc-event'
import { protocol, app } from 'electron'
import { URL } from 'url'
import path from 'path'
import crypto from 'crypto'
import fs from 'fs'
import { overlayOnEvent } from './overlay-window'
export function createFileProtocol () {
protocol.registerFileProtocol('app', (req, resp) => {
@@ -16,7 +16,7 @@ export function createFileProtocol () {
resp({ path: path.join(app.getPath('userData'), 'apt-data/files', req.url.substr('app-file://'.length)) })
})
ipcMain.on(IMPORT_FILE, (e, filePath: string) => {
overlayOnEvent('OVERLAY->MAIN::import-file', (e, filePath) => {
const file = fs.readFileSync(filePath)
const hash = crypto.createHash('md5').update(file).digest('hex')
const filename = `${hash}${path.extname(filePath)}`
+8 -9
View File
@@ -1,6 +1,5 @@
import { ipcMain, BrowserView, screen, shell } from 'electron'
import * as ipc from '@/ipc/ipc-event'
import { DPR, overlayWindow, handleExtraCommands } from './overlay-window'
import { BrowserView, screen, shell } from 'electron'
import { DPR, overlayWindow, handleExtraCommands, overlayOnEvent } from './overlay-window'
import { PoeWindow } from './PoeWindow'
import { logger } from './logger'
import { config } from './config'
@@ -10,7 +9,7 @@ const WIDTH_96DPI = 460 / 16
let browserViewExternal: BrowserView | undefined
export function setupBuiltinBrowser () {
ipcMain.on(ipc.SHOW_BROWSER, (e, opts: ipc.IpcShowBrowser) => {
overlayOnEvent('OVERLAY->MAIN::show-browser', (_, opts) => {
logger.debug('Show', { source: 'builtin-browser', opts })
if (!browserViewExternal) {
browserViewExternal = new BrowserView()
@@ -26,8 +25,8 @@ export function setupBuiltinBrowser () {
let browserBounds = {
x: 0,
y: 0,
width: PoeWindow.bounds!.width - Math.floor(WIDTH_96DPI * DPR * config.get('fontSize')),
height: PoeWindow.bounds!.height
width: PoeWindow.bounds.width - Math.floor(WIDTH_96DPI * DPR * config.get('fontSize')),
height: PoeWindow.bounds.height
}
if (process.platform === 'win32') {
browserBounds = screen.screenToDipRect(overlayWindow!, browserBounds)
@@ -38,7 +37,7 @@ export function setupBuiltinBrowser () {
}
})
ipcMain.on(ipc.HIDE_BROWSER, (e, opts: ipc.IpcHideBrowser) => {
overlayOnEvent('OVERLAY->MAIN::hide-browser', (_, opts) => {
logger.debug('Hide', { source: 'builtin-browser', close: opts.close || false })
if (browserViewExternal) {
overlayWindow!.removeBrowserView(browserViewExternal)
@@ -51,7 +50,7 @@ export function setupBuiltinBrowser () {
}
})
ipcMain.on(ipc.OPEN_SYSTEM_BROWSER, (e, opts: ipc.IpcOpenSystemBrowser) => {
shell.openExternal(opts.url)
overlayOnEvent('OVERLAY->MAIN::system-browser', (_, url) => {
shell.openExternal(url)
})
}
+4 -4
View File
@@ -1,18 +1,18 @@
import Store from 'electron-store'
import { dialog, ipcMain, app } from 'electron'
import { dialog, app } from 'electron'
import isDeepEq from 'fast-deep-equal'
import { Config, defaultConfig } from '@/ipc/types'
import { GET_CONFIG, SAVE_CONFIG } from '@/ipc/ipc-event'
import { logger } from './logger'
import { LogWatcher } from './LogWatcher'
import { ItemCheckWidget } from '@/web/overlay/interfaces'
import { loadAndCache as loadAndCacheGameCfg } from './game-config'
import { overlayOnEvent } from './overlay-window'
export function setupConfigEvents () {
ipcMain.on(GET_CONFIG, (e) => {
overlayOnEvent('OVERLAY->MAIN::get-config', (e) => {
e.returnValue = config.store
})
ipcMain.on(SAVE_CONFIG, (e, cfg: Config) => {
overlayOnEvent('OVERLAY->MAIN::save-config', (_, cfg) => {
batchUpdateConfig(cfg)
})
}
+25 -9
View File
@@ -1,5 +1,6 @@
import path from 'path'
import { BrowserWindow, ipcMain, dialog, Menu, systemPreferences } from 'electron'
import assert from 'assert'
import { BrowserWindow, ipcMain, dialog, Menu, systemPreferences, IpcMainEvent } from 'electron'
import { PoeWindow } from './PoeWindow'
import { logger } from './logger'
import * as ipc from '@/ipc/ipc-event'
@@ -15,6 +16,18 @@ export const overlayReady = new Promise<void>((resolve) => {
_resolveOverlayReady = resolve
})
export function overlaySendEvent (event: ipc.IpcEvent) {
assert.ok(overlayWindow)
overlayWindow.webContents.send('named-event', event)
}
export function overlayOnEvent<Name extends ipc.IpcEvent['name']> (
name: Name,
cb: (e: IpcMainEvent, payload: ipc.IpcEventPayload<Name>) => void
) {
ipcMain.on(name, cb)
}
export async function createOverlayWindow () {
if (process.platform === 'win32' && !systemPreferences.isAeroGlassEnabled()) {
dialog.showErrorBox(
@@ -25,9 +38,9 @@ export async function createOverlayWindow () {
)
}
ipcMain.once(ipc.OVERLAY_READY, _resolveOverlayReady)
ipcMain.on(ipc.DPR_CHANGE, (_: any, dpr: number) => handleDprChange(dpr))
ipcMain.on(ipc.CLOSE_OVERLAY, assertPoEActive)
overlayOnEvent('OVERLAY->MAIN::ready', _resolveOverlayReady)
overlayOnEvent('OVERLAY->MAIN::devicePixelRatio-change', (_, dpr) => handleDprChange(dpr))
overlayOnEvent('OVERLAY->MAIN::close-overlay', assertPoEActive)
PoeWindow.on('active-change', handlePoeWindowActiveChange)
PoeWindow.onAttach(handleOverlayAttached)
@@ -86,11 +99,14 @@ function handlePoeWindowActiveChange (isActive: boolean) {
if (isActive && isInteractable) {
isInteractable = false
}
overlayWindow!.webContents.send(ipc.FOCUS_CHANGE, {
game: isActive,
overlay: isInteractable,
usingHotkey: _isOverlayKeyUsed
} as ipc.IpcFocusChange)
overlaySendEvent({
name: 'MAIN->OVERLAY::focus-change',
payload: {
game: isActive,
overlay: isInteractable,
usingHotkey: _isOverlayKeyUsed
}
})
_isOverlayKeyUsed = false
}
+8 -6
View File
@@ -1,11 +1,10 @@
import { ipcMain, Rectangle, Point } from 'electron'
import { Rectangle, Point } from 'electron'
import { uIOhook } from 'uiohook-napi'
import { isPollingClipboard } from './poll-clipboard'
import { PoeWindow } from './PoeWindow'
import * as ipc from '@/ipc/ipc-event'
import { config } from './config'
import { logger } from './logger'
import { overlayWindow, isInteractable, assertOverlayActive, assertPoEActive, DPR } from './overlay-window'
import { isInteractable, assertOverlayActive, assertPoEActive, DPR, overlayOnEvent, overlaySendEvent } from './overlay-window'
import type { PriceCheckWidget } from '@/web/overlay/interfaces'
const WIDTH_96DPI = 460 / 16
@@ -26,7 +25,10 @@ export function showWidget (opts: {
checkPressPosition = opts.pressPosition
const isLokedMode = (opts.eventName === 'price-check-locked')
overlayWindow!.webContents.send(ipc.PRICE_CHECK, { clipboard: opts.clipboard, position: checkPressPosition, lockedMode: isLokedMode } as ipc.IpcPriceCheck)
overlaySendEvent({
name: 'MAIN->OVERLAY::price-check',
payload: { clipboard: opts.clipboard, position: checkPressPosition, lockedMode: isLokedMode }
})
const poeBounds = PoeWindow.bounds
activeAreaRect = {
@@ -52,7 +54,7 @@ export function lockWindow (syntheticClick = false) {
}
export function setupShowHide () {
ipcMain.on(ipc.PRICE_CHECK_HIDE, () => {
overlayOnEvent('OVERLAY->MAIN::price-check-hide', () => {
if (isPriceCheckShown) {
logger.debug('Closing', { source: 'price-check', reason: 'Event from widget' })
isPriceCheckShown = false
@@ -68,7 +70,7 @@ export function setupShowHide () {
if (distance > (CLOSE_THRESHOLD_96DPI * DPR * config.get('fontSize'))) {
logger.debug('Closing', { source: 'price-check', reason: 'Auto-hide on mouse move', distance, threshold: CLOSE_THRESHOLD_96DPI })
overlayWindow!.webContents.send(ipc.PRICE_CHECK_CANCELED)
overlaySendEvent({ name: 'MAIN->OVERLAY::price-check-canceled', payload: undefined })
isPriceCheckShown = false
}
} else if (!isMouseInside) {
+21 -12
View File
@@ -1,4 +1,4 @@
import { screen, globalShortcut, ipcMain } from 'electron'
import { screen, globalShortcut } from 'electron'
import robotjs from 'robotjs'
import { uIOhook, UiohookKey, UiohookWheelEvent } from 'uiohook-napi'
import { pollClipboard } from './poll-clipboard'
@@ -7,7 +7,7 @@ import { isModKey, KeyToElectron, mergeTwoHotkeys } from '@/ipc/KeyToCode'
import { config } from './config'
import { PoeWindow } from './PoeWindow'
import { logger } from './logger'
import { toggleOverlayState, overlayWindow, assertOverlayActive, assertPoEActive } from './overlay-window'
import { toggleOverlayState, assertOverlayActive, assertPoEActive, overlayOnEvent, overlaySendEvent } from './overlay-window'
import * as ipc from '@/ipc/ipc-event'
import { typeInChat } from './game-chat'
import { gameConfig } from './game-config'
@@ -20,11 +20,17 @@ export interface ShortcutAction {
keepModKeys?: true
action: {
type: 'copy-item'
eventName: string
eventName: (
ipc.IpcOpenWiki['name'] |
ipc.IpcOpenCraftOfExile['name'] |
ipc.IpcItemCheck['name'] |
'price-check-quick' |
'price-check-locked'
)
focusOverlay?: boolean
} | {
type: 'trigger-event'
eventName: string
eventName: ipc.IpcToggleDelveGrid['name']
} | {
type: 'toggle-overlay'
} | {
@@ -61,25 +67,25 @@ function shortcutsFromConfig () {
if (config.get('wikiKey')) {
actions.push({
shortcut: config.get('wikiKey')!,
action: { type: 'copy-item', eventName: ipc.OPEN_WIKI }
action: { type: 'copy-item', eventName: 'MAIN->OVERLAY::open-wiki' }
})
}
if (config.get('craftOfExileKey')) {
actions.push({
shortcut: config.get('craftOfExileKey')!,
action: { type: 'copy-item', eventName: ipc.OPEN_COE }
action: { type: 'copy-item', eventName: 'MAIN->OVERLAY::open-craft-of-exile' }
})
}
if (config.get('itemCheckKey')) {
actions.push({
shortcut: config.get('itemCheckKey')!,
action: { type: 'copy-item', eventName: ipc.ITEM_CHECK, focusOverlay: true }
action: { type: 'copy-item', eventName: 'MAIN->OVERLAY::item-check', focusOverlay: true }
})
}
if (config.get('delveGridKey')) {
actions.push({
shortcut: config.get('delveGridKey')!,
action: { type: 'trigger-event', eventName: ipc.TOGGLE_DELVE_GRID },
action: { type: 'trigger-event', eventName: 'MAIN->OVERLAY::delve-grid' },
keepModKeys: true
})
}
@@ -149,7 +155,7 @@ function registerGlobal () {
} else if (entry.action.type === 'paste-in-chat') {
typeInChat(entry.action.text, entry.action.send)
} else if (entry.action.type === 'trigger-event') {
overlayWindow!.webContents.send(entry.action.eventName)
overlaySendEvent({ name: entry.action.eventName, payload: undefined })
} else if (entry.action.type === 'copy-item') {
const { action } = entry
@@ -160,10 +166,13 @@ function registerGlobal () {
pollClipboard()
.then(clipboard => {
if (action.eventName.startsWith('price-check')) {
if (action.eventName === 'price-check-quick' || action.eventName === 'price-check-locked') {
showPriceCheck({ clipboard, pressPosition, eventName: action.eventName })
} else {
overlayWindow!.webContents.send(action.eventName, { clipboard, position: pressPosition })
overlaySendEvent({
name: action.eventName,
payload: { clipboard, position: pressPosition }
})
if (action.focusOverlay) {
assertOverlayActive()
}
@@ -233,7 +242,7 @@ export function setupShortcuts () {
})
})
ipcMain.on(ipc.STASH_SEARCH, (e, opts: ipc.IpcStashSearch) => { stashSearch(opts.text) })
overlayOnEvent('OVERLAY->MAIN::stash-search', (_, { text }) => { stashSearch(text) })
uIOhook.on('keydown', (e) => {
const pressed = eventToString(e)
+9 -4
View File
@@ -1,8 +1,7 @@
import { autoUpdater } from 'electron-updater'
import { logger } from './logger'
import { rebuildTrayMenu } from './tray'
import { UPDATE_AVAILABLE } from '@/ipc/ipc-event'
import { overlayWindow, overlayReady } from './overlay-window'
import { overlayReady, overlaySendEvent } from './overlay-window'
import { config } from './config'
export const UpdateState = {
@@ -17,7 +16,10 @@ autoUpdater.on('update-available', async (info: { version: string }) => {
} else {
UpdateState.status = `Update v${info.version} available on GitHub`
await overlayReady
overlayWindow!.webContents.send(UPDATE_AVAILABLE, { auto: false, version: info.version })
overlaySendEvent({
name: 'MAIN->OVERLAY::update-available',
payload: { auto: false, version: info.version }
})
}
rebuildTrayMenu()
})
@@ -39,7 +41,10 @@ autoUpdater.on('update-downloaded', async (info: { version: string }) => {
UpdateState.status = `v${info.version} will be installed on exit`
rebuildTrayMenu()
await overlayReady
overlayWindow!.webContents.send(UPDATE_AVAILABLE, { auto: true, version: info.version })
overlaySendEvent({
name: 'MAIN->OVERLAY::update-available',
payload: { auto: true, version: info.version }
})
})
// on('download-progress') https://github.com/electron-userland/electron-builder/issues/2521
+1 -1
View File
@@ -1,5 +1,5 @@
import { reactive as deepReactive, shallowRef } from 'vue'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import type { Config } from '@/ipc/types'
import type { Widget } from './overlay/interfaces'
+6 -6
View File
@@ -1,9 +1,9 @@
import { UPDATE_AVAILABLE, IpcUpdateInfo } from '@/ipc/ipc-event'
import { MainProcess } from '@/ipc/main-process-bindings'
import { ref } from 'vue'
import type { IpcUpdateInfo } from '@/ipc/ipc-event'
import { MainProcess } from '@/web/background/IPC'
import { shallowRef } from 'vue'
export const updateInfo = ref<IpcUpdateInfo | null>(null)
export const updateInfo = shallowRef<IpcUpdateInfo['payload'] | null>(null)
MainProcess.addEventListener(UPDATE_AVAILABLE, (e) => {
updateInfo.value = (e as CustomEvent<IpcUpdateInfo>).detail
MainProcess.onEvent('MAIN->OVERLAY::update-available', (e) => {
updateInfo.value = e
})
+85
View File
@@ -0,0 +1,85 @@
import type { Renderer } from 'electron'
import type { IpcEvent, IpcEventPayload, IpcGetConfig, IpcImportFile } from '@/ipc/ipc-event'
import { Config, defaultConfig } from '@/ipc/types'
let electron: typeof Renderer | undefined
try {
electron = require('electron')
} catch {}
class MainProcessBinding {
private evBus = new EventTarget()
constructor () {
if (electron) {
electron.ipcRenderer.on('named-event', (_e, data: IpcEvent) => {
this.selfDispatch(data)
})
}
}
selfDispatch (event: IpcEvent) {
this.evBus.dispatchEvent(new CustomEvent(event.name, {
detail: event.payload
}))
}
sendEvent (event: IpcEvent) {
if (electron) {
electron.ipcRenderer.send(event.name, event.payload)
}
}
onEvent<Name extends IpcEvent['name']> (
name: Name,
cb: (payload: IpcEventPayload<Name>) => void
) {
this.evBus.addEventListener(name, (e) => {
cb((e as CustomEvent<IpcEventPayload<Name>>).detail)
})
}
closeOverlay () {
this.sendEvent({ name: 'OVERLAY->MAIN::close-overlay', payload: undefined })
}
getConfig (): Config {
if (electron) {
const name: IpcGetConfig['name'] = 'OVERLAY->MAIN::get-config'
return electron.ipcRenderer.sendSync(name) as IpcGetConfig['payload']
} else {
return defaultConfig()
}
}
openSystemBrowser (url: string) {
if (electron) {
this.sendEvent({ name: 'OVERLAY->MAIN::system-browser', payload: url })
} else {
window.open(url)
}
}
saveConfig (config: Config) {
this.sendEvent({ name: 'OVERLAY->MAIN::save-config', payload: config })
}
importFile (filePath: string) {
if (electron) {
const name: IpcImportFile['name'] = 'OVERLAY->MAIN::import-file'
return electron.ipcRenderer.sendSync(name, filePath) as IpcImportFile['payload']
}
}
get CORS () {
return (!electron)
? 'https://apt-cors.snos.workers.dev/?'
: ''
}
get isElectron () {
return (electron != null)
}
}
export const MainProcess = new MainProcessBinding()
+1 -1
View File
@@ -1,5 +1,5 @@
import { ref, watch } from 'vue'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { selected as selectedLeague, isPublic as isPublicLeague } from './Leagues'
interface NinjaCurrencyInfo { /* eslint-disable camelcase */
+5 -8
View File
@@ -13,11 +13,9 @@ import { useI18n } from 'vue-i18n'
import Widget from '../overlay/Widget.vue'
import MapCheck from '../map-check/MapCheck.vue'
import ItemInfo from './ItemInfo.vue'
import { MainProcess } from '@/ipc/main-process-bindings'
import { ITEM_CHECK } from '@/ipc/ipc-event'
import { MainProcess } from '@/web/background/IPC'
import { ItemCategory, parseClipboard, ParsedItem } from '@/parser'
import { ItemCheckWidget, WidgetManager } from '../overlay/interfaces'
import * as ipc from '@/ipc/ipc-event'
export default defineComponent({
components: {
@@ -38,13 +36,12 @@ export default defineComponent({
const checkPosition = ref({ x: 1, y: 1 })
const item = ref<ParsedItem | null>(null)
MainProcess.addEventListener(ITEM_CHECK, (e) => {
const _e = (e as CustomEvent<ipc.IpcItemCheck>).detail
MainProcess.onEvent('MAIN->OVERLAY::item-check', (e) => {
checkPosition.value = {
x: _e.position.x - window.screenX,
y: _e.position.y - window.screenY
x: e.position.x - window.screenX,
y: e.position.y - window.screenY
}
item.value = parseClipboard(_e.clipboard)
item.value = parseClipboard(e.clipboard)
if (item.value) {
wm.show(props.config.wmId)
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { parseClipboard } from '@/parser'
const COE_URL = 'https://craftofexile.com/'
+9 -8
View File
@@ -1,19 +1,20 @@
import { MainProcess } from '@/ipc/main-process-bindings'
import * as ipc from '@/ipc/ipc-event'
import { MainProcess } from '@/web/background/IPC'
import { openWiki } from './wiki'
import { openCOE } from './craft-of-exile'
import { handleLine } from '../client-log/client-log'
export function registerOtherServices () {
MainProcess.addEventListener(ipc.OPEN_WIKI, (e) => {
openWiki((e as CustomEvent<{ clipboard: string }>).detail.clipboard)
MainProcess.onEvent('MAIN->OVERLAY::open-wiki', (e) => {
openWiki(e.clipboard)
})
MainProcess.addEventListener(ipc.CLIENT_LOG_UPDATE, (e) => {
handleLine((e as CustomEvent<string>).detail)
MainProcess.onEvent('MAIN->OVERLAY::client-log', (e) => {
for (const line of e.lines) {
handleLine(line)
}
})
MainProcess.addEventListener(ipc.OPEN_COE, (e) => {
openCOE((e as CustomEvent<{ clipboard: string }>).detail.clipboard)
MainProcess.onEvent('MAIN->OVERLAY::open-craft-of-exile', (e) => {
openCOE(e.clipboard)
})
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { parseClipboard } from '@/parser'
import { AppConfig } from '@/web/Config'
+20 -9
View File
@@ -20,7 +20,7 @@
</template>
<script>
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import WidgetTimer from './WidgetTimer'
import WidgetStashSearch from './WidgetStashSearch'
import WidgetMenu from './WidgetMenu'
@@ -31,7 +31,6 @@ import WidgetImageStrip from './WidgetImageStrip'
import WidgetDelveGrid from './WidgetDelveGrid'
import WidgetSettings from '../settings/SettingsWindow'
import { registerOtherServices } from '../other-services'
import { FOCUS_CHANGE, VISIBILITY } from '@/ipc/ipc-event'
import { AppConfig, saveConfig } from '@/web/Config'
import LoadingAnimation from './LoadingAnimation.vue'
// ---
@@ -69,7 +68,10 @@ export default {
devicePixelRatio: {
immediate: false,
handler (dpr) {
MainProcess.dprChanged(dpr)
MainProcess.sendEvent({
name: 'OVERLAY->MAIN::devicePixelRatio-change',
payload: dpr
})
}
},
visibilityState (stateNow, stateOld) {
@@ -98,7 +100,7 @@ export default {
created () {
loadLeagues()
MainProcess.addEventListener(FOCUS_CHANGE, ({ detail: state }) => {
MainProcess.onEvent('MAIN->OVERLAY::focus-change', (state) => {
this.active = state.overlay
this.gameFocused = state.game
@@ -120,7 +122,7 @@ export default {
}
}
})
MainProcess.addEventListener(VISIBILITY, ({ detail: e }) => {
MainProcess.onEvent('MAIN->OVERLAY::visibility', (e) => {
this.hideUI = !e.isVisible
})
window.addEventListener('resize', () => {
@@ -133,7 +135,7 @@ export default {
},
mounted () {
this.$nextTick(() => {
MainProcess.readyReceiveEvents()
MainProcess.sendEvent({ name: 'OVERLAY->MAIN::ready', payload: undefined })
})
},
computed: {
@@ -208,19 +210,28 @@ export default {
},
showBrowser (wmId, url) {
this.setFlag(wmId, 'has-browser', true)
MainProcess.openAppBrowser({ url })
MainProcess.sendEvent({
name: 'OVERLAY->MAIN::show-browser',
payload: { url }
})
},
closeBrowser (wmId) {
const widget = this.widgets.find(_ => _.wmId === wmId)
if (widget.wmFlags.includes('has-browser')) {
this.setFlag(wmId, 'has-browser', false)
MainProcess.hideAppBrowser({ close: true })
MainProcess.sendEvent({
name: 'OVERLAY->MAIN::hide-browser',
payload: { close: true }
})
}
},
hideBrowser (wmId) {
const widget = this.widgets.find(_ => _.wmId === wmId)
if (widget.wmFlags.includes('has-browser')) {
MainProcess.hideAppBrowser({ close: false })
MainProcess.sendEvent({
name: 'OVERLAY->MAIN::hide-browser',
payload: { close: false }
})
}
},
setFlag (wmId, flag, state) {
+5 -2
View File
@@ -20,7 +20,7 @@
import { defineComponent, inject, reactive, computed } from 'vue'
import { WidgetManager, Anchor } from './interfaces'
import Widget from './Widget.vue'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { parseClipboard } from '@/parser'
const ITEMS = [
@@ -199,7 +199,10 @@ export default defineComponent({
})
function priceCheck (text: string) { /* eslint-disable no-console */
MainProcess.selfEmitPriceCheck({ clipboard: text, position: { x: window.screenX + 100, y: window.screenY + 100 }, lockedMode: false })
MainProcess.selfDispatch({
name: 'MAIN->OVERLAY::price-check',
payload: { clipboard: text, position: { x: window.screenX + 100, y: window.screenY + 100 }, lockedMode: false }
})
console.time('parsing item')
const parsed = parseClipboard(text)
console.timeEnd('parsing item')
+2 -3
View File
@@ -25,8 +25,7 @@
<script lang="ts">
import { computed, defineComponent, inject, PropType } from 'vue'
import Widget from './Widget.vue'
import { MainProcess } from '@/ipc/main-process-bindings'
import { TOGGLE_DELVE_GRID } from '@/ipc/ipc-event'
import { MainProcess } from '@/web/background/IPC'
import { Widget as IWidget, WidgetManager } from './interfaces'
export default defineComponent({
@@ -40,7 +39,7 @@ export default defineComponent({
setup (props) {
const wm = inject<WidgetManager>('wm')!
MainProcess.addEventListener(TOGGLE_DELVE_GRID, () => {
MainProcess.onEvent('MAIN->OVERLAY::delve-grid', () => {
if (props.config.wmWants === 'hide') {
wm.show(props.config.wmId)
} else {
+2 -2
View File
@@ -39,7 +39,7 @@ import { defineComponent, inject, PropType, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import Widget from './Widget.vue'
import DndContainer from 'vuedraggable'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { WidgetManager, ImageStripWidget } from './interfaces'
export default defineComponent({
@@ -76,7 +76,7 @@ export default defineComponent({
const target = e.target as HTMLInputElement
props.config.images.push({
id: Math.max(0, ...props.config.images.map(_ => _.id)) + 1,
url: MainProcess.importFile(target.files![0].path)
url: MainProcess.importFile(target.files![0].path)!
})
target.value = ''
},
+5 -2
View File
@@ -46,7 +46,7 @@ import { defineComponent, inject, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import Widget from './Widget.vue'
import DndContainer from 'vuedraggable'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { WidgetManager, StashSearchWidget } from './interfaces'
export default defineComponent({
@@ -87,7 +87,10 @@ export default defineComponent({
})
},
stashSearch (text: string) {
MainProcess.stashSearch(text)
MainProcess.sendEvent({
name: 'OVERLAY->MAIN::stash-search',
payload: { text }
})
}
}
}
+1 -1
View File
@@ -58,7 +58,7 @@ import FilterName from './filters/FilterName.vue'
import { CATEGORY_TO_TRADE_ID } from './trade/pathofexile-trade'
import { AppConfig } from '@/web/Config'
import { FilterTag, ItemFilters, StatFilter } from './filters/interfaces'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { PriceCheckWidget } from '../overlay/interfaces'
import { selected as selectedLeague, isPublic as isPublicLeague } from '@/web/background/Leagues'
+11 -10
View File
@@ -65,8 +65,7 @@ import { defineComponent, inject, PropType, shallowRef, watch, computed, nextTic
import { useI18n } from 'vue-i18n'
import CheckedItem from './CheckedItem.vue'
import BackgroundInfo from './BackgroundInfo.vue'
import { MainProcess } from '@/ipc/main-process-bindings'
import { IpcPriceCheck, PRICE_CHECK, PRICE_CHECK_CANCELED } from '@/ipc/ipc-event'
import { MainProcess } from '@/web/background/IPC'
import { chaosExaRate } from '../background/Prices'
import { selected as league } from '@/web/background/Leagues'
import { AppConfig } from '@/web/Config'
@@ -106,24 +105,26 @@ export default defineComponent({
const advancedCheck = shallowRef(false)
const checkPosition = shallowRef({ x: 1, y: 1 })
MainProcess.addEventListener(PRICE_CHECK, (e) => {
const _e = (e as CustomEvent<IpcPriceCheck>).detail
MainProcess.onEvent('MAIN->OVERLAY::price-check', (e) => {
wm.closeBrowser(props.config.wmId)
wm.show(props.config.wmId)
checkPosition.value = {
x: _e.position.x - window.screenX,
y: _e.position.y - window.screenY
x: e.position.x - window.screenX,
y: e.position.y - window.screenY
}
item.value = parseClipboard(_e.clipboard)
advancedCheck.value = _e.lockedMode
item.value = parseClipboard(e.clipboard)
advancedCheck.value = e.lockedMode
})
MainProcess.addEventListener(PRICE_CHECK_CANCELED, () => {
MainProcess.onEvent('MAIN->OVERLAY::price-check-canceled', () => {
wm.hide(props.config.wmId)
})
watch(() => props.config.wmWants, (state) => {
if (state === 'hide') {
MainProcess.priceCheckWidgetIsHidden()
MainProcess.sendEvent({
name: 'OVERLAY->MAIN::price-check-hide',
payload: undefined
})
}
})
@@ -64,7 +64,7 @@ import { getExternalLink, RareItemPrice, requestPoeprices } from './poeprices'
import FeedbackOption from './FeedbackOption.vue'
import ItemQuickPrice from '@/web/ui/ItemQuickPrice.vue'
import { ParsedItem } from '@/parser'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { artificialSlowdown } from '../trade/artificial-slowdown'
export default defineComponent({
@@ -1,6 +1,6 @@
import { ParsedItem } from '@/parser'
import { selected as league } from '@/web/background/Leagues'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { Cache } from '../trade/Cache'
const cache = new Cache()
+1 -1
View File
@@ -89,7 +89,7 @@
<script lang="ts">
import { defineComponent, PropType, inject, ref, computed, watch, ComputedRef, shallowRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { BulkSearch, execBulkSearch, PricingResult, requestResults } from './pathofexile-bulk'
import { getTradeEndpoint } from './common'
import { selected as league } from '../../background/Leagues'
+1 -1
View File
@@ -83,7 +83,7 @@
<script lang="ts">
import { defineComponent, computed, watch, PropType, inject, shallowReactive, shallowRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { requestTradeResultList, requestResults, createTradeRequest, PricingResult } from './pathofexile-trade'
import { getTradeEndpoint, SearchResult } from './common'
import { AppConfig } from '@/web/Config'
@@ -1,5 +1,5 @@
import { DateTime } from 'luxon'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { SearchResult, Account, getTradeEndpoint, RATE_LIMIT_RULES, adjustRateLimits, tradeTag, preventQueueCreation } from './common'
import { RateLimiter } from './RateLimiter'
import { ItemFilters } from '../filters/interfaces'
@@ -2,7 +2,7 @@ import { ItemInfluence, ItemCategory, ParsedItem, ItemRarity } from '@/parser'
import { ItemFilters, StatFilter, INTERNAL_TRADE_IDS, InternalTradeId } from '../filters/interfaces'
import prop from 'dot-prop'
import { DateTime } from 'luxon'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { SearchResult, Account, getTradeEndpoint, adjustRateLimits, RATE_LIMIT_RULES, preventQueueCreation } from './common'
import { STAT_BY_REF } from '@/assets/data'
import { RateLimiter } from './RateLimiter'
+1 -1
View File
@@ -31,7 +31,7 @@
<script lang="ts">
import { defineComponent, shallowRef, computed, Component, PropType, nextTick, inject, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { MainProcess } from '@/ipc/main-process-bindings'
import { MainProcess } from '@/web/background/IPC'
import { AppConfig, updateConfig, saveConfig } from '@/web/Config'
import type { Config } from '@/ipc/types'
import type { Widget, WidgetManager } from '@/web/overlay/interfaces'