ogi-addon 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/main.ts","../src/config/ConfigurationBuilder.ts","../src/config/Configuration.ts","../src/EventResponse.ts"],"sourcesContent":["import ws, { WebSocket } from 'ws';\r\nimport events from 'node:events';\r\nimport { ConfigurationBuilder, ConfigurationFile } from './config/ConfigurationBuilder';\r\nimport { Configuration } from './config/Configuration';\r\nimport EventResponse from './EventResponse';\r\nimport { SearchResult } from './SearchEngine';\r\n\r\nexport type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';\r\nexport type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification';\r\n\r\nexport type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup';\r\nexport { ConfigurationBuilder, Configuration, EventResponse, SearchResult };\r\nconst defaultPort = 7654;\r\n\r\nexport interface ClientSentEventTypes {\r\n response: any;\r\n authenticate: any;\r\n configure: ConfigurationFile;\r\n 'defer-update': {\r\n logs: string[], \r\n progress: number\r\n };\r\n notification: Notification;\r\n}\r\n\r\nexport interface EventListenerTypes {\r\n connect: (socket: ws) => void;\r\n disconnect: (reason: string) => void;\r\n configure: (config: ConfigurationBuilder) => ConfigurationBuilder;\r\n response: (response: any) => void;\r\n authenticate: (config: any) => void;\r\n search: (query: string, event: EventResponse<SearchResult[]>) => void;\r\n setup: (\r\n data: { \r\n path: string, \r\n type: 'direct' | 'torrent' | 'magnet',\r\n name: string,\r\n usedRealDebrid: boolean, \r\n multiPartFiles?: {\r\n name: string,\r\n downloadURL: string\r\n }[],\r\n }, event: EventResponse<undefined | null>\r\n ) => void;\r\n}\r\n\r\nexport interface WebsocketMessageClient {\r\n event: OGIAddonClientSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface WebsocketMessageServer {\r\n event: OGIAddonServerSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface OGIAddonConfiguration {\r\n name: string;\r\n id: string;\r\n description: string;\r\n version: string;\r\n\r\n author: string;\r\n repository: string;\r\n}\r\nexport default class OGIAddon {\r\n public eventEmitter = new events.EventEmitter();\r\n public addonWSListener: OGIAddonWSListener;\r\n public addonInfo: OGIAddonConfiguration;\r\n public config: Configuration = new Configuration({});\r\n\r\n constructor(addonInfo: OGIAddonConfiguration) {\r\n this.addonInfo = addonInfo;\r\n this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);\r\n }\r\n \r\n public on<T extends OGIAddonEvent>(event: T, listener: EventListenerTypes[T]) {\r\n this.eventEmitter.on(event, listener);\r\n }\r\n\r\n public emit<T extends OGIAddonEvent>(event: T, ...args: Parameters<EventListenerTypes[T]>) {\r\n this.eventEmitter.emit(event, ...args);\r\n }\r\n\r\n public notify(notification: Notification) {\r\n this.addonWSListener.send('notification', [ notification ]);\r\n }\r\n}\r\ninterface Notification {\r\n type: 'warning' | 'error' | 'info' | 'success';\r\n message: string;\r\n id: string\r\n}\r\nclass OGIAddonWSListener {\r\n private socket: WebSocket;\r\n public eventEmitter: events.EventEmitter;\r\n public addon: OGIAddon;\r\n\r\n constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter) {\r\n if (process.argv[process.argv.length - 1].split('=')[0] !== '--addonSecret') {\r\n throw new Error('No secret provided. This usually happens because the addon was not started by the OGI Addon Server.');\r\n }\r\n this.addon = ogiAddon;\r\n this.eventEmitter = eventEmitter;\r\n this.socket = new ws('ws://localhost:' + defaultPort);\r\n this.socket.on('open', () => {\r\n console.log('Connected to OGI Addon Server');\r\n\r\n // Authenticate with OGI Addon Server\r\n this.socket.send(JSON.stringify({\r\n event: 'authenticate',\r\n args: {\r\n ...this.addon.addonInfo,\r\n secret: process.argv[process.argv.length - 1].split('=')[1]\r\n }\r\n }));\r\n\r\n this.eventEmitter.emit('connect');\r\n\r\n // send a configuration request\r\n let configBuilder = new ConfigurationBuilder();\r\n this.eventEmitter.emit('configure', configBuilder);\r\n \r\n this.socket.send(JSON.stringify({\r\n event: 'configure',\r\n args: configBuilder.build(false) \r\n }));\r\n this.addon.config = new Configuration(configBuilder.build(true));\r\n });\r\n\r\n this.socket.on('error', (error) => {\r\n if (error.message.includes('Failed to connect')) {\r\n throw new Error('OGI Addon Server is not running/is unreachable. Please start the server and try again.');\r\n }\r\n console.error('An error occurred:', error);\r\n })\r\n\r\n this.socket.on('close', (code, reason) => {\r\n if (code === 1008) {\r\n console.error('Authentication failed:', reason);\r\n return;\r\n }\r\n this.eventEmitter.emit('disconnect', reason);\r\n console.log(\"Disconnected from OGI Addon Server\")\r\n this.socket.close();\r\n });\r\n\r\n this.registerMessageReceiver();\r\n }\r\n\r\n private registerMessageReceiver() {\r\n this.socket.on('message', async (data: string) => {\r\n const message: WebsocketMessageServer = JSON.parse(data);\r\n switch (message.event) {\r\n case 'config-update':\r\n const result = this.addon.config.updateConfig(message.args);\r\n if (!result[0]) {\r\n this.respondToMessage(message.id!!, { success: false, error: result[1] });\r\n }\r\n else {\r\n this.respondToMessage(message.id!!, { success: true });\r\n }\r\n break \r\n case 'search':\r\n let searchResultEvent = new EventResponse<SearchResult[]>();\r\n this.eventEmitter.emit('search', message.args, searchResultEvent);\r\n const searchResult = await this.waitForEventToRespond(searchResultEvent); \r\n console.log(searchResult.data)\r\n this.respondToMessage(message.id!!, searchResult.data);\r\n break\r\n case 'setup':\r\n let setupEvent = new EventResponse<undefined | null>();\r\n this.eventEmitter.emit('setup', { path: message.args.path, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);\r\n const interval = setInterval(() => {\r\n if (setupEvent.resolved) {\r\n clearInterval(interval);\r\n return;\r\n }\r\n this.send('defer-update', { \r\n logs: setupEvent.logs,\r\n deferID: message.args.deferID,\r\n progress: setupEvent.progress\r\n } as any);\r\n }, 100);\r\n const setupResult = await this.waitForEventToRespond(setupEvent);\r\n this.respondToMessage(message.id!!, setupResult.data);\r\n break\r\n }\r\n });\r\n }\r\n\r\n private waitForEventToRespond<T>(event: EventResponse<T>): Promise<EventResponse<T>> {\r\n return new Promise((resolve, reject) => {\r\n const dataGet = setInterval(() => {\r\n if (event.resolved) {\r\n resolve(event);\r\n clearTimeout(timeout);\r\n }\r\n }, 5); \r\n\r\n const timeout = setTimeout(() => {\r\n if (event.deffered) {\r\n clearInterval(dataGet);\r\n const interval = setInterval(() => {\r\n if (event.resolved) {\r\n clearInterval(interval);\r\n resolve(event);\r\n }\r\n }, 100);\r\n }\r\n else {\r\n reject('Event did not respond in time');\r\n }\r\n }, 5000)\r\n });\r\n }\r\n\r\n public respondToMessage(messageID: string, response: any) {\r\n this.socket.send(JSON.stringify({\r\n event: 'response',\r\n id: messageID,\r\n args: response\r\n }));\r\n console.log(\"dispatched response to \" + messageID)\r\n }\r\n\r\n public send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>) {\r\n this.socket.send(JSON.stringify({\r\n event,\r\n args\r\n }));\r\n }\r\n\r\n public close() {\r\n this.socket.close();\r\n }\r\n\r\n \r\n}","import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}","import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\r\n\r\ninterface DefiniteConfig {\r\n [key: string]: string | number | boolean;\r\n}\r\nexport class Configuration {\r\n readonly storedConfigTemplate: ConfigurationFile;\r\n definiteConfig: DefiniteConfig = {};\r\n constructor(configTemplate: ConfigurationFile) {\r\n this.storedConfigTemplate = configTemplate;\r\n }\r\n\r\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\r\n this.definiteConfig = config;\r\n if (validate) {\r\n const result = this.validateConfig();\r\n return result;\r\n }\r\n return [ true, {} ];\r\n }\r\n // provides falsey or truthy value, and an error message if falsey\r\n private validateConfig(): [ boolean, { [key: string]: string } ] {\r\n const erroredKeys = new Map<string, string>();\r\n for (const key in this.storedConfigTemplate) {\r\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\r\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\r\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\r\n }\r\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\r\n throw new Error('Option ' + key + ' is not of the correct type');\r\n }\r\n\r\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\r\n if (!result[0]) {\r\n erroredKeys.set(key, result[1]);\r\n }\r\n }\r\n\r\n for (const key in this.definiteConfig) {\r\n if (!this.storedConfigTemplate[key]) {\r\n throw new Error('Option ' + key + ' is not defined in the configuration template');\r\n }\r\n }\r\n\r\n if (erroredKeys.size > 0) {\r\n return [ false, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n return [ true, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n getStringValue(optionName: string): string {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'string') {\r\n throw new Error('Option ' + optionName + ' is not a string');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getNumberValue(optionName: string): number {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'number') {\r\n throw new Error('Option ' + optionName + ' is not a number');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getBooleanValue(optionName: string): boolean {\r\n if (this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\r\n throw new Error('Option ' + optionName + ' is not a boolean');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n}\r\n\r\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };","export default class EventResponse<T> {\r\n data: T | undefined = undefined;\r\n deffered: boolean = false;\r\n resolved: boolean = false;\r\n progress: number = 0;\r\n logs: string[] = [];\r\n\r\n public defer() {\r\n this.deffered = true;\r\n }\r\n\r\n public resolve(data: T) {\r\n this.resolved = true;\r\n this.data = data;\r\n }\r\n\r\n public complete() {\r\n this.resolved = true;\r\n }\r\n\r\n public log(message: string) {\r\n this.logs.push(message);\r\n }\r\n\r\n \r\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAA8B;AAC9B,yBAAmB;;;ACDnB,iBAA4B;AAM5B,IAAM,mBAAmB,WAAAA,QAAE,OAAO;AAAA,EAChC,MAAM,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAa,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,aAAa,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAC/B,CAAC;AAcM,IAAM,uBAAN,MAA2B;AAAA,EACxB,UAAiC,CAAC;AAAA,EACnC,gBAAgB,QAAsE;AAC3F,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,gBAAgB,QAAgD;AACrE,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,iBAAiB,QAAkD;AACxE,QAAI,YAAY,IAAI,cAAc;AAClC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,MAAM,kBAA8C;AACzD,QAAI,SAA4B,CAAC;AACjC,SAAK,QAAQ,QAAQ,YAAU;AAE7B,UAAI,CAAC,kBAAkB;AACrB,iBAAS,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAC1C,cAAM,aAAa,iBAAiB,UAAU,MAAM;AACpD,YAAI,CAAC,WAAW,SAAS;AACvB,gBAAM,IAAI,oBAAS,WAAW,MAAM,MAAM;AAAA,QAC5C;AAEA,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB,OACK;AACH,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAGO,IAAM,sBAAN,MAA0B;AAAA,EACxB,OAAe;AAAA,EACf,eAAwB;AAAA,EACxB,cAAsB;AAAA,EACtB,cAAsB;AAAA,EACtB,OAAgC;AAAA,EAEvC,QAAQ,MAAc;AACpB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA,EAGA,SAAS,OAAqC;AAC5C,UAAM,IAAI,MAAM,6CAA6C,KAAK;AAAA,EACpE;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,gBAA0B,CAAC;AAAA,EAC3B,gBAAwB;AAAA,EACxB,gBAAwB,OAAO;AAAA,EAC/B,eAAuB;AAAA,EACvB,OAAgC;AAAA,EAEvC,iBAAiB,eAA+B;AAC9C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,KAAK,cAAc,WAAW,KAAK,MAAM,WAAW;AACtD,aAAO,CAAE,MAAM,EAAG;AACpB,QAAI,MAAM,SAAS,KAAK,iBAAiB,MAAM,SAAS,KAAK,eAAe;AAC1E,aAAO,CAAE,OAAO,yCAAyC,KAAK,gBAAgB,UAAU,KAAK,gBAAgB,4BAA4B,MAAM,SAAS,cAAe;AAAA,IACzK;AAEA,WAAO,CAAE,KAAK,cAAc,SAAS,KAAK,GAAG,+BAAgC;AAAA,EAC/E;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,MAAc;AAAA,EACd,MAAc,OAAO;AAAA,EACrB,eAAuB;AAAA,EACvB,OAAgC;AAAA,EAChC,YAAgC;AAAA,EACvC,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,MAAgC;AAC3C,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA,EAEA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,MAAM,OAAO,KAAK,CAAC,GAAG;AACxB,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,OAAO,KAAK,IAAI,KAAK,OAAO,OAAO,KAAK,IAAI,KAAK,KAAK;AACxD,aAAO,CAAE,OAAO,sCAAsC,KAAK,MAAM,UAAU,KAAK,GAAI;AAAA,IACtF;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;AAEO,IAAM,gBAAN,cAA4B,oBAAoB;AAAA,EAC9C,OAAgC;AAAA,EAChC,eAAwB;AAAA,EAE/B,gBAAgB,cAA6B;AAC3C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,WAAW;AAC9B,aAAO,CAAE,OAAO,wBAAyB;AAAA,IAC3C;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;;;AC3LO,IAAM,gBAAN,MAAoB;AAAA,EAChB;AAAA,EACT,iBAAiC,CAAC;AAAA,EAClC,YAAY,gBAAmC;AAC7C,SAAK,uBAAuB;AAAA,EAC9B;AAAA,EAEA,aAAa,QAAwB,WAAoB,MAA8C;AACrG,SAAK,iBAAiB;AACtB,QAAI,UAAU;AACZ,YAAM,SAAS,KAAK,eAAe;AACnC,aAAO;AAAA,IACT;AACA,WAAO,CAAE,MAAM,CAAC,CAAE;AAAA,EACpB;AAAA;AAAA,EAEQ,iBAAyD;AAC/D,UAAM,cAAc,oBAAI,IAAoB;AAC5C,eAAW,OAAO,KAAK,sBAAsB;AAC3C,UAAI,KAAK,eAAe,GAAG,MAAM,QAAQ,KAAK,eAAe,GAAG,MAAM,QAAW;AAC/E,gBAAQ,KAAK,YAAY,MAAM,iDAAiD,KAAK,eAAe,GAAG,CAAC;AACxG,aAAK,eAAe,GAAG,IAAI,KAAK,qBAAqB,GAAG,EAAE;AAAA,MAC5D;AACA,UAAI,KAAK,qBAAqB,GAAG,EAAE,SAAS,OAAO,KAAK,eAAe,GAAG,GAAG;AAC3E,cAAM,IAAI,MAAM,YAAY,MAAM,6BAA6B;AAAA,MACjE;AAEA,YAAM,SAAS,KAAK,qBAAqB,GAAG,EAAE,SAAS,KAAK,eAAe,GAAG,CAAC;AAC/E,UAAI,CAAC,OAAO,CAAC,GAAG;AACd,oBAAY,IAAI,KAAK,OAAO,CAAC,CAAC;AAAA,MAChC;AAAA,IACF;AAEA,eAAW,OAAO,KAAK,gBAAgB;AACrC,UAAI,CAAC,KAAK,qBAAqB,GAAG,GAAG;AACnC,cAAM,IAAI,MAAM,YAAY,MAAM,+CAA+C;AAAA,MACnF;AAAA,IACF;AAEA,QAAI,YAAY,OAAO,GAAG;AACxB,aAAO,CAAE,OAAO,OAAO,YAAY,WAAW,CAAE;AAAA,IAClD;AAEA,WAAO,CAAE,MAAM,OAAO,YAAY,WAAW,CAAE;AAAA,EACjD;AAAA,EAEA,eAAe,YAA4B;AACzC,QAAI,CAAC,KAAK,eAAe,UAAU,MAAM,MAAM;AAC7C,YAAM,IAAI,MAAM,YAAY,aAAa,iBAAiB;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,eAAe,UAAU,MAAM,UAAU;AACvD,YAAM,IAAI,MAAM,YAAY,aAAa,kBAAkB;AAAA,IAC7D;AACA,WAAO,KAAK,eAAe,UAAU;AAAA,EACvC;AAAA,EAEA,eAAe,YAA4B;AACzC,QAAI,CAAC,KAAK,eAAe,UAAU,MAAM,MAAM;AAC7C,YAAM,IAAI,MAAM,YAAY,aAAa,iBAAiB;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,eAAe,UAAU,MAAM,UAAU;AACvD,YAAM,IAAI,MAAM,YAAY,aAAa,kBAAkB;AAAA,IAC7D;AACA,WAAO,KAAK,eAAe,UAAU;AAAA,EACvC;AAAA,EAEA,gBAAgB,YAA6B;AAC3C,QAAI,KAAK,eAAe,UAAU,MAAM,MAAM;AAC5C,YAAM,IAAI,MAAM,YAAY,aAAa,iBAAiB;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,eAAe,UAAU,MAAM,WAAW;AACxD,YAAM,IAAI,MAAM,YAAY,aAAa,mBAAmB;AAAA,IAC9D;AACA,WAAO,KAAK,eAAe,UAAU;AAAA,EACvC;AACF;;;AChFA,IAAqB,gBAArB,MAAsC;AAAA,EACpC,OAAsB;AAAA,EACtB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAmB;AAAA,EACnB,OAAiB,CAAC;AAAA,EAEX,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA,EAEO,QAAQ,MAAS;AACtB,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA,EACd;AAAA,EAEO,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEO,IAAI,SAAiB;AAC1B,SAAK,KAAK,KAAK,OAAO;AAAA,EACxB;AAGF;;;AHbA,IAAM,cAAc;AAqDpB,IAAqB,WAArB,MAA8B;AAAA,EACrB,eAAe,IAAI,mBAAAC,QAAO,aAAa;AAAA,EACvC;AAAA,EACA;AAAA,EACA,SAAwB,IAAI,cAAc,CAAC,CAAC;AAAA,EAEnD,YAAY,WAAkC;AAC5C,SAAK,YAAY;AACjB,SAAK,kBAAkB,IAAI,mBAAmB,MAAM,KAAK,YAAY;AAAA,EACvE;AAAA,EAEO,GAA4B,OAAU,UAAiC;AAC5E,SAAK,aAAa,GAAG,OAAO,QAAQ;AAAA,EACtC;AAAA,EAEO,KAA8B,UAAa,MAAyC;AACzF,SAAK,aAAa,KAAK,OAAO,GAAG,IAAI;AAAA,EACvC;AAAA,EAEO,OAAO,cAA4B;AACxC,SAAK,gBAAgB,KAAK,gBAAgB,CAAE,YAAa,CAAC;AAAA,EAC5D;AACF;AAMA,IAAM,qBAAN,MAAyB;AAAA,EACf;AAAA,EACD;AAAA,EACA;AAAA,EAEP,YAAY,UAAoB,cAAmC;AACjE,QAAI,QAAQ,KAAK,QAAQ,KAAK,SAAS,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,MAAM,iBAAiB;AAC3E,YAAM,IAAI,MAAM,qGAAqG;AAAA,IACvH;AACA,SAAK,QAAQ;AACb,SAAK,eAAe;AACpB,SAAK,SAAS,IAAI,UAAAC,QAAG,oBAAoB,WAAW;AACpD,SAAK,OAAO,GAAG,QAAQ,MAAM;AAC3B,cAAQ,IAAI,+BAA+B;AAG3C,WAAK,OAAO,KAAK,KAAK,UAAU;AAAA,QAC9B,OAAO;AAAA,QACP,MAAM;AAAA,UACJ,GAAG,KAAK,MAAM;AAAA,UACd,QAAQ,QAAQ,KAAK,QAAQ,KAAK,SAAS,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QAC5D;AAAA,MACF,CAAC,CAAC;AAEF,WAAK,aAAa,KAAK,SAAS;AAGhC,UAAI,gBAAgB,IAAI,qBAAqB;AAC7C,WAAK,aAAa,KAAK,aAAa,aAAa;AAEjD,WAAK,OAAO,KAAK,KAAK,UAAU;AAAA,QAC9B,OAAO;AAAA,QACP,MAAM,cAAc,MAAM,KAAK;AAAA,MACjC,CAAC,CAAC;AACF,WAAK,MAAM,SAAS,IAAI,cAAc,cAAc,MAAM,IAAI,CAAC;AAAA,IACjE,CAAC;AAED,SAAK,OAAO,GAAG,SAAS,CAAC,UAAU;AACjC,UAAI,MAAM,QAAQ,SAAS,mBAAmB,GAAG;AAC/C,cAAM,IAAI,MAAM,wFAAwF;AAAA,MAC1G;AACA,cAAQ,MAAM,sBAAsB,KAAK;AAAA,IAC3C,CAAC;AAED,SAAK,OAAO,GAAG,SAAS,CAAC,MAAM,WAAW;AACxC,UAAI,SAAS,MAAM;AACjB,gBAAQ,MAAM,0BAA0B,MAAM;AAC9C;AAAA,MACF;AACA,WAAK,aAAa,KAAK,cAAc,MAAM;AAC3C,cAAQ,IAAI,oCAAoC;AAChD,WAAK,OAAO,MAAM;AAAA,IACpB,CAAC;AAED,SAAK,wBAAwB;AAAA,EAC/B;AAAA,EAEQ,0BAA0B;AAChC,SAAK,OAAO,GAAG,WAAW,OAAO,SAAiB;AAChD,YAAM,UAAkC,KAAK,MAAM,IAAI;AACvD,cAAQ,QAAQ,OAAO;AAAA,QACrB,KAAK;AACH,gBAAM,SAAS,KAAK,MAAM,OAAO,aAAa,QAAQ,IAAI;AAC1D,cAAI,CAAC,OAAO,CAAC,GAAG;AACd,iBAAK,iBAAiB,QAAQ,IAAM,EAAE,SAAS,OAAO,OAAO,OAAO,CAAC,EAAE,CAAC;AAAA,UAC1E,OACK;AACH,iBAAK,iBAAiB,QAAQ,IAAM,EAAE,SAAS,KAAK,CAAC;AAAA,UACvD;AACA;AAAA,QACF,KAAK;AACH,cAAI,oBAAoB,IAAI,cAA8B;AAC1D,eAAK,aAAa,KAAK,UAAU,QAAQ,MAAM,iBAAiB;AAChE,gBAAM,eAAe,MAAM,KAAK,sBAAsB,iBAAiB;AACvE,kBAAQ,IAAI,aAAa,IAAI;AAC7B,eAAK,iBAAiB,QAAQ,IAAM,aAAa,IAAI;AACrD;AAAA,QACF,KAAK;AACH,cAAI,aAAa,IAAI,cAAgC;AACrD,eAAK,aAAa,KAAK,SAAS,EAAE,MAAM,QAAQ,KAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,gBAAgB,QAAQ,KAAK,gBAAgB,gBAAgB,QAAQ,KAAK,eAAe,GAAG,UAAU;AACnN,gBAAM,WAAW,YAAY,MAAM;AACjC,gBAAI,WAAW,UAAU;AACvB,4BAAc,QAAQ;AACtB;AAAA,YACF;AACA,iBAAK,KAAK,gBAAgB;AAAA,cACxB,MAAM,WAAW;AAAA,cACjB,SAAS,QAAQ,KAAK;AAAA,cACtB,UAAU,WAAW;AAAA,YACvB,CAAQ;AAAA,UACV,GAAG,GAAG;AACN,gBAAM,cAAc,MAAM,KAAK,sBAAsB,UAAU;AAC/D,eAAK,iBAAiB,QAAQ,IAAM,YAAY,IAAI;AACpD;AAAA,MACJ;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,sBAAyB,OAAoD;AACnF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,UAAU,YAAY,MAAM;AAChC,YAAI,MAAM,UAAU;AAClB,kBAAQ,KAAK;AACb,uBAAa,OAAO;AAAA,QACtB;AAAA,MACF,GAAG,CAAC;AAEJ,YAAM,UAAU,WAAW,MAAM;AAC/B,YAAI,MAAM,UAAU;AAClB,wBAAc,OAAO;AACrB,gBAAM,WAAW,YAAY,MAAM;AACjC,gBAAI,MAAM,UAAU;AAClB,4BAAc,QAAQ;AACtB,sBAAQ,KAAK;AAAA,YACf;AAAA,UACF,GAAG,GAAG;AAAA,QACR,OACK;AACH,iBAAO,+BAA+B;AAAA,QACxC;AAAA,MACF,GAAG,GAAI;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEO,iBAAiB,WAAmB,UAAe;AACxD,SAAK,OAAO,KAAK,KAAK,UAAU;AAAA,MAC9B,OAAO;AAAA,MACP,IAAI;AAAA,MACJ,MAAM;AAAA,IACR,CAAC,CAAC;AACF,YAAQ,IAAI,4BAA4B,SAAS;AAAA,EACnD;AAAA,EAEO,KAAK,OAAgC,MAAiE;AAC3G,SAAK,OAAO,KAAK,KAAK,UAAU;AAAA,MAC9B;AAAA,MACA;AAAA,IACF,CAAC,CAAC;AAAA,EACJ;AAAA,EAEO,QAAQ;AACb,SAAK,OAAO,MAAM;AAAA,EACpB;AAGF;","names":["z","events","ws"]}
1
+ {"version":3,"sources":["../src/main.ts","../src/config/ConfigurationBuilder.ts","../src/config/Configuration.ts","../src/EventResponse.ts"],"sourcesContent":["import ws, { WebSocket } from 'ws';\r\nimport events from 'node:events';\r\nimport { ConfigurationBuilder, ConfigurationFile } from './config/ConfigurationBuilder';\r\nimport { Configuration } from './config/Configuration';\r\nimport EventResponse from './EventResponse';\r\nimport { SearchResult } from './SearchEngine';\r\n\r\nexport type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';\r\nexport type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification' | 'input-asked';\r\n\r\nexport type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup' | 'response';\r\nexport { ConfigurationBuilder, Configuration, EventResponse, SearchResult };\r\nconst defaultPort = 7654;\r\nconst version = process.env.npm_package_version;\r\n\r\nexport interface ClientSentEventTypes {\r\n response: any;\r\n authenticate: any;\r\n configure: ConfigurationFile;\r\n 'defer-update': {\r\n logs: string[], \r\n progress: number\r\n };\r\n notification: Notification;\r\n 'input-asked': ConfigurationBuilder;\r\n}\r\n\r\nexport interface EventListenerTypes {\r\n connect: (socket: ws) => void;\r\n disconnect: (reason: string) => void;\r\n configure: (config: ConfigurationBuilder) => ConfigurationBuilder;\r\n response: (response: any) => void;\r\n authenticate: (config: any) => void;\r\n search: (query: { type: 'steamapp', text: string }, event: EventResponse<SearchResult[]>) => void;\r\n setup: (\r\n data: { \r\n path: string, \r\n type: 'direct' | 'torrent' | 'magnet',\r\n name: string,\r\n usedRealDebrid: boolean, \r\n multiPartFiles?: {\r\n name: string,\r\n downloadURL: string\r\n }[],\r\n steamAppID: number\r\n }, event: EventResponse<LibraryInfo>\r\n ) => void;\r\n}\r\n\r\nexport interface WebsocketMessageClient {\r\n event: OGIAddonClientSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface WebsocketMessageServer {\r\n event: OGIAddonServerSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface OGIAddonConfiguration {\r\n name: string;\r\n id: string;\r\n description: string;\r\n version: string;\r\n\r\n author: string;\r\n repository: string;\r\n}\r\nexport default class OGIAddon {\r\n public eventEmitter = new events.EventEmitter();\r\n public addonWSListener: OGIAddonWSListener;\r\n public addonInfo: OGIAddonConfiguration;\r\n public config: Configuration = new Configuration({});\r\n\r\n constructor(addonInfo: OGIAddonConfiguration) {\r\n this.addonInfo = addonInfo;\r\n this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);\r\n }\r\n \r\n public on<T extends OGIAddonEvent>(event: T, listener: EventListenerTypes[T]) {\r\n this.eventEmitter.on(event, listener);\r\n }\r\n\r\n public emit<T extends OGIAddonEvent>(event: T, ...args: Parameters<EventListenerTypes[T]>) {\r\n this.eventEmitter.emit(event, ...args);\r\n }\r\n\r\n public notify(notification: Notification) {\r\n this.addonWSListener.send('notification', [ notification ]);\r\n }\r\n}\r\n\r\nexport interface LibraryInfo {\r\n name: string;\r\n version: string;\r\n cwd: string;\r\n steamAppID: number;\r\n launchExecutable: string;\r\n launchArguments?: string;\r\n capsuleImage: string;\r\n}\r\ninterface Notification {\r\n type: 'warning' | 'error' | 'info' | 'success';\r\n message: string;\r\n id: string\r\n}\r\nclass OGIAddonWSListener {\r\n private socket: WebSocket;\r\n public eventEmitter: events.EventEmitter;\r\n public addon: OGIAddon;\r\n\r\n constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter) {\r\n if (process.argv[process.argv.length - 1].split('=')[0] !== '--addonSecret') {\r\n throw new Error('No secret provided. This usually happens because the addon was not started by the OGI Addon Server.');\r\n }\r\n this.addon = ogiAddon;\r\n this.eventEmitter = eventEmitter;\r\n this.socket = new ws('ws://localhost:' + defaultPort);\r\n this.socket.on('open', () => {\r\n console.log('Connected to OGI Addon Server');\r\n console.log('OGI Addon Server Version:', version);\r\n\r\n // Authenticate with OGI Addon Server\r\n this.socket.send(JSON.stringify({\r\n event: 'authenticate',\r\n args: {\r\n ...this.addon.addonInfo,\r\n secret: process.argv[process.argv.length - 1].split('=')[1],\r\n ogiVersion: version\r\n }\r\n }));\r\n\r\n this.eventEmitter.emit('connect');\r\n\r\n // send a configuration request\r\n let configBuilder = new ConfigurationBuilder();\r\n this.eventEmitter.emit('configure', configBuilder);\r\n \r\n this.socket.send(JSON.stringify({\r\n event: 'configure',\r\n args: configBuilder.build(false) \r\n }));\r\n this.addon.config = new Configuration(configBuilder.build(true));\r\n });\r\n\r\n this.socket.on('error', (error) => {\r\n if (error.message.includes('Failed to connect')) {\r\n throw new Error('OGI Addon Server is not running/is unreachable. Please start the server and try again.');\r\n }\r\n console.error('An error occurred:', error);\r\n })\r\n\r\n this.socket.on('close', (code, reason) => {\r\n if (code === 1008) {\r\n console.error('Authentication failed:', reason);\r\n return;\r\n }\r\n this.eventEmitter.emit('disconnect', reason);\r\n console.log(\"Disconnected from OGI Addon Server\")\r\n console.log(reason.toString())\r\n this.socket.close();\r\n });\r\n\r\n this.registerMessageReceiver();\r\n }\r\n\r\n private async userInputAsked(configBuilt: ConfigurationBuilder, name: string, description: string, socket: WebSocket): Promise<{ [key: string]: number | boolean | string }> {\r\n const config = configBuilt.build(false);\r\n const id = Math.random().toString(36).substring(7);\r\n if (!socket) {\r\n return {};\r\n }\r\n socket.send(JSON.stringify({\r\n event: 'input-asked',\r\n args: {\r\n config,\r\n name,\r\n description\r\n },\r\n id: id\r\n }));\r\n return await this.waitForResponseFromServer(id);\r\n }\r\n\r\n private registerMessageReceiver() {\r\n this.socket.on('message', async (data: string) => {\r\n const message: WebsocketMessageServer = JSON.parse(data);\r\n switch (message.event) {\r\n case 'config-update':\r\n const result = this.addon.config.updateConfig(message.args);\r\n if (!result[0]) {\r\n this.respondToMessage(message.id!!, { success: false, error: result[1] });\r\n }\r\n else {\r\n this.respondToMessage(message.id!!, { success: true });\r\n }\r\n break \r\n case 'search':\r\n let searchResultEvent = new EventResponse<SearchResult[]>((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));\r\n this.eventEmitter.emit('search', message.args, searchResultEvent);\r\n const searchResult = await this.waitForEventToRespond(searchResultEvent); \r\n console.log(searchResult.data)\r\n this.respondToMessage(message.id!!, searchResult.data);\r\n break\r\n case 'setup':\r\n let setupEvent = new EventResponse<LibraryInfo>((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));\r\n this.eventEmitter.emit('setup', { path: message.args.path, steamAppID: message.args.steamAppID, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);\r\n const interval = setInterval(() => {\r\n if (setupEvent.resolved) {\r\n clearInterval(interval);\r\n return;\r\n }\r\n this.send('defer-update', { \r\n logs: setupEvent.logs,\r\n deferID: message.args.deferID,\r\n progress: setupEvent.progress\r\n } as any);\r\n }, 100);\r\n const setupResult = await this.waitForEventToRespond(setupEvent);\r\n this.respondToMessage(message.id!!, setupResult.data);\r\n break\r\n }\r\n });\r\n }\r\n\r\n private waitForEventToRespond<T>(event: EventResponse<T>): Promise<EventResponse<T>> {\r\n return new Promise((resolve, reject) => {\r\n const dataGet = setInterval(() => {\r\n if (event.resolved) {\r\n resolve(event);\r\n clearTimeout(timeout);\r\n }\r\n }, 5); \r\n\r\n const timeout = setTimeout(() => {\r\n if (event.deffered) {\r\n clearInterval(dataGet);\r\n const interval = setInterval(() => {\r\n if (event.resolved) {\r\n clearInterval(interval);\r\n resolve(event);\r\n }\r\n }, 100);\r\n }\r\n else {\r\n reject('Event did not respond in time');\r\n }\r\n }, 5000)\r\n });\r\n }\r\n\r\n public respondToMessage(messageID: string, response: any) {\r\n this.socket.send(JSON.stringify({\r\n event: 'response',\r\n id: messageID,\r\n args: response\r\n }));\r\n console.log(\"dispatched response to \" + messageID)\r\n }\r\n\r\n public waitForResponseFromServer<T>(messageID: string): Promise<T> {\r\n return new Promise((resolve) => {\r\n const waiter = (data: string) => {\r\n const message: WebsocketMessageClient = JSON.parse(data);\r\n if (message.event !== 'response') {\r\n this.socket.once('message', waiter);\r\n return;\r\n }\r\n console.log(\"received response from \" + messageID)\r\n\r\n if (message.id === messageID) {\r\n resolve(message.args);\r\n }\r\n else {\r\n this.socket.once('message', waiter);\r\n }\r\n }\r\n this.socket.once('message', waiter);\r\n });\r\n }\r\n\r\n public send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>) {\r\n this.socket.send(JSON.stringify({\r\n event,\r\n args\r\n }));\r\n }\r\n\r\n public close() {\r\n this.socket.close();\r\n }\r\n\r\n \r\n}","import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\r\n this.inputType = inputType;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}","import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\r\n\r\ninterface DefiniteConfig {\r\n [key: string]: string | number | boolean;\r\n}\r\nexport class Configuration {\r\n readonly storedConfigTemplate: ConfigurationFile;\r\n definiteConfig: DefiniteConfig = {};\r\n constructor(configTemplate: ConfigurationFile) {\r\n this.storedConfigTemplate = configTemplate;\r\n }\r\n\r\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\r\n this.definiteConfig = config;\r\n if (validate) {\r\n const result = this.validateConfig();\r\n return result;\r\n }\r\n return [ true, {} ];\r\n }\r\n // provides falsey or truthy value, and an error message if falsey\r\n private validateConfig(): [ boolean, { [key: string]: string } ] {\r\n const erroredKeys = new Map<string, string>();\r\n for (const key in this.storedConfigTemplate) {\r\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\r\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\r\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\r\n }\r\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\r\n throw new Error('Option ' + key + ' is not of the correct type');\r\n }\r\n\r\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\r\n if (!result[0]) {\r\n erroredKeys.set(key, result[1]);\r\n }\r\n }\r\n\r\n for (const key in this.definiteConfig) {\r\n if (!this.storedConfigTemplate[key]) {\r\n throw new Error('Option ' + key + ' is not defined in the configuration template');\r\n }\r\n }\r\n\r\n if (erroredKeys.size > 0) {\r\n return [ false, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n return [ true, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n getStringValue(optionName: string): string {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'string') {\r\n throw new Error('Option ' + optionName + ' is not a string');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getNumberValue(optionName: string): number {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'number') {\r\n throw new Error('Option ' + optionName + ' is not a number');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getBooleanValue(optionName: string): boolean {\r\n if (this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\r\n throw new Error('Option ' + optionName + ' is not a boolean');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n}\r\n\r\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };","import { ConfigurationBuilder } from \"./main\";\r\n\r\nexport default class EventResponse<T> {\r\n data: T | undefined = undefined;\r\n deffered: boolean = false;\r\n resolved: boolean = false;\r\n progress: number = 0;\r\n logs: string[] = [];\r\n onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;\r\n\r\n constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {\r\n this.onInputAsked = onInputAsked;\r\n }\r\n \r\n\r\n public defer() {\r\n this.deffered = true;\r\n }\r\n\r\n public resolve(data: T) {\r\n this.resolved = true;\r\n this.data = data;\r\n }\r\n\r\n public complete() {\r\n this.resolved = true;\r\n }\r\n\r\n public log(message: string) {\r\n this.logs.push(message);\r\n }\r\n\r\n public async askForInput(name: string, description: string, screen: ConfigurationBuilder) {\r\n if (!this.onInputAsked) {\r\n throw new Error('No input asked callback');\r\n }\r\n return await this.onInputAsked(screen, name, description);\r\n }\r\n\r\n \r\n}"],"mappings":"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","names":["z","events","ws"]}
package/build/main.d.cts CHANGED
@@ -6,8 +6,8 @@ import EventResponse from './EventResponse.cjs';
6
6
  import { SearchResult } from './SearchEngine.cjs';
