import { Client } from 'node-ipc' ; import { ClientMessage , Reply , Error , ServerMessage } from '../../background/server/ipc' ; import { v4 } from 'uuid' ; import { Handlers } from '../../background/main' ; export type Listener < Result = unknown > = ( ... args : unknown [ ] ) => Result ; interface ReplyHandler { resolve : ( value ? : unknown ) => void ; reject : ( reason ? : unknown ) => void ; } export async function init ( ) { const socketName = await window . getServerSocket ( ) ; await connectSocket ( socketName ) ; console . log ( Date . now ( ) , 'client connected' , 'socket:' , socketName ) ; window . onbeforeunload = ( ) => { send ( 'disconnected' ) ; } ; } const replyHandlers = new Map < string , ReplyHandler > ( ) ; const listeners = new Map < string , Listener [ ] > ( ) ; let serverConnected = false ; let messageQueue = [ ] ; let socketClient = null ; export async function connectSocket ( name ) { const client = await window . ipcConnect ( name ) ; return new Promise ( resolve => { client . on ( 'message' , onMessage ) ; client . on ( 'connect' , ( ) => onConnect ( client , resolve ) ) ; client . on ( 'disconnect' , ( ) => { socketClient = null ; } ) ; } ) ; } function onMessage ( data ) { const msg = JSON . parse ( data ) ; console . log ( Date . now ( ) , 'client received:' , msg ) ; if ( msg . type === 'error' || msg . type === 'reply' ) { handleResponse ( msg ) ; } else if ( msg . type === 'push' ) { const listens = listeners . get ( msg . name ) ; if ( listens ) { listens . forEach ( listener => listener ( ... msg . args ) ) ; } } else { throw new Error ( 'Unknown message type: ' + JSON . stringify ( msg ) ) ; } } function handleResponse ( msg ) { const handler = replyHandlers . get ( msg . id ) ; if ( ! handler ) return ; if ( msg . type === 'reply' ) { handler . resolve ( msg . result ) ; } else { handler . reject ( ) ; } replyHandlers . delete ( msg . id ) ; } function onConnect ( client , onOpen ) { socketClient = client ; socketClient . emit ( 'message' , JSON . stringify ( { id : v4 ( ) , name : 'connected' , args : [ ] } ) ) ; listen ( 'connected' , ( ) => { if ( serverConnected ) { return ; } serverConnected = true ; send ( 'connected' ) ; if ( messageQueue . length > 0 ) { messageQueue . forEach ( msg => client . emit ( 'message' , msg ) ) ; messageQueue = [ ] ; } } ) ; onOpen ( ) ; } export function send < T extends keyof Handlers > ( name ) ; export function send < T extends keyof Handlers > ( name , ... args ) ; export function send < T extends keyof Handlers > ( name , ... args ) { return new Promise ( ( resolve , reject ) => { const id = v4 ( ) ; const msg = { id , name , args } ; const stringMsg = JSON . stringify ( msg ) ; replyHandlers . set ( id , { resolve , reject } ) ; if ( socketClient && serverConnected ) { socketClient . emit ( 'message' , stringMsg ) ; console . log ( Date . now ( ) , 'client sending:' , msg ) ; } else { messageQueue . push ( stringMsg ) ; } } ) as ReturnType < Handlers [ T ] > ; } export function listen ( name , listener ) { if ( ! listeners . get ( name ) ) { listeners . set ( name , [ ] ) ; } listeners . get ( name ) . push ( listener ) ; return ( ) => { const arr = listeners . get ( name ) ; listeners . set ( name , arr . filter ( func => func !== listener ) ) ; } ; } export function unlisten ( name ) { listeners . set ( name , [ ] ) ; }