This repository has been archived by the owner on Sep 15, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGameManagerWorkerInterface.ts
170 lines (156 loc) · 6.36 KB
/
GameManagerWorkerInterface.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import { GameCreationOptions } from '../rules/GameCreationOptions'
import { GameState, Move } from '../rules/CurrentGame'
import { MessageContent } from '../rules/Message'
import { Logger } from '../Logger'
import { Backend } from './Backend'
import * as path from 'path'
import * as portfinder from 'portfinder'
import * as child_process from 'child_process'
import { ExecutableStatus } from '../rules/ExecutableStatus'
import promiseRetry = require('promise-retry')
export interface GameServerInfo {
status: ExecutableStatus.Status
port: number
error: String
}
export class GameManagerWorkerInterface {
worker: child_process.ChildProcess
private backend: Promise<Backend>
constructor() {
Logger.getLogger().log('GameManagerWorkerInterface', 'constructor', 'Forking GameManagerWorker.')
const fork: any = child_process.fork //disable typechecking, one faulty line causes everything to fail
console.log('SGC_LOG_PATH:' + process.env.SGC_LOG_PATH)
//this.worker = child_process.spawn(process.execPath, [path.join(__dirname, '/../asynchronous/GameManagerWorker.js')], { env: { "SGC_LOG_PATH": process.env.SGC_LOG_PATH } })
this.backend = portfinder.getPortPromise({ port: 12000 })
.then((port) => {
return new Backend(port)
})
this.backend.then(backend => {
this.worker = fork(
path.join(__dirname, '/../asynchronous/GameManagerWorker.js'), {
execArgv: process.execArgv,
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
env: {
'SGC_LOG_PATH': process.env.SGC_LOG_PATH,
'GAME_MANAGER_WORKER_PORT': backend.getPort(),
},
},
)
})
}
private fetchBackend(query: string, init?: RequestInit) {
return this.backend.then(backend => fetch(backend.urlFor('/' + query), init))
}
/** Requests a list of the names of the games currently loaded in the worker */
getListOfGames(retries: number = 3) {
return promiseRetry(retry => {
return this.fetchBackend('list-games')
.then(r => r.json())
.catch(retry)
}, {
minTimeout: 150,
retries: retries,
}).catch(e => Logger.getLogger().logError('GameManagerWorkerInterface', 'getListOfGames', 'Error getting list of games: ' + e, e))
}
/**
* Requests the creation of a new game with the given options
* @returns Promise containing the gameId
*/
createGameWithOptions(options: GameCreationOptions) {
console.log('Creating game ' + options.gameName + ' with id ' + options.gameId)
return this.fetchBackend('start-game', {
method: 'POST',
body: JSON.stringify(options),
headers: new Headers({
'Content-Type': 'application/json',
}),
}).then(r => {
return r.json().catch(() => r.text()).then(c => {
if (r.ok) {
return c
} else {
throw c
}
})
}).then(t => {
console.log('Created game with id ' + t)
return parseInt(t)
})
}
deleteGame(gameId: number) {
this.fetchBackend('delete-game?id=' + gameId)
}
saveReplayOfGame(gameId: number, path: string) {
console.log('Saving replay of game with id ' + gameId + ' to ' + path)
this.fetchBackend('save-replay', {
method: 'POST',
body: JSON.stringify({ gameId: gameId, path: path }),
headers: new Headers({
'Content-Type': 'application/json',
}),
})
.catch(e => Logger.getLogger().logError('GameManagerWorkerInterface', 'saveReplayOfGame', 'Error saving replay of a game: ' + e, e))
}
/** Requests the gameState for the given turn and game. */
getState(gameId: number, turn: number) {
return this.fetchBackend(`state?id=${gameId}&turn=${turn}`)
.then(r => r.json())
.then(state => {
let gs = GameState.lift(state)
console.log('Got gamestate from backend:', gs)
return gs
})
}
/**
* Requests the status of a given game
*/
getStatus(gameId: number): Promise<MessageContent.StatusReportContent> {
return this.fetchBackend(`status?id=${gameId}`)
.then(r => r.json())
.catch(e => Logger.getLogger().logError('GameManagerWorkerInterface', 'getStatus', 'Error getting status: ' + e, e))
}
/**
* Sends a Move for an action request with id to the worker
* @returns a Promise containing the gameId
*/
sendMove(gameId: number, id: number, move: Move): Promise<number> {
return this.fetchBackend(`send-move?id=${gameId}&moveId=${id}`, {
method: 'POST',
body: JSON.stringify(move),
headers: new Headers({
'Content-Type': 'application/json',
}),
}).then(response => {
response.text().then(value => {
Logger.getLogger().log('GameManagerWorkerInterface', 'sendMove', 'Server response: ' + value)
this.getGameServerStatus().then(serverStatus => {
// Dieser Fall tritt anscheinend nie ein, da der Server keinen solchen Code sendet? if (serverStatus.status == ExecutableStatus.Status.ERROR) {
if (serverStatus.error.toLowerCase().indexOf('error') > 0) {
const ipc = require('electron').ipcRenderer
ipc.send('showGameErrorBox', 'Spiel wurde beendet', gameId, 'Nach senden des Moves: \n' + JSON.stringify(move) + '\nkam es zu folgendem Fehler:\n\n' + serverStatus.error
+ '\n\nSollte dieser Fehler noch nicht auf Github unter: https://github.com/CAU-Kiel-Tech-Inf/socha-gui/issues/ gemeldet sein, melde doch bitte diesen Fehler.\nInfolge dieses Fehlers kam es zur Beendigung dieses Spiels.')
return -1
}
})
})
return gameId
})
}
stop() {
return this.fetchBackend('stop', { method: 'POST' })
.then(t => t.text())
.then(t => Logger.getLogger().log('GameManagerWorkerInterface', 'stop', 'received server message: ' + t))
.catch(e => Logger.getLogger().logError('GameManagerWorkerInterface', 'stop', 'Error stopping backend: ' + e, e))
}
getGameServerStatus(): Promise<GameServerInfo> {
return this.fetchBackend('server-info')
.then(t => t.json().then(j => {
console.log('got getGameServerStatus ', j)
return j as GameServerInfo
}))
.catch(e => {
Logger.getLogger().logError('GameManagerWorkerInterface', 'getGameServerStatus', 'Error getting game server info: ' + e, e)
return Promise.reject(e)
})
}
}