7
7
 
8
8
  type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';
9
- type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification';
10
- type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup';
9
+ type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification' | 'input-asked';
10
+ type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup' | 'response';
11
11
 
12
12
  interface ClientSentEventTypes {
13
13
  response: any;
@@ -18,6 +18,7 @@ interface ClientSentEventTypes {
18
18
  progress: number;
19
19
  };
20
20
  notification: Notification;
21
+ 'input-asked': ConfigurationBuilder;
21
22
  }
22
23
  interface EventListenerTypes {
23
24
  connect: (socket: ws) => void;
@@ -25,7 +26,10 @@ interface EventListenerTypes {
25
26
  configure: (config: ConfigurationBuilder) => ConfigurationBuilder;
26
27
  response: (response: any) => void;
27
28
  authenticate: (config: any) => void;
28
- search: (query: string, event: EventResponse<SearchResult[]>) => void;
29
+ search: (query: {
30
+ type: 'steamapp';
31
+ text: string;
32
+ }, event: EventResponse<SearchResult[]>) => void;
29
33
  setup: (data: {
30
34
  path: string;
31
35
  type: 'direct' | 'torrent' | 'magnet';
@@ -35,7 +39,8 @@ interface EventListenerTypes {
35
39
  name: string;
36
40
  downloadURL: string;
37
41
  }[];
38
- }, event: EventResponse<undefined | null>) => void;
42
+ steamAppID: number;
43
+ }, event: EventResponse<LibraryInfo>) => void;
39
44
  }
