Skip to content

Commit

Permalink
refactor: ElectronWebview component
Browse files Browse the repository at this point in the history
  • Loading branch information
KochiyaOcean committed Oct 12, 2023
1 parent 662e999 commit aa3c6ac
Show file tree
Hide file tree
Showing 17 changed files with 283 additions and 320 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const configExtends = [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:import/errors',
'plugin:import/warnings',
]
Expand Down Expand Up @@ -55,7 +56,7 @@ module.exports = {
{
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
plugins: ['@typescript-eslint', 'import', 'react', 'prettier', 'react-hooks'],
extends: [
...configExtends,
'plugin:import/typescript',
Expand Down
26 changes: 13 additions & 13 deletions lib/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,22 @@ const isRenderer = (process || {}).type === 'renderer'

// the very base class
abstract class BaseDebugger {
public debug: Console['debug'] = (...args) => this.getLeveledLog('debug')(...args)
public debug: Console['debug'] = (...args: never[]) => this.getLeveledLog('debug')(...args)

public log: Console['log'] = (...args) => this.getLeveledLog('log')(...args)
public log: Console['log'] = (...args: never[]) => this.getLeveledLog('log')(...args)

public info: Console['info'] = (...args) => this.getLeveledLog('info')(...args)
public info: Console['info'] = (...args: never[]) => this.getLeveledLog('info')(...args)

public warn: Console['warn'] = (...args) => this.getLeveledLog('warn')(...args)
public warn: Console['warn'] = (...args: never[]) => this.getLeveledLog('warn')(...args)

public error: Console['error'] = (...args) => this.getLeveledLog('error')(...args)
public error: Console['error'] = (...args: never[]) => this.getLeveledLog('error')(...args)

public trace: Console['trace'] | void = (...args) => this.getLeveledLog('trace')(...args)
public trace: Console['trace'] | void = (...args: never[]) => this.getLeveledLog('trace')(...args)

public table: Console['table'] = (...args) =>
public table: Console['table'] = (...args: never[]) =>
(this.getLeveledLog('table') as Console['table'])(...args)

public assert: Console['assert'] = (...args) => this.getLeveledLog('assert')(...args)
public assert: Console['assert'] = (...args: never[]) => this.getLeveledLog('assert')(...args)

protected prefix = '[MAIN]'

Expand All @@ -114,7 +114,7 @@ abstract class BaseDebugger {

protected abstract getLogFunc(level: LogType): DefaultLogger

protected getLeveledLog(level: LogType): (...args: any[]) => void {
protected getLeveledLog(level: LogType): (...args: never[]) => void {
if (this.isEnabled()) {
switch (level) {
case 'assert':
Expand Down Expand Up @@ -174,15 +174,15 @@ abstract class DebuggerBase extends BaseDebugger {
if (!this.extra(tag)) {
return Debug.wrap('Invalid extra option name')
}
this.extra(tag).enable()
this.extra(tag)?.enable()
return Debug.wrap({ enabledExtra: tag })
}

public disableExtra(tag: string) {
if (!this.validateTagName(tag)) {
return Debug.wrap('Invalid extra option name')
}
this.extra(tag).disable()
this.extra(tag)?.disable()
return Debug.wrap({ disabledExtra: tag })
}

Expand All @@ -206,14 +206,14 @@ abstract class DebuggerBase extends BaseDebugger {
}
this.h.set(tag, extraHandler)
}
return this.h.get(tag)!
return this.h.get(tag)
}

public main() {
if (!this.h || !this.h.get('main')) {
this.h.set('main', new ExtraDebugger('[MAIN]'))
}
return this.h.get('main')!
return this.h.get('main')
}

public init() {
Expand Down
8 changes: 4 additions & 4 deletions lib/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { EventEmitter } from 'events'
import { mapValues } from 'lodash'

class IPC extends EventEmitter {
data: any = new Object()
data: Record<string, Record<string, (...arg: never[]) => never | never>> = {}

// scope: string
// opts: key-func Object
Expand All @@ -15,7 +15,7 @@ class IPC extends EventEmitter {
return
}
if (!this.data[scope]) {
this.data[scope] = new Object()
this.data[scope] = {}
}
this.unregister(scope, Object.keys(opts))
for (const key in opts) {
Expand Down Expand Up @@ -61,10 +61,10 @@ class IPC extends EventEmitter {

// key: string
// args: arguments passing to api
foreachCall = (key: string, ...args: any[]) => {
foreachCall = (key: string, ...args: never[]) => {
for (const scope in this.data) {
if (Object.prototype.hasOwnProperty.call(this.data[scope], key)) {
this.data[key].apply(null, args)
this.data[scope][key].apply(null as never, args)
}
}
}
Expand Down
88 changes: 49 additions & 39 deletions lib/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import http from 'http'
import path from 'path'
import querystring from 'querystring'
import mime from 'mime'
import createPacProxyAgent from 'pac-proxy-agent'
import createHttpProxyAgent from 'http-proxy-agent'
import createPacProxyAgent, { PacProxyAgent } from 'pac-proxy-agent'
import createHttpProxyAgent, { HttpProxyAgent } from 'http-proxy-agent'
import { SocksProxyAgent } from 'socks-proxy-agent'
import { app, session } from 'electron'
import util from 'util'
Expand All @@ -26,7 +26,7 @@ type PoiRequestOptions = http.RequestOptions
interface PoiResponseData {
statusCode?: number
error?: Error
data?: any
data?: unknown
}

interface KancolleServer {
Expand All @@ -42,7 +42,7 @@ interface KancolleServerInfo {
const gunzipAsync = util.promisify(gunzip)
const inflateAsync = util.promisify(inflate)

const delay = (time) => new Promise((res) => setTimeout(res, time))
const delay = (time: number) => new Promise((res) => setTimeout(res, time))

const isStaticResource = (pathname: string, hostname: string): boolean => {
if (pathname.startsWith('/kcs2/')) {
Expand Down Expand Up @@ -91,13 +91,16 @@ const findHack = (pathname: string): string | null => {
const sp = loc.split('.')
const ext = sp.pop()
sp.push('hack')
sp.push(ext)
if (ext) {
sp.push(ext)
}
loc = sp.join('.')
try {
fs.accessSync(loc, fs.constants.R_OK)
return loc
} catch (e) {
if (e.code !== 'ENOENT') console.error(`error while loading hack file ${loc}`, e)
if ((e as { code: string })?.code !== 'ENOENT')
console.error(`error while loading hack file ${loc}`, e)
return null
}
}
Expand Down Expand Up @@ -150,16 +153,16 @@ const resolveProxyUrl = (): string => {
}

class Proxy extends EventEmitter {
pacAgents = {}
socksAgents = {}
httpAgents = {}
pacAgents: Record<string, PacProxyAgent> = {}
socksAgents: Record<string, SocksProxyAgent> = {}
httpAgents: Record<string, HttpProxyAgent> = {}
serverInfo: KancolleServer = {}
serverList: KancolleServerInfo = fs.readJsonSync(path.join(ROOT, 'assets', 'data', 'server.json'))

getServerInfo = () => this.serverInfo

server: http.Server
port: number
server!: http.Server
port!: number

load = () => {
// Handles http request only, https request will be passed to upstream proxy directly.
Expand Down Expand Up @@ -193,7 +196,12 @@ class Proxy extends EventEmitter {
}

updateServerInfo = (urlPattern: url.UrlWithStringQuery) => {
if (isKancolleGameApi(urlPattern.pathname) && this.serverInfo.ip !== urlPattern.hostname) {
if (
urlPattern.pathname &&
urlPattern.hostname &&
isKancolleGameApi(urlPattern.pathname) &&
this.serverInfo.ip !== urlPattern.hostname
) {
if (this.serverList[urlPattern.hostname]) {
this.serverInfo = {
...this.serverList[urlPattern.hostname],
Expand All @@ -210,7 +218,7 @@ class Proxy extends EventEmitter {
}

createServer = async (req: http.IncomingMessage, res: http.ServerResponse) => {
const urlPattern = url.parse(req.url)
const urlPattern = url.parse(req.url || '')

// Prepare request headers
delete req.headers['proxy-connection']
Expand All @@ -221,7 +229,9 @@ class Proxy extends EventEmitter {

// Find cachefile for static resource
const cacheFile =
urlPattern.hostname && isStaticResource(urlPattern.pathname, urlPattern.hostname)
urlPattern.hostname &&
urlPattern.pathname &&
isStaticResource(urlPattern.pathname, urlPattern.hostname)
? findHack(urlPattern.pathname) || findCache(urlPattern.pathname, urlPattern.hostname)
: false

Expand All @@ -246,7 +256,7 @@ class Proxy extends EventEmitter {
const reqOption = this.getRequestOptions(urlPattern, req)
const { statusCode, data, error } = await this.fetchResponse(reqOption, rawReqBody, res)
if (error) {
if (count >= retries || !isKancolleGameApi(urlPattern.pathname)) {
if (count >= retries || !isKancolleGameApi(urlPattern.pathname || '')) {
res.end()
throw error
}
Expand All @@ -257,22 +267,22 @@ class Proxy extends EventEmitter {
res.end()
if (statusCode === 200 && data != null) {
this.emit('network.on.response', req.method, requestInfo, data, reqBody, Date.now())
} else if (statusCode >= 400) {
} else if (statusCode == null || statusCode >= 400) {
this.emit('network.error', requestInfo, statusCode)
}
break
}
}
}
} catch (e) {
error(`${req.method} ${req.url} ${e.toString()}`)
error(`${req.method} ${req.url} ${(e as Error).toString()}`)
this.emit('network.error', requestInfo)
}
}

fetchRequest = (req: http.IncomingMessage): any =>
fetchRequest = (req: http.IncomingMessage): Promise<Buffer> =>
new Promise((resolve) => {
const reqBody = []
const reqBody: Uint8Array[] = []
req.on('data', (chunk) => {
reqBody.push(chunk)
})
Expand All @@ -296,8 +306,8 @@ class Proxy extends EventEmitter {
switch (config.get('proxy.use')) {
// HTTP Request via SOCKS5 proxy
case 'socks5': {
const socksHost = config.get('proxy.socks5.host', '127.0.0.1')
const socksPort = config.get('proxy.socks5.port', 1080)
const socksHost: string = config.get('proxy.socks5.host', '127.0.0.1')
const socksPort: number = config.get('proxy.socks5.port', 1080)
const uri = `${socksHost}:${socksPort}`
if (!this.socksAgents[uri]) {
this.socksAgents[uri] = new SocksProxyAgent(`socks://${uri}`)
Expand Down Expand Up @@ -335,48 +345,48 @@ class Proxy extends EventEmitter {
}

parseResponse = async (
resDataChunks: any[],
resDataChunks: unknown[],
header: http.IncomingHttpHeaders,
): Promise<any | null> => {
): Promise<string | undefined> => {
const contentType: string = header['content-type'] || (header['Content-Type'] as string) || ''
if (!contentType.startsWith('text') && !contentType.startsWith('application')) {
return null
return undefined
}

const resData = Buffer.concat(resDataChunks)
const resData = Buffer.concat(resDataChunks as never[])
const contentEncoding = header['content-encoding'] || (header['Content-Encoding'] as string)
const isGzip = /gzip/i.test(contentEncoding)
const isDeflat = /deflate/i.test(contentEncoding)
const unzipped = isGzip
? await gunzipAsync(resData).catch(() => {
return null
return undefined
})
: isDeflat
? await inflateAsync(resData).catch(() => {
return null
return undefined
})
: resData
try {
const str = unzipped.toString()
const parsed = str.startsWith('svdata=') ? str.substring(7) : str
JSON.parse(parsed)
const str = unzipped?.toString()
const parsed = str?.startsWith('svdata=') ? str.substring(7) : str
JSON.parse(parsed || '')
return parsed
} catch (e) {
return null
return undefined
}
}

fetchResponse = (
options: PoiRequestOptions,
rawReqBody: any,
rawReqBody: unknown,
cRes: http.ServerResponse,
): Promise<PoiResponseData> =>
new Promise((resolve) => {
const proxyRequest = http.request(options, (res) => {
const { statusCode, headers } = res
const resDataChunks: any[] = []
const resDataChunks: unknown[] = []

cRes.writeHead(statusCode, headers)
cRes.writeHead(statusCode || 0, headers)
res.pipe(cRes)

res.on('data', (chunk) => {
Expand Down Expand Up @@ -425,7 +435,7 @@ class Proxy extends EventEmitter {
res.writeHead(200, {
Server: 'nginx',
'Content-Length': data.length,
'Content-Type': mime.getType(cacheFile),
'Content-Type': mime.getType(cacheFile) || '',
'Last-Modified': mtime,
'Cache-Control': 'max-age=0',
})
Expand All @@ -437,15 +447,15 @@ class Proxy extends EventEmitter {
delete req.headers['proxy-connection']
req.headers['connection'] = 'close'
const remoteUrl = url.parse(`https://${req.url}`)
let remote = null
let remote: net.Socket
switch (config.get('proxy.use')) {
case 'socks5': {
// Write data directly to SOCKS5 proxy
remote = socks.createConnection({
socksHost: config.get('proxy.socks5.host', '127.0.0.1'),
socksPort: config.get('proxy.socks5.port', 1080),
host: remoteUrl.hostname,
port: remoteUrl.port,
host: remoteUrl.hostname || '',
port: remoteUrl.port || 0,
})
remote.on('connect', () => {
client.write('HTTP/1.1 200 Connection Established\r\nConnection: close\r\n\r\n')
Expand Down Expand Up @@ -479,7 +489,7 @@ class Proxy extends EventEmitter {
}
default: {
// Connect to remote directly
remote = net.connect(Number(remoteUrl.port), remoteUrl.hostname, () => {
remote = net.connect(Number(remoteUrl.port), remoteUrl.hostname || undefined, () => {
client.write('HTTP/1.1 200 Connection Established\r\nConnection: close\r\n\r\n')
remote.write(head)
client.pipe(remote)
Expand Down
13 changes: 9 additions & 4 deletions shims/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ interface ToastConfig {
title: string
}

interface Window {
toast: (message: string, config: ToastConfig) => void
}

declare global {
namespace NodeJS {
interface Global {
Expand All @@ -15,6 +11,15 @@ declare global {
DEFAULT_CACHE_PATH: string
}
}
interface Window {
toast: (message: string, config: ToastConfig) => void
}
// let and const do not show up on globalThis
/* eslint-disable no-var */
var EXROOT: string
var ROOT: string
var DEFAULT_CACHE_PATH: string
/* eslint-enable no-var */
}

export {}
Loading

0 comments on commit aa3c6ac

Please sign in to comment.