import * as stream from 'stream' ; import { session , net , app , ipcMain , BrowserWindow } from 'electron' ; import * as url from 'url' ; import * as path from 'path' ; import * as fs from 'fs' ; import * as Config from 'electron-store' ; import * as log from 'electron-log' ; import { parseAL , AL } from 'aigis-fuel' ; const config = new Config ( ) ; export class Rule { public Url : Array < string > ; public Method : string ; public Request : boolean ; public Callback : ( url : string , response , request ? : any ) => void ; constructor ( options , callback ) { this . Url = options . url ; this . Method = options . method || 'ALL' ; this . Request = options . request || false ; this . Callback = callback ; } match ( url , method ) { function checkUrl ( value ) { if ( url . indexOf ( value ) !== - 1 ) { return true ; } else { return false ; } } if ( this . Url . find ( checkUrl ) && ( this . Method === 'ALL' || this . Method === method ) ) { return true ; } return null ; } } let subscription = [ ] ; let FileList = { } ; let mainFontPath = config . get ( 'fontPath' ) ; let browserWindow ; export class RequestHandler { static setFileList ( fileList ) { FileList = fileList ; } static setFontPath ( path ) { mainFontPath = path ; } static Clear ( ) { subscription = [ ] ; } static setWin ( win ) { browserWindow = win ; } static Subscribe ( options , callback ) { subscription . push ( new Rule ( options , callback ) ) ; } static async handleData ( req , cb ) { const requestSession = session . fromPartition ( 'persist:request' ) ; if ( browserWindow ) { browserWindow . webContents . send ( 'request-incoming' ) ; } const rule = subscription . find ( value => value . match ( req . url , req . method ) ) ; const readable = new stream . PassThrough ( ) ; const gameSession = session . fromPartition ( 'persist:game' ) ; const cookies = await gameSession . cookies . get ( { url : req . url } ) ; cookies . forEach ( cookie => { requestSession . cookies . set ( { url : req . url , ... cookie } ) ; } ) ; let ModifyFilePath = '' ; if ( req . url . indexOf ( '://drc1bk94f7rq8.cloudfront.net/' ) !== - 1 ) { let modifyFileName = '' ; const reqPath = url . parse ( req . url ) . path ; let requestFileName = FileList [ reqPath ] ; if ( reqPath . indexOf ( mainFontPath ) !== - 1 ) { requestFileName = 'MainFont.aft' ; } if ( requestFileName ) { switch ( path . extname ( requestFileName ) ) { case '.atb' : modifyFileName = requestFileName . replace ( '.atb' , '.txt' ) ; break ; case '.aar' : modifyFileName = requestFileName . replace ( '.aar' , '' ) ; break ; default : modifyFileName = requestFileName ; } } const protoablePath = process . env . PORTABLE_EXECUTABLE_DIR ; const userDataPath = app . getPath ( 'userData' ) ; const modPath = protoablePath ? protoablePath + '/mods' : path . join ( userDataPath , 'mods' ) ; if ( ! fs . existsSync ( modPath ) ) { fs . mkdirSync ( modPath ) ; } const modifyFilePath = path . join ( modPath , modifyFileName ) ; if ( modifyFileName !== '' && fs . existsSync ( modifyFilePath ) ) { log . info ( requestFileName , 'modify by Server' ) ; if ( fs . existsSync ( path . join ( modPath , requestFileName ) ) ) { const fileStream = fs . createReadStream ( modifyFilePath ) ; cb ( { statusCode : 200 , data : readable } ) ; fileStream . on ( 'data' , chunk => { readable . push ( chunk ) ; } ) ; fileStream . on ( 'end' , ( ) => { readable . pause ( ) ; readable . push ( null ) ; readable . resume ( ) ; if ( browserWindow ) { browserWindow . webContents . send ( 'response-incoming' ) ; } } ) ; return ; } ModifyFilePath = modifyFilePath ; } } const request = net . request ( { method : req . method , url : req . url , session : requestSession , } ) ; if ( req . referrer ) { request . setHeader ( 'Referer' , req . referrer ) ; } Object . keys ( req . headers ) . forEach ( key => { request . setHeader ( key , req . headers [ key ] ) ; } ) ; request . setHeader ( 'If-None-Match' , " " ) ; if ( req . uploadData ) { req . uploadData . forEach ( v => { if ( v . bytes ) { request . write ( v . bytes ) ; } } ) ; } request . on ( 'response' , response => { const raws = [ ] ; let length = 0 ; let time = 10 ; const timeout = setTimeout ( ( ) => { time -- ; if ( time === 0 ) { console . log ( req . url , 'Time out' ) ; } } , 1000 ) ; cb ( { statusCode : response . statusCode , headers : response . headers , data : readable } ) ; response . on ( 'data' , chunk => { time = 10 ; if ( ! ModifyFilePath ) { readable . push ( chunk ) ; } if ( rule || ModifyFilePath ) { raws . push ( chunk ) ; } length += chunk . byteLength ; } ) ; response . on ( 'end' , ( ) => { clearTimeout ( timeout ) ; const raw = raws . length !== 0 ? Buffer . concat ( raws ) : null ; if ( ! ModifyFilePath ) { readable . pause ( ) ; readable . push ( null ) ; readable . resume ( ) ; if ( browserWindow ) { browserWindow . webContents . send ( 'response-incoming' ) ; } } else { const result = parseAL ( raw ) ; const packaged = result . Package ( ModifyFilePath ) ; readable . push ( packaged ) ; readable . pause ( ) ; readable . push ( null ) ; readable . resume ( ) ; if ( browserWindow ) { browserWindow . webContents . send ( 'response-incoming' ) ; } } if ( rule ) { const _res = raw || Buffer . concat ( raws ) ; const _req = req . uploadData ? req . uploadData [ 0 ] . bytes : null ; rule . Callback ( req . url , _res , _req ) ; } } ) ; response . on ( 'error' , err => { clearTimeout ( timeout ) ; readable . push ( null ) ; if ( browserWindow ) { browserWindow . webContents . send ( 'error-incoming' , req . url , err ) ; } log . error ( req . url , err , response . statusCode ) ; } ) ; } ) ; request . on ( 'error' , err => { log . error ( req . url , err ) ; if ( browserWindow ) { browserWindow . webContents . send ( 'error-incoming' , req . url , err ) ; } } ) ; request . end ( ) ; } }