40
45
  interface WebsocketMessageClient {
41
46
  event: OGIAddonClientSentEvent;
@@ -65,6 +70,15 @@ declare class OGIAddon {
65
70
  emit<T extends OGIAddonEvent>(event: T, ...args: Parameters<EventListenerTypes[T]>): void;
66
71
  notify(notification: Notification): void;
67
72
  }
73
+ interface LibraryInfo {
74
+ name: string;
75
+ version: string;
76
+ cwd: string;
77
+ steamAppID: number;
78
+ launchExecutable: string;
79
+ launchArguments?: string;
80
+ capsuleImage: string;
81
+ }
68
82
  interface Notification {
69
83
  type: 'warning' | 'error' | 'info' | 'success';
70
84
  message: string;
@@ -75,11 +89,13 @@ declare class OGIAddonWSListener {
75
89
  eventEmitter: events.EventEmitter;
76
90
  addon: OGIAddon;
77
91
  constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter);
92
+ private userInputAsked;
78
93
  private registerMessageReceiver;
79
94
  private waitForEventToRespond;
80
95
  respondToMessage(messageID: string, response: any): void;
96
+ waitForResponseFromServer<T>(messageID: string): Promise<T>;
81
97
  send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>): void;
82
98
  close(): void;
83
99
  }
