import fs from 'fs' ; import path from 'path' ; import p from "child_process" ; import aws from "aws-sdk" ; import { BrowserWindow , app , session , ipcMain , dialog } from 'electron' ; import { searchDevtools } from 'electron-search-devtools' ; import http from 'http' ; import * as io from "socket.io" ; import AsyncLock from "async-lock" ; const bucketName = process . env . BUCKET_NAME ; console . log ( `BUCKET_NAME::::::::::::::::::::::::::::::::::${ bucketName }` ) ; var s3 = new aws . S3 ( ) ; const isDev = process . env . NODE_ENV === 'development' ; const execPath = process . platform === 'win32' ? '../node_modules/electron/dist/electron.exe' : '../node_modules/.bin/electron' ; if ( isDev ) { require ( 'electron-reload' ) ( __dirname , { electron : path . resolve ( __dirname , execPath ) , forceHardReset : true , hardResetMethod : 'exit' , } ) ; } const now = ( ) => new Date ( ) . toISOString ( ) . substr ( 14 , 9 ) ; type PlayerState = { name : string ; isDead : boolean ; isDeadDiscovered : boolean ; disconnected : boolean ; color : number ; action : number ; attendeeId ? : string ; chimeName ? : string ; } ; type GameState = { hmmAttendeeId : string ; state : number ; lobbyCode : string ; gameRegion : number ; map : number ; connectCode : string ; players : PlayerState [ ] ; } ; const initialState = { hmmAttendeeId : "" , state : 3 , lobbyCode : "" , gameRegion : 0 , map : 0 , connectCode : "" , players : [ ] , } ; var lock = new AsyncLock ( ) ; let gameState = { ... initialState , players : [ ] } ; let hostname = '0.0.0.0' ; let port = 3000 ; let protocol = 'http' ; const server = http . createServer ( { } , async ( request , response ) => { console . log ( `${ request . method } ${ request . url } BEGIN` ) ; } ) ; server . listen ( port , hostname , ( ) => { console . log ( `server listen: ${ hostname }:${ port }` ) ; } ) ; var io_server = new io . Server ( server , { allowEIO3 : true } ) ; io_server . on ( 'connection' , client => { client . on ( 'connectCode' , ( connectCode ) => { console . log ( "connectCode" , connectCode ) ; lock . acquire ( 'io_on' , async ( ) => { console . log ( "AMONG: [connectCode]" , connectCode ) ; client . connectCode = connectCode ; gameState = { ... initialState , players : [ ] } ; return 'Successful' ; } , ( error , result ) => { if ( error ) { console . log ( now ( ) , 'Connect Failure : ' , error ) ; } else { console . log ( now ( ) , 'Connect Success : ' , result ) ; } } ) ; } ) ; client . on ( 'lobby' , ( data ) => { console . log ( "lobby" , data ) ; lock . acquire ( 'io_on' , async ( ) => { console . log ( "AMONG: [lobby]" , data ) ; const lobbyData = JSON . parse ( data ) ; gameState . lobbyCode = lobbyData . LobbyCode ; gameState . gameRegion = lobbyData . Region ; gameState . map = lobbyData . Map ; client . emit ( "requestdata" , 2 ) ; return 'Successful' ; } , ( error , result ) => { if ( error ) { console . log ( now ( ) , 'Lobby Failure : ' , error ) ; } else { console . log ( now ( ) , 'Lobby Success : ' , result ) ; } } ) ; } ) ; client . on ( 'state' , ( index ) => { console . log ( "state" , index ) ; lock . acquire ( 'io_on' , async ( ) => { console . log ( "AMONG: [state]" , index ) ; if ( index == 0 || index == 3 ) { gameState . players = [ ] ; } if ( index == 2 ) { gameState . players . forEach ( x => { if ( x . isDead ) { x . isDeadDiscovered = true ; } } ) ; } gameState . state = index ; return 'Successful' ; } , ( error , result ) => { if ( error ) { console . log ( now ( ) , 'State Failure : ' , error ) ; } else { console . log ( now ( ) , 'State Success : ' , result ) ; } } ) ; } ) ; client . on ( 'player' , ( data ) => { console . log ( "player" , data ) ; lock . acquire ( 'io_on' , async ( ) => { console . log ( "AMONG: [player]" , data ) ; const playerData = JSON . parse ( data ) ; const otherPlayers = gameState . players . filter ( x => { return x . name !== playerData . Name ; } ) ; let targetPlayers = gameState . players . filter ( x => { return x . name === playerData . Name ; } ) ; if ( targetPlayers . length == 0 ) { const newPlayer = { name : playerData . Name , isDead : playerData . IsDead , isDeadDiscovered : false , disconnected : playerData . Disconnected , action : parseInt ( playerData . Action ) , color : parseInt ( playerData . Color ) } ; targetPlayers . push ( newPlayer ) ; } else { targetPlayers [ 0 ] . name = playerData . Name ; targetPlayers [ 0 ] . isDead = playerData . IsDead ; targetPlayers [ 0 ] . disconnected = playerData . Disconnected ; targetPlayers [ 0 ] . action = parseInt ( playerData . Action ) ; targetPlayers [ 0 ] . color = parseInt ( playerData . Color ) ; if ( targetPlayers [ 0 ] . action == 6 ) { targetPlayers [ 0 ] . isDeadDiscovered = true ; } } if ( parseInt ( playerData . Action ) !== 1 ) { otherPlayers . push ( ... targetPlayers ) ; } gameState . players = otherPlayers ; return 'Successful' ; } , ( error , result ) => { if ( error ) { console . log ( now ( ) , 'Player Failure : ' , error ) ; } else { console . log ( now ( ) , 'Player Success : ' , result ) ; } } ) ; } ) ; client . on ( 'disconnect' , ( ) => { console . log ( "disconnect" ) ; lock . acquire ( 'io_on' , async ( ) => { console . log ( "AMONG: [disconnect]" ) ; gameState . players = [ ] ; return 'Successful' ; } , ( error , result ) => { if ( error ) { console . log ( now ( ) , 'Disconnect Failure : ' , error ) ; } else { console . log ( now ( ) , 'Disconnect Success : ' , result ) ; } } ) ; } ) ; } ) ; const createWindow = ( ) => { const mainWindow = new BrowserWindow ( { width : 1280 , height : 960 , show : false , title : 'Electron' , frame : false , webPreferences : { preload : path . join ( __dirname , 'preload.js' ) , } , } ) ; ipcMain . handle ( 'finalize' , ( ) => { console . log ( "[main] receive finalize" ) ; mainWindow . close ( ) ; app . quit ( ) ; } ) ; const generateAndStoreRecord = ( file , data ) => { const dstDir = "/tmp" ; const dateString = getDateString ( ) ; const dstFilenameWebm = `${ dateString }_${ file }.webm` ; const dstFilenameMP4 = `${ dateString }_${ file }.mp4` ; const dstPathWebm = `${ dstDir }/${ dstFilenameWebm }` ; const dstPathMP4 = `${ dstDir }/${ dstFilenameMP4 }` ; if ( ! fs . existsSync ( dstDir ) ) { try { fs . mkdirSync ( dstDir ) ; } catch ( e ) { console . log ( e ) ; } } fs . writeFileSync ( dstPathWebm , data ) ; var fileStream = fs . createReadStream ( dstPathWebm ) ; const params = { Body : fileStream , Bucket : bucketName ! , Key : `recording/${ dstFilenameWebm }` } ; s3 . putObject ( params ) . promise ( ) . then ( x => { console . log ( "S3 SUCCESS" , JSON . stringify ( x ) ) ; } ) . catch ( e => { console . log ( "S3 ERROR" , JSON . stringify ( e ) ) ; } ) ; } ; ipcMain . handle ( 'recorder-data-available1' , ( ev , file , data ) => { console . log ( data ) ; generateAndStoreRecord ( file , data ) ; } ) ; ipcMain . handle ( 'recorder-data-available2' , ( ev , file , data ) => { console . log ( data ) ; generateAndStoreRecord ( file , data ) ; } ) ; if ( isDev ) mainWindow . webContents . openDevTools ( { mode : 'detach' } ) ; mainWindow . loadFile ( 'dist/index.html' ) ; mainWindow . once ( 'ready-to-show' , ( ) => mainWindow . show ( ) ) ; const uploadGameState = ( ) => { console . log ( "upload game state!" ) ; lock . acquire ( 'io_on' , async ( ) => { mainWindow . webContents . send ( 'amongus-gamestate-updated' , JSON . stringify ( gameState ) ) ; return 'Successful' ; } , ( error , result ) => { if ( error ) { } else { console . log ( now ( ) , 'Upload game state Success : ' , result ) ; } setTimeout ( ( ) => { uploadGameState ( ) ; } , 1000 * 1 ) ; } ) ; } ; uploadGameState ( ) ; } ; app . whenReady ( ) . then ( async ( ) => { if ( isDev ) { const devtools = await searchDevtools ( 'REACT' ) ; if ( devtools ) { await session . defaultSession . loadExtension ( devtools , { allowFileAccess : true , } ) ; } } createWindow ( ) ; } ) ; const getDateString = ( ) => { const date = new Date ( ) ; const Y = date . getFullYear ( ) ; const M = ( "00" + ( date . getMonth ( ) + 1 ) ) . slice ( - 2 ) ; const D = ( "00" + date . getDate ( ) ) . slice ( - 2 ) ; const h = ( "00" + date . getHours ( ) ) . slice ( - 2 ) ; const m = ( "00" + date . getMinutes ( ) ) . slice ( - 2 ) ; const s = ( "00" + date . getSeconds ( ) ) . slice ( - 2 ) ; return Y + M + D + h + m + s ; } ; app . once ( 'window-all-closed' , ( ) => app . quit ( ) ) ;