84
100
 
85
- export { type ClientSentEventTypes, Configuration, ConfigurationBuilder, type EventListenerTypes, EventResponse, type OGIAddonClientSentEvent, type OGIAddonConfiguration, type OGIAddonEvent, type OGIAddonServerSentEvent, SearchResult, type WebsocketMessageClient, type WebsocketMessageServer, OGIAddon as default };
101
+ export { type ClientSentEventTypes, Configuration, ConfigurationBuilder, type EventListenerTypes, EventResponse, type LibraryInfo, type OGIAddonClientSentEvent, type OGIAddonConfiguration, type OGIAddonEvent, type OGIAddonServerSentEvent, SearchResult, type WebsocketMessageClient, type WebsocketMessageServer, OGIAddon as default };
package/build/main.d.ts CHANGED
@@ -6,8 +6,8 @@ import EventResponse from './EventResponse.js';
6
6
  import { SearchResult } from './SearchEngine.js';
7
7
 
8
8
  type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';
9
- type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification';
10
- type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup';
9
+ type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification' | 'input-asked';
10
+ type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup' | 'response';
11
11
 
12
12
  interface ClientSentEventTypes {
13
13
  response: any;
@@ -18,6 +18,7 @@ interface ClientSentEventTypes {
18
18
  progress: number;
19
19
  };
20
20
  notification: Notification;
21
+ 'input-asked': ConfigurationBuilder;
21
22
  }
22
23
  interface EventListenerTypes {
23
24
  connect: (socket: ws) => void;
@@ -25,7 +26,10 @@ interface EventListenerTypes {
25
26
  configure: (config: ConfigurationBuilder) => ConfigurationBuilder;
26
27
  response: (response: any) => void;
27
28
  authenticate: (config: any) => void;
28
- search: (query: string, event: EventResponse<SearchResult[]>) => void;
29
+ search: (query: {
30
+ type: 'steamapp';
31
+ text: string;
32
+ }, event: EventResponse<SearchResult[]>) => void;
29
33
  setup: (data: {
30
34
  path: string;
31
35
  type: 'direct' | 'torrent' | 'magnet';
@@ -35,7 +39,8 @@ interface EventListenerTypes {
35
39
  name: string;
36
40
  downloadURL: string;
37
41
  }[];
38
- }, event: EventResponse<undefined | null>) => void;
42
+ steamAppID: number;
43
+ }, event: EventResponse<LibraryInfo>) => void;
39
44
  }
40
45
  interface WebsocketMessageClient {
41
46
  event: OGIAddonClientSentEvent;
@@ -65,6 +70,15 @@ declare class OGIAddon {
65
70
  emit<T extends OGIAddonEvent>(event: T, ...args: Parameters<EventListenerTypes[T]>): void;
66
71
  notify(notification: Notification): void;
67
72
  }
73
+ interface LibraryInfo {
74
+ name: string;
75
+ version: string;
76
+ cwd: string;
77
+ steamAppID: number;
78
+ launchExecutable: string;
79
+ launchArguments?: string;
80
+ capsuleImage: string;
81
+ }
68
82
  interface Notification {
69
83
  type: 'warning' | 'error' | 'info' | 'success';
70
84
  message: string;
@@ -75,11 +89,13 @@ declare class OGIAddonWSListener {
75
89
  eventEmitter: events.EventEmitter;
76
90
  addon: OGIAddon;
77
91
  constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter);
92
+ private userInputAsked;
78
93
  private registerMessageReceiver;
79
94
  private waitForEventToRespond;
80
95
  respondToMessage(messageID: string, response: any): void;
96
+ waitForResponseFromServer<T>(messageID: string): Promise<T>;
81
97
  send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>): void;
82
98
  close(): void;
83
99
  }
84
100
 
85
- export { type ClientSentEventTypes, Configuration, ConfigurationBuilder, type EventListenerTypes, EventResponse, type OGIAddonClientSentEvent, type OGIAddonConfiguration, type OGIAddonEvent, type OGIAddonServerSentEvent, SearchResult, type WebsocketMessageClient, type WebsocketMessageServer, OGIAddon as default };
101
+ export { type ClientSentEventTypes, Configuration, ConfigurationBuilder, type EventListenerTypes, EventResponse, type LibraryInfo, type OGIAddonClientSentEvent, type OGIAddonConfiguration, type OGIAddonEvent, type OGIAddonServerSentEvent, SearchResult, type WebsocketMessageClient, type WebsocketMessageServer, OGIAddon as default };
package/build/main.js CHANGED
@@ -73,6 +73,7 @@ var StringOption = class extends ConfigurationOption {
73
73
  minTextLength = 0;
74
74
  maxTextLength = Number.MAX_SAFE_INTEGER;
75
75
  defaultValue = "";
76
+ inputType = "text";
76
77
  type = "string";
77
78
  setAllowedValues(allowedValues) {
78
79
  this.allowedValues = allowedValues;
@@ -90,6 +91,10 @@ var StringOption = class extends ConfigurationOption {
90
91
  this.maxTextLength = maxTextLength;
91
92
  return this;
92
93
  }
94
+ setInputType(inputType) {
95
+ this.inputType = inputType;
96
+ return this;
97
+ }
93
98
  validate(input) {
94
99
  if (typeof input !== "string") {
95
100
  return [false, "Input is not a string"];
@@ -226,6 +231,10 @@ var EventResponse = class {
226
231
  resolved = false;
227
232
  progress = 0;
228
233
  logs = [];
234
+ onInputAsked;
235
+ constructor(onInputAsked) {
236
+ this.onInputAsked = onInputAsked;
237
+ }
229
238
  defer() {
230
239
  this.deffered = true;
231
240
  }
@@ -239,10 +248,17 @@ var EventResponse = class {
239
248
  log(message) {
240
249
  this.logs.push(message);
241
250
  }
251
+ async askForInput(name, description, screen) {
252
+ if (!this.onInputAsked) {
253
+ throw new Error("No input asked callback");
254
+ }
255
+ return await this.onInputAsked(screen, name, description);
256
+ }
242
257
  };
243
258
 
244
259
  // src/main.ts
245
260
  var defaultPort = 7654;
261
+ var version = process.env.npm_package_version;
246
262
  var OGIAddon = class {
247
263
  eventEmitter = new events.EventEmitter();
248
264
  addonWSListener;
@@ -275,11 +291,13 @@ var OGIAddonWSListener = class {
275
291
  this.socket = new ws("ws://localhost:" + defaultPort);
276
292
  this.socket.on("open", () => {
277
293
  console.log("Connected to OGI Addon Server");
294
+ console.log("OGI Addon Server Version:", version);
278
295
  this.socket.send(JSON.stringify({
279
296
  event: "authenticate",
280
297
  args: {
281
298
  ...this.addon.addonInfo,
282
- secret: process.argv[process.argv.length - 1].split("=")[1]
299
+ secret: process.argv[process.argv.length - 1].split("=")[1],
300
+ ogiVersion: version
283
301
  }
284
302
  }));
285
303
  this.eventEmitter.emit("connect");
@@ -304,10 +322,28 @@ var OGIAddonWSListener = class {
304
322
  }
305
323
  this.eventEmitter.emit("disconnect", reason);
306
324
  console.log("Disconnected from OGI Addon Server");
325
+ console.log(reason.toString());
307
326
  this.socket.close();
308
327
  });
309
328
  this.registerMessageReceiver();
310
329
  }
330
+ async userInputAsked(configBuilt, name, description, socket) {
331
+ const config = configBuilt.build(false);
332
+ const id = Math.random().toString(36).substring(7);
333
+ if (!socket) {
334
+ return {};
335
+ }
336
+ socket.send(JSON.stringify({
337
+ event: "input-asked",
338
+ args: {
339
+ config,
340
+ name,
341
+ description
342
+ },
343
+ id
344
+ }));
345
+ return await this.waitForResponseFromServer(id);
346
+ }
311
347
  registerMessageReceiver() {
312
348
  this.socket.on("message", async (data) => {
313
349
  const message = JSON.parse(data);
@@ -321,15 +357,15 @@ var OGIAddonWSListener = class {
321
357
  }
322
358
  break;
323
359
  case "search":
324
- let searchResultEvent = new EventResponse();
360
+ let searchResultEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
325
361
  this.eventEmitter.emit("search", message.args, searchResultEvent);
326
362
  const searchResult = await this.waitForEventToRespond(searchResultEvent);
327
363
  console.log(searchResult.data);
328
364
  this.respondToMessage(message.id, searchResult.data);
329
365
  break;
330
366
  case "setup":
331
- let setupEvent = new EventResponse();
332
- this.eventEmitter.emit("setup", { path: message.args.path, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);
367
+ let setupEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
368
+ this.eventEmitter.emit("setup", { path: message.args.path, steamAppID: message.args.steamAppID, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);
333
369
  const interval = setInterval(() => {
334
370
  if (setupEvent.resolved) {
335
371
  clearInterval(interval);
@@ -378,6 +414,24 @@ var OGIAddonWSListener = class {
378
414
  }));
379
415
  console.log("dispatched response to " + messageID);
380
416
  }
417
+ waitForResponseFromServer(messageID) {
418
+ return new Promise((resolve) => {
419
+ const waiter = (data) => {
420
+ const message = JSON.parse(data);
421
+ if (message.event !== "response") {
422
+ this.socket.once("message", waiter);
423
+ return;
424
+ }
425
+ console.log("received response from " + messageID);
426
+ if (message.id === messageID) {
427
+ resolve(message.args);
428
+ } else {
429
+ this.socket.once("message", waiter);
430
+ }
431
+ };
432
+ this.socket.once("message", waiter);
433
+ });
434
+ }
381
435
  send(event, args) {
382
436
  this.socket.send(JSON.stringify({
383
437
  event,
package/build/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/main.ts","../src/config/ConfigurationBuilder.ts","../src/config/Configuration.ts","../src/EventResponse.ts"],"sourcesContent":["import ws, { WebSocket } from 'ws';\r\nimport events from 'node:events';\r\nimport { ConfigurationBuilder, ConfigurationFile } from './config/ConfigurationBuilder';\r\nimport { Configuration } from './config/Configuration';\r\nimport EventResponse from './EventResponse';\r\nimport { SearchResult } from './SearchEngine';\r\n\r\nexport type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';\r\nexport type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification';\r\n\r\nexport type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup';\r\nexport { ConfigurationBuilder, Configuration, EventResponse, SearchResult };\r\nconst defaultPort = 7654;\r\n\r\nexport interface ClientSentEventTypes {\r\n response: any;\r\n authenticate: any;\r\n configure: ConfigurationFile;\r\n 'defer-update': {\r\n logs: string[], \r\n progress: number\r\n };\r\n notification: Notification;\r\n}\r\n\r\nexport interface EventListenerTypes {\r\n connect: (socket: ws) => void;\r\n disconnect: (reason: string) => void;\r\n configure: (config: ConfigurationBuilder) => ConfigurationBuilder;\r\n response: (response: any) => void;\r\n authenticate: (config: any) => void;\r\n search: (query: string, event: EventResponse<SearchResult[]>) => void;\r\n setup: (\r\n data: { \r\n path: string, \r\n type: 'direct' | 'torrent' | 'magnet',\r\n name: string,\r\n usedRealDebrid: boolean, \r\n multiPartFiles?: {\r\n name: string,\r\n downloadURL: string\r\n }[],\r\n }, event: EventResponse<undefined | null>\r\n ) => void;\r\n}\r\n\r\nexport interface WebsocketMessageClient {\r\n event: OGIAddonClientSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface WebsocketMessageServer {\r\n event: OGIAddonServerSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface OGIAddonConfiguration {\r\n name: string;\r\n id: string;\r\n description: string;\r\n version: string;\r\n\r\n author: string;\r\n repository: string;\r\n}\r\nexport default class OGIAddon {\r\n public eventEmitter = new events.EventEmitter();\r\n public addonWSListener: OGIAddonWSListener;\r\n public addonInfo: OGIAddonConfiguration;\r\n public config: Configuration = new Configuration({});\r\n\r\n constructor(addonInfo: OGIAddonConfiguration) {\r\n this.addonInfo = addonInfo;\r\n this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);\r\n }\r\n \r\n public on<T extends OGIAddonEvent>(event: T, listener: EventListenerTypes[T]) {\r\n this.eventEmitter.on(event, listener);\r\n }\r\n\r\n public emit<T extends OGIAddonEvent>(event: T, ...args: Parameters<EventListenerTypes[T]>) {\r\n this.eventEmitter.emit(event, ...args);\r\n }\r\n\r\n public notify(notification: Notification) {\r\n this.addonWSListener.send('notification', [ notification ]);\r\n }\r\n}\r\ninterface Notification {\r\n type: 'warning' | 'error' | 'info' | 'success';\r\n message: string;\r\n id: string\r\n}\r\nclass OGIAddonWSListener {\r\n private socket: WebSocket;\r\n public eventEmitter: events.EventEmitter;\r\n public addon: OGIAddon;\r\n\r\n constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter) {\r\n if (process.argv[process.argv.length - 1].split('=')[0] !== '--addonSecret') {\r\n throw new Error('No secret provided. This usually happens because the addon was not started by the OGI Addon Server.');\r\n }\r\n this.addon = ogiAddon;\r\n this.eventEmitter = eventEmitter;\r\n this.socket = new ws('ws://localhost:' + defaultPort);\r\n this.socket.on('open', () => {\r\n console.log('Connected to OGI Addon Server');\r\n\r\n // Authenticate with OGI Addon Server\r\n this.socket.send(JSON.stringify({\r\n event: 'authenticate',\r\n args: {\r\n ...this.addon.addonInfo,\r\n secret: process.argv[process.argv.length - 1].split('=')[1]\r\n }\r\n }));\r\n\r\n this.eventEmitter.emit('connect');\r\n\r\n // send a configuration request\r\n let configBuilder = new ConfigurationBuilder();\r\n this.eventEmitter.emit('configure', configBuilder);\r\n \r\n this.socket.send(JSON.stringify({\r\n event: 'configure',\r\n args: configBuilder.build(false) \r\n }));\r\n this.addon.config = new Configuration(configBuilder.build(true));\r\n });\r\n\r\n this.socket.on('error', (error) => {\r\n if (error.message.includes('Failed to connect')) {\r\n throw new Error('OGI Addon Server is not running/is unreachable. Please start the server and try again.');\r\n }\r\n console.error('An error occurred:', error);\r\n })\r\n\r\n this.socket.on('close', (code, reason) => {\r\n if (code === 1008) {\r\n console.error('Authentication failed:', reason);\r\n return;\r\n }\r\n this.eventEmitter.emit('disconnect', reason);\r\n console.log(\"Disconnected from OGI Addon Server\")\r\n this.socket.close();\r\n });\r\n\r\n this.registerMessageReceiver();\r\n }\r\n\r\n private registerMessageReceiver() {\r\n this.socket.on('message', async (data: string) => {\r\n const message: WebsocketMessageServer = JSON.parse(data);\r\n switch (message.event) {\r\n case 'config-update':\r\n const result = this.addon.config.updateConfig(message.args);\r\n if (!result[0]) {\r\n this.respondToMessage(message.id!!, { success: false, error: result[1] });\r\n }\r\n else {\r\n this.respondToMessage(message.id!!, { success: true });\r\n }\r\n break \r\n case 'search':\r\n let searchResultEvent = new EventResponse<SearchResult[]>();\r\n this.eventEmitter.emit('search', message.args, searchResultEvent);\r\n const searchResult = await this.waitForEventToRespond(searchResultEvent); \r\n console.log(searchResult.data)\r\n this.respondToMessage(message.id!!, searchResult.data);\r\n break\r\n case 'setup':\r\n let setupEvent = new EventResponse<undefined | null>();\r\n this.eventEmitter.emit('setup', { path: message.args.path, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);\r\n const interval = setInterval(() => {\r\n if (setupEvent.resolved) {\r\n clearInterval(interval);\r\n return;\r\n }\r\n this.send('defer-update', { \r\n logs: setupEvent.logs,\r\n deferID: message.args.deferID,\r\n progress: setupEvent.progress\r\n } as any);\r\n }, 100);\r\n const setupResult = await this.waitForEventToRespond(setupEvent);\r\n this.respondToMessage(message.id!!, setupResult.data);\r\n break\r\n }\r\n });\r\n }\r\n\r\n private waitForEventToRespond<T>(event: EventResponse<T>): Promise<EventResponse<T>> {\r\n return new Promise((resolve, reject) => {\r\n const dataGet = setInterval(() => {\r\n if (event.resolved) {\r\n resolve(event);\r\n clearTimeout(timeout);\r\n }\r\n }, 5); \r\n\r\n const timeout = setTimeout(() => {\r\n if (event.deffered) {\r\n clearInterval(dataGet);\r\n const interval = setInterval(() => {\r\n if (event.resolved) {\r\n clearInterval(interval);\r\n resolve(event);\r\n }\r\n }, 100);\r\n }\r\n else {\r\n reject('Event did not respond in time');\r\n }\r\n }, 5000)\r\n });\r\n }\r\n\r\n public respondToMessage(messageID: string, response: any) {\r\n this.socket.send(JSON.stringify({\r\n event: 'response',\r\n id: messageID,\r\n args: response\r\n }));\r\n console.log(\"dispatched response to \" + messageID)\r\n }\r\n\r\n public send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>) {\r\n this.socket.send(JSON.stringify({\r\n event,\r\n args\r\n }));\r\n }\r\n\r\n public close() {\r\n this.socket.close();\r\n }\r\n\r\n \r\n}","import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}","import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\r\n\r\ninterface DefiniteConfig {\r\n [key: string]: string | number | boolean;\r\n}\r\nexport class Configuration {\r\n readonly storedConfigTemplate: ConfigurationFile;\r\n definiteConfig: DefiniteConfig = {};\r\n constructor(configTemplate: ConfigurationFile) {\r\n this.storedConfigTemplate = configTemplate;\r\n }\r\n\r\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\r\n this.definiteConfig = config;\r\n if (validate) {\r\n const result = this.validateConfig();\r\n return result;\r\n }\r\n return [ true, {} ];\r\n }\r\n // provides falsey or truthy value, and an error message if falsey\r\n private validateConfig(): [ boolean, { [key: string]: string } ] {\r\n const erroredKeys = new Map<string, string>();\r\n for (const key in this.storedConfigTemplate) {\r\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\r\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\r\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\r\n }\r\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\r\n throw new Error('Option ' + key + ' is not of the correct type');\r\n }\r\n\r\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\r\n if (!result[0]) {\r\n erroredKeys.set(key, result[1]);\r\n }\r\n }\r\n\r\n for (const key in this.definiteConfig) {\r\n if (!this.storedConfigTemplate[key]) {\r\n throw new Error('Option ' + key + ' is not defined in the configuration template');\r\n }\r\n }\r\n\r\n if (erroredKeys.size > 0) {\r\n return [ false, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n return [ true, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n getStringValue(optionName: string): string {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'string') {\r\n throw new Error('Option ' + optionName + ' is not a string');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getNumberValue(optionName: string): number {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'number') {\r\n throw new Error('Option ' + optionName + ' is not a number');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getBooleanValue(optionName: string): boolean {\r\n if (this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\r\n throw new Error('Option ' + optionName + ' is not a boolean');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n}\r\n\r\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };","export default class EventResponse<T> {\r\n data: T | undefined = undefined;\r\n deffered: boolean = false;\r\n resolved: boolean = false;\r\n progress: number = 0;\r\n logs: string[] = [];\r\n\r\n public defer() {\r\n this.deffered = true;\r\n }\r\n\r\n public resolve(data: T) {\r\n this.resolved = true;\r\n this.data = data;\r\n }\r\n\r\n public complete() {\r\n this.resolved = true;\r\n }\r\n\r\n public log(message: string) {\r\n this.logs.push(message);\r\n }\r\n\r\n \r\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/main.ts","../src/config/ConfigurationBuilder.ts","../src/config/Configuration.ts","../src/EventResponse.ts"],"sourcesContent":["import ws, { WebSocket } from 'ws';\r\nimport events from 'node:events';\r\nimport { ConfigurationBuilder, ConfigurationFile } from './config/ConfigurationBuilder';\r\nimport { Configuration } from './config/Configuration';\r\nimport EventResponse from './EventResponse';\r\nimport { SearchResult } from './SearchEngine';\r\n\r\nexport type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';\r\nexport type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification' | 'input-asked';\r\n\r\nexport type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup' | 'response';\r\nexport { ConfigurationBuilder, Configuration, EventResponse, SearchResult };\r\nconst defaultPort = 7654;\r\nconst version = process.env.npm_package_version;\r\n\r\nexport interface ClientSentEventTypes {\r\n response: any;\r\n authenticate: any;\r\n configure: ConfigurationFile;\r\n 'defer-update': {\r\n logs: string[], \r\n progress: number\r\n };\r\n notification: Notification;\r\n 'input-asked': ConfigurationBuilder;\r\n}\r\n\r\nexport interface EventListenerTypes {\r\n connect: (socket: ws) => void;\r\n disconnect: (reason: string) => void;\r\n configure: (config: ConfigurationBuilder) => ConfigurationBuilder;\r\n response: (response: any) => void;\r\n authenticate: (config: any) => void;\r\n search: (query: { type: 'steamapp', text: string }, event: EventResponse<SearchResult[]>) => void;\r\n setup: (\r\n data: { \r\n path: string, \r\n type: 'direct' | 'torrent' | 'magnet',\r\n name: string,\r\n usedRealDebrid: boolean, \r\n multiPartFiles?: {\r\n name: string,\r\n downloadURL: string\r\n }[],\r\n steamAppID: number\r\n }, event: EventResponse<LibraryInfo>\r\n ) => void;\r\n}\r\n\r\nexport interface WebsocketMessageClient {\r\n event: OGIAddonClientSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface WebsocketMessageServer {\r\n event: OGIAddonServerSentEvent;\r\n id?: string;\r\n args: any;\r\n}\r\nexport interface OGIAddonConfiguration {\r\n name: string;\r\n id: string;\r\n description: string;\r\n version: string;\r\n\r\n author: string;\r\n repository: string;\r\n}\r\nexport default class OGIAddon {\r\n public eventEmitter = new events.EventEmitter();\r\n public addonWSListener: OGIAddonWSListener;\r\n public addonInfo: OGIAddonConfiguration;\r\n public config: Configuration = new Configuration({});\r\n\r\n constructor(addonInfo: OGIAddonConfiguration) {\r\n this.addonInfo = addonInfo;\r\n this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);\r\n }\r\n \r\n public on<T extends OGIAddonEvent>(event: T, listener: EventListenerTypes[T]) {\r\n this.eventEmitter.on(event, listener);\r\n }\r\n\r\n public emit<T extends OGIAddonEvent>(event: T, ...args: Parameters<EventListenerTypes[T]>) {\r\n this.eventEmitter.emit(event, ...args);\r\n }\r\n\r\n public notify(notification: Notification) {\r\n this.addonWSListener.send('notification', [ notification ]);\r\n }\r\n}\r\n\r\nexport interface LibraryInfo {\r\n name: string;\r\n version: string;\r\n cwd: string;\r\n steamAppID: number;\r\n launchExecutable: string;\r\n launchArguments?: string;\r\n capsuleImage: string;\r\n}\r\ninterface Notification {\r\n type: 'warning' | 'error' | 'info' | 'success';\r\n message: string;\r\n id: string\r\n}\r\nclass OGIAddonWSListener {\r\n private socket: WebSocket;\r\n public eventEmitter: events.EventEmitter;\r\n public addon: OGIAddon;\r\n\r\n constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter) {\r\n if (process.argv[process.argv.length - 1].split('=')[0] !== '--addonSecret') {\r\n throw new Error('No secret provided. This usually happens because the addon was not started by the OGI Addon Server.');\r\n }\r\n this.addon = ogiAddon;\r\n this.eventEmitter = eventEmitter;\r\n this.socket = new ws('ws://localhost:' + defaultPort);\r\n this.socket.on('open', () => {\r\n console.log('Connected to OGI Addon Server');\r\n console.log('OGI Addon Server Version:', version);\r\n\r\n // Authenticate with OGI Addon Server\r\n this.socket.send(JSON.stringify({\r\n event: 'authenticate',\r\n args: {\r\n ...this.addon.addonInfo,\r\n secret: process.argv[process.argv.length - 1].split('=')[1],\r\n ogiVersion: version\r\n }\r\n }));\r\n\r\n this.eventEmitter.emit('connect');\r\n\r\n // send a configuration request\r\n let configBuilder = new ConfigurationBuilder();\r\n this.eventEmitter.emit('configure', configBuilder);\r\n \r\n this.socket.send(JSON.stringify({\r\n event: 'configure',\r\n args: configBuilder.build(false) \r\n }));\r\n this.addon.config = new Configuration(configBuilder.build(true));\r\n });\r\n\r\n this.socket.on('error', (error) => {\r\n if (error.message.includes('Failed to connect')) {\r\n throw new Error('OGI Addon Server is not running/is unreachable. Please start the server and try again.');\r\n }\r\n console.error('An error occurred:', error);\r\n })\r\n\r\n this.socket.on('close', (code, reason) => {\r\n if (code === 1008) {\r\n console.error('Authentication failed:', reason);\r\n return;\r\n }\r\n this.eventEmitter.emit('disconnect', reason);\r\n console.log(\"Disconnected from OGI Addon Server\")\r\n console.log(reason.toString())\r\n this.socket.close();\r\n });\r\n\r\n this.registerMessageReceiver();\r\n }\r\n\r\n private async userInputAsked(configBuilt: ConfigurationBuilder, name: string, description: string, socket: WebSocket): Promise<{ [key: string]: number | boolean | string }> {\r\n const config = configBuilt.build(false);\r\n const id = Math.random().toString(36).substring(7);\r\n if (!socket) {\r\n return {};\r\n }\r\n socket.send(JSON.stringify({\r\n event: 'input-asked',\r\n args: {\r\n config,\r\n name,\r\n description\r\n },\r\n id: id\r\n }));\r\n return await this.waitForResponseFromServer(id);\r\n }\r\n\r\n private registerMessageReceiver() {\r\n this.socket.on('message', async (data: string) => {\r\n const message: WebsocketMessageServer = JSON.parse(data);\r\n switch (message.event) {\r\n case 'config-update':\r\n const result = this.addon.config.updateConfig(message.args);\r\n if (!result[0]) {\r\n this.respondToMessage(message.id!!, { success: false, error: result[1] });\r\n }\r\n else {\r\n this.respondToMessage(message.id!!, { success: true });\r\n }\r\n break \r\n case 'search':\r\n let searchResultEvent = new EventResponse<SearchResult[]>((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));\r\n this.eventEmitter.emit('search', message.args, searchResultEvent);\r\n const searchResult = await this.waitForEventToRespond(searchResultEvent); \r\n console.log(searchResult.data)\r\n this.respondToMessage(message.id!!, searchResult.data);\r\n break\r\n case 'setup':\r\n let setupEvent = new EventResponse<LibraryInfo>((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));\r\n this.eventEmitter.emit('setup', { path: message.args.path, steamAppID: message.args.steamAppID, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);\r\n const interval = setInterval(() => {\r\n if (setupEvent.resolved) {\r\n clearInterval(interval);\r\n return;\r\n }\r\n this.send('defer-update', { \r\n logs: setupEvent.logs,\r\n deferID: message.args.deferID,\r\n progress: setupEvent.progress\r\n } as any);\r\n }, 100);\r\n const setupResult = await this.waitForEventToRespond(setupEvent);\r\n this.respondToMessage(message.id!!, setupResult.data);\r\n break\r\n }\r\n });\r\n }\r\n\r\n private waitForEventToRespond<T>(event: EventResponse<T>): Promise<EventResponse<T>> {\r\n return new Promise((resolve, reject) => {\r\n const dataGet = setInterval(() => {\r\n if (event.resolved) {\r\n resolve(event);\r\n clearTimeout(timeout);\r\n }\r\n }, 5); \r\n\r\n const timeout = setTimeout(() => {\r\n if (event.deffered) {\r\n clearInterval(dataGet);\r\n const interval = setInterval(() => {\r\n if (event.resolved) {\r\n clearInterval(interval);\r\n resolve(event);\r\n }\r\n }, 100);\r\n }\r\n else {\r\n reject('Event did not respond in time');\r\n }\r\n }, 5000)\r\n });\r\n }\r\n\r\n public respondToMessage(messageID: string, response: any) {\r\n this.socket.send(JSON.stringify({\r\n event: 'response',\r\n id: messageID,\r\n args: response\r\n }));\r\n console.log(\"dispatched response to \" + messageID)\r\n }\r\n\r\n public waitForResponseFromServer<T>(messageID: string): Promise<T> {\r\n return new Promise((resolve) => {\r\n const waiter = (data: string) => {\r\n const message: WebsocketMessageClient = JSON.parse(data);\r\n if (message.event !== 'response') {\r\n this.socket.once('message', waiter);\r\n return;\r\n }\r\n console.log(\"received response from \" + messageID)\r\n\r\n if (message.id === messageID) {\r\n resolve(message.args);\r\n }\r\n else {\r\n this.socket.once('message', waiter);\r\n }\r\n }\r\n this.socket.once('message', waiter);\r\n });\r\n }\r\n\r\n public send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>) {\r\n this.socket.send(JSON.stringify({\r\n event,\r\n args\r\n }));\r\n }\r\n\r\n public close() {\r\n this.socket.close();\r\n }\r\n\r\n \r\n}","import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\r\n this.inputType = inputType;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}","import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\r\n\r\ninterface DefiniteConfig {\r\n [key: string]: string | number | boolean;\r\n}\r\nexport class Configuration {\r\n readonly storedConfigTemplate: ConfigurationFile;\r\n definiteConfig: DefiniteConfig = {};\r\n constructor(configTemplate: ConfigurationFile) {\r\n this.storedConfigTemplate = configTemplate;\r\n }\r\n\r\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\r\n this.definiteConfig = config;\r\n if (validate) {\r\n const result = this.validateConfig();\r\n return result;\r\n }\r\n return [ true, {} ];\r\n }\r\n // provides falsey or truthy value, and an error message if falsey\r\n private validateConfig(): [ boolean, { [key: string]: string } ] {\r\n const erroredKeys = new Map<string, string>();\r\n for (const key in this.storedConfigTemplate) {\r\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\r\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\r\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\r\n }\r\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\r\n throw new Error('Option ' + key + ' is not of the correct type');\r\n }\r\n\r\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\r\n if (!result[0]) {\r\n erroredKeys.set(key, result[1]);\r\n }\r\n }\r\n\r\n for (const key in this.definiteConfig) {\r\n if (!this.storedConfigTemplate[key]) {\r\n throw new Error('Option ' + key + ' is not defined in the configuration template');\r\n }\r\n }\r\n\r\n if (erroredKeys.size > 0) {\r\n return [ false, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n return [ true, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n getStringValue(optionName: string): string {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'string') {\r\n throw new Error('Option ' + optionName + ' is not a string');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getNumberValue(optionName: string): number {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'number') {\r\n throw new Error('Option ' + optionName + ' is not a number');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getBooleanValue(optionName: string): boolean {\r\n if (this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\r\n throw new Error('Option ' + optionName + ' is not a boolean');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n}\r\n\r\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };","import { ConfigurationBuilder } from \"./main\";\r\n\r\nexport default class EventResponse<T> {\r\n data: T | undefined = undefined;\r\n deffered: boolean = false;\r\n resolved: boolean = false;\r\n progress: number = 0;\r\n logs: string[] = [];\r\n onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;\r\n\r\n constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {\r\n this.onInputAsked = onInputAsked;\r\n }\r\n \r\n\r\n public defer() {\r\n this.deffered = true;\r\n }\r\n\r\n public resolve(data: T) {\r\n this.resolved = true;\r\n this.data = data;\r\n }\r\n\r\n public complete() {\r\n this.resolved = true;\r\n }\r\n\r\n public log(message: string) {\r\n this.logs.push(message);\r\n }\r\n\r\n public async askForInput(name: string, description: string, screen: ConfigurationBuilder) {\r\n if (!this.onInputAsked) {\r\n throw new Error('No input asked callback');\r\n }\r\n return await this.onInputAsked(screen, name, description);\r\n }\r\n\r\n \r\n}"],"mappings":"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","names":[]}