homegames-common 1.4.2 → 1.5.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.
- package/docker-helper.js +396 -0
- package/game-loader.js +214 -0
- package/game-session-manager.js +693 -0
- package/game-session.js +600 -0
- package/index.js +96 -624
- package/package.json +5 -1
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const https = require('https');
|
|
2
|
+
const http = require('http');
|
|
2
3
|
const readline = require('readline');
|
|
3
4
|
const WebSocket = require('ws');
|
|
4
|
-
const http = require('http');
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const unzipper = require('unzipper');
|
|
@@ -10,10 +10,6 @@ const { Readable } = require('stream');
|
|
|
10
10
|
const os = require('os');
|
|
11
11
|
const process = require('process');
|
|
12
12
|
|
|
13
|
-
const getUserHash = (username) => {
|
|
14
|
-
return crypto.createHash('md5').update(username).digest('hex');
|
|
15
|
-
};
|
|
16
|
-
|
|
17
13
|
const DEFAULT_CONFIG = {
|
|
18
14
|
"HTTPS_ENABLED": true,
|
|
19
15
|
"LINK_ENABLED": true,
|
|
@@ -37,36 +33,19 @@ const DEFAULT_CONFIG = {
|
|
|
37
33
|
"API_URL": "https://api.homegames.io",
|
|
38
34
|
"LINK_PROXY_URL": "wss://public.homegames.link:81",
|
|
39
35
|
"LINK_URL": "wss://homegames.link",
|
|
40
|
-
"MAP_ENABLED": true
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const getLocalIP = () => {
|
|
44
|
-
const ifaces = os.networkInterfaces();
|
|
45
|
-
let localIP;
|
|
46
|
-
|
|
47
|
-
Object.keys(ifaces).forEach((ifname) => {
|
|
48
|
-
ifaces[ifname].forEach((iface) => {
|
|
49
|
-
if ('IPv4' !== iface.family || iface.internal) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
localIP = localIP || iface.address;
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
return localIP;
|
|
36
|
+
"MAP_ENABLED": true
|
|
57
37
|
};
|
|
58
38
|
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// HTTP helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
59
43
|
const getUrl = (url, headers = {}) => new Promise((resolve, reject) => {
|
|
60
44
|
const getModule = url.startsWith('https') ? https : http;
|
|
61
45
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
getModule.get(url, { headers } , (res) => {
|
|
46
|
+
getModule.get(url, { headers }, (res) => {
|
|
65
47
|
const bufs = [];
|
|
66
|
-
res.on('data', (chunk) => {
|
|
67
|
-
bufs.push(chunk);
|
|
68
|
-
});
|
|
69
|
-
|
|
48
|
+
res.on('data', (chunk) => { bufs.push(chunk); });
|
|
70
49
|
res.on('end', () => {
|
|
71
50
|
if (res.statusCode > 199 && res.statusCode < 300) {
|
|
72
51
|
resolve(Buffer.concat(bufs));
|
|
@@ -74,17 +53,13 @@ const getUrl = (url, headers = {}) => new Promise((resolve, reject) => {
|
|
|
74
53
|
reject(Buffer.concat(bufs));
|
|
75
54
|
}
|
|
76
55
|
});
|
|
77
|
-
}).on('error',
|
|
78
|
-
reject(error);
|
|
79
|
-
});
|
|
80
|
-
|
|
56
|
+
}).on('error', reject);
|
|
81
57
|
});
|
|
82
58
|
|
|
83
|
-
const postUrl = (url,
|
|
59
|
+
const postUrl = (url, urlPath, _payload, headers = {}) => new Promise((resolve, reject) => {
|
|
84
60
|
const payload = JSON.stringify(_payload);
|
|
85
61
|
|
|
86
62
|
let module, hostname, port;
|
|
87
|
-
|
|
88
63
|
if (url.startsWith('https')) {
|
|
89
64
|
module = https;
|
|
90
65
|
port = 443;
|
|
@@ -93,654 +68,151 @@ const postUrl = (url, path, _payload, headers = {}) => new Promise((resolve, rej
|
|
|
93
68
|
module = http;
|
|
94
69
|
port = 80;
|
|
95
70
|
hostname = url.replace('http://', '');
|
|
96
|
-
}
|
|
71
|
+
}
|
|
97
72
|
|
|
98
73
|
Object.assign(headers, {
|
|
99
74
|
'Content-Type': 'application/json',
|
|
100
75
|
'Content-Length': payload.length
|
|
101
76
|
});
|
|
102
77
|
|
|
103
|
-
const options = {
|
|
104
|
-
hostname,
|
|
105
|
-
path,
|
|
106
|
-
port,
|
|
107
|
-
method: 'POST',
|
|
108
|
-
headers
|
|
109
|
-
};
|
|
110
|
-
|
|
111
78
|
let responseData = '';
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
res.on('
|
|
115
|
-
responseData += chunk;
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
res.on('end', () => {
|
|
119
|
-
resolve(responseData);
|
|
120
|
-
});
|
|
79
|
+
const req = module.request({ hostname, path: urlPath, port, method: 'POST', headers }, (res) => {
|
|
80
|
+
res.on('data', (chunk) => { responseData += chunk; });
|
|
81
|
+
res.on('end', () => { resolve(responseData); });
|
|
121
82
|
});
|
|
122
|
-
|
|
83
|
+
req.on('error', reject);
|
|
123
84
|
req.write(payload);
|
|
124
85
|
req.end();
|
|
125
86
|
});
|
|
126
87
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
resolve();
|
|
131
|
-
} else {
|
|
132
|
-
fs.mkdir(dir, (thing) => {
|
|
133
|
-
resolve();
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const guaranteeCertFiles = (dir) => new Promise((resolve, reject) => {
|
|
140
|
-
|
|
141
|
-
let certPath, keyPath;
|
|
142
|
-
|
|
143
|
-
fs.readdir(dir, (err, files) => {
|
|
144
|
-
files.forEach(file => {
|
|
145
|
-
if (file === 'cert.pem') {
|
|
146
|
-
certPath = path.join(dir, file);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (file === 'key.pem') {
|
|
150
|
-
keyPath = path.join(dir, file);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
if (!certPath) {
|
|
155
|
-
reject('Could not find cert.pem');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!keyPath) {
|
|
159
|
-
reject('Could not find key.pem');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
resolve({
|
|
163
|
-
certPath,
|
|
164
|
-
keyPath
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const validateCertData = (certPaths, username, accessToken) => new Promise((resolve, reject) => {
|
|
171
|
-
// one day
|
|
172
|
-
resolve(JSON.stringify({success: true}));
|
|
173
|
-
// postUrl('https://certifier.homegames.io', '/verify', {
|
|
174
|
-
// checksum: ''
|
|
175
|
-
// },
|
|
176
|
-
// {
|
|
177
|
-
// 'hg-username': username,
|
|
178
|
-
// 'hg-access-token': accessToken
|
|
179
|
-
// }).then(data => {
|
|
180
|
-
// resolve(data);
|
|
181
|
-
// }).catch(err => {
|
|
182
|
-
// reject({
|
|
183
|
-
// message: err.toString()
|
|
184
|
-
// });
|
|
185
|
-
// });
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Filesystem helpers
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
186
91
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const validateExistingCerts = (certPath, username, accessToken) => new Promise((resolve, reject) => {
|
|
190
|
-
guaranteeDir(certPath).then(() => {
|
|
191
|
-
guaranteeCertFiles(certPath).then((certPaths) => {
|
|
192
|
-
validateCertData(certPath, username, accessToken).then((response) => {
|
|
193
|
-
const data = JSON.parse(response);
|
|
194
|
-
if (data.success) {
|
|
195
|
-
resolve();
|
|
196
|
-
} else {
|
|
197
|
-
getCertData(username, accessToken).then(certData => {
|
|
198
|
-
validateCertData(certPath, username, accessToken).then((response) => {
|
|
199
|
-
const data = JSON.parse(response);
|
|
200
|
-
if (data.success) {
|
|
201
|
-
storeCertData(certData, certPath).then(() => {
|
|
202
|
-
resolve();
|
|
203
|
-
});
|
|
204
|
-
} else {
|
|
205
|
-
reject(data);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}).catch(err => {
|
|
211
|
-
console.log(err);
|
|
212
|
-
reject(err);
|
|
213
|
-
});
|
|
214
|
-
}).catch(err => {
|
|
215
|
-
console.log(err);
|
|
216
|
-
getCertData(username, accessToken).then(certData => {
|
|
217
|
-
validateCertData(certPath, username, accessToken).then((response) => {
|
|
218
|
-
const data = JSON.parse(response);
|
|
219
|
-
if (data.success) {
|
|
220
|
-
storeCertData(certData, certPath).then(() => {
|
|
221
|
-
resolve();
|
|
222
|
-
});
|
|
223
|
-
} else {
|
|
224
|
-
reject(data);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
const guaranteeLoginFile = (loginPath) => new Promise((resolve, reject) => {
|
|
233
|
-
fs.exists(path.join(loginPath, 'config'), (exists) => {
|
|
92
|
+
const guaranteeDir = (dir) => new Promise((resolve) => {
|
|
93
|
+
fs.exists(dir, (exists) => {
|
|
234
94
|
if (exists) {
|
|
235
95
|
resolve();
|
|
236
96
|
} else {
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
const validateLoginData = (loginPath) => new Promise((resolve, reject) => {
|
|
243
|
-
guaranteeDir(loginPath).then(() => {
|
|
244
|
-
guaranteeLoginFile(loginPath).then((loginData) => {
|
|
245
|
-
resolve(loginData);
|
|
246
|
-
}).catch(() => {
|
|
247
|
-
reject('could not find login file');
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
const certInit = (certPath, loginPath) => new Promise((resolve, reject) => {
|
|
253
|
-
validateExistingCerts(certPath).then((certData) => {
|
|
254
|
-
}).catch(err => {
|
|
255
|
-
validateLoginData(loginPath).then((loginData) => {
|
|
256
|
-
getUrl('https://certifier.homegames.io/get-certs').then(data => {
|
|
257
|
-
resolve(data);
|
|
258
|
-
}).catch(err => {
|
|
259
|
-
});
|
|
260
|
-
}).catch(err => {
|
|
261
|
-
reject(err);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
const signup = (username, email, password) => new Promise((resolve, reject) => {
|
|
267
|
-
postUrl('https://auth.homegames.io', '/', {
|
|
268
|
-
email,
|
|
269
|
-
username,
|
|
270
|
-
password,
|
|
271
|
-
type: 'signUp'
|
|
272
|
-
}).then(data => {
|
|
273
|
-
resolve(data);
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
const confirmUser = (username, code) => new Promise((resolve, reject) => {
|
|
278
|
-
postUrl('https://auth.homegames.io', '/', {
|
|
279
|
-
username,
|
|
280
|
-
code,
|
|
281
|
-
type: 'confirmUser'
|
|
282
|
-
}).then(data => {
|
|
283
|
-
resolve(data);
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
const login = (username, password) => new Promise((resolve, reject) => {
|
|
288
|
-
postUrl('https://auth.homegames.io', '/', {
|
|
289
|
-
type: 'login',
|
|
290
|
-
username,
|
|
291
|
-
password
|
|
292
|
-
}).then(_data => {
|
|
293
|
-
const data = JSON.parse(_data);
|
|
294
|
-
if (data.errorType) {
|
|
295
|
-
reject(data);
|
|
296
|
-
} else {
|
|
297
|
-
resolve(data);
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const refreshAccessToken = (username, tokens) => new Promise((resolve, reject) => {
|
|
303
|
-
postUrl('https://auth.homegames.io', '/', {
|
|
304
|
-
type: 'refresh',
|
|
305
|
-
username,
|
|
306
|
-
accessToken: tokens.accessToken,
|
|
307
|
-
refreshToken: tokens.refreshToken,
|
|
308
|
-
idToken: tokens.idToken
|
|
309
|
-
}).then(_data => {
|
|
310
|
-
const data = JSON.parse(_data);
|
|
311
|
-
if (data.accessToken && data.refreshToken) {
|
|
312
|
-
resolve(data);
|
|
313
|
-
} else {
|
|
314
|
-
reject();
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
const verifyAccessToken = (username, accessToken) => new Promise((resolve, reject) => {
|
|
320
|
-
postUrl('https://auth.homegames.io', '/', {
|
|
321
|
-
type: 'verify',
|
|
322
|
-
username,
|
|
323
|
-
accessToken
|
|
324
|
-
}).then(_data => {
|
|
325
|
-
const data = JSON.parse(_data);
|
|
326
|
-
if (data.errorType) {
|
|
327
|
-
reject(data);
|
|
328
|
-
} else {
|
|
329
|
-
resolve(data);
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
const getLoginInfo = (authPath) => new Promise((resolve, reject) => {
|
|
335
|
-
fs.exists(authPath, (exists) => {
|
|
336
|
-
if (exists) {
|
|
337
|
-
fs.readFile(authPath, (err, _data) => {
|
|
338
|
-
let data;
|
|
339
|
-
|
|
340
|
-
if (!_data) {
|
|
341
|
-
reject({type: 'DATA_NOT_FOUND'});
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
try {
|
|
345
|
-
data = JSON.parse(_data);
|
|
346
|
-
if (!data.username || !data.tokens || data.errorType) {
|
|
347
|
-
throw new Error();
|
|
348
|
-
}
|
|
349
|
-
} catch (err) {
|
|
350
|
-
reject({
|
|
351
|
-
type: 'DATA_READ_ERROR',
|
|
352
|
-
message: err
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (err) {
|
|
357
|
-
reject({
|
|
358
|
-
type: 'DATA_READ_ERROR',
|
|
359
|
-
message: err
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
resolve(data);
|
|
364
|
-
});
|
|
365
|
-
} else {
|
|
366
|
-
reject({type: 'DATA_NOT_FOUND'});
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
const getCertData = (username, accessToken) => new Promise((resolve, reject) => {
|
|
372
|
-
|
|
373
|
-
getUrl('https://certifier.homegames.io/get-cert', {
|
|
374
|
-
|
|
375
|
-
'hg-username': username,
|
|
376
|
-
'hg-token': accessToken
|
|
377
|
-
}).then(data => {
|
|
378
|
-
resolve(data);
|
|
379
|
-
}).catch(err => {
|
|
380
|
-
console.log(err.toString());
|
|
381
|
-
console.log('that was an error');
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
const bufToStream = (buf) => {
|
|
386
|
-
return new Readable({
|
|
387
|
-
read() {
|
|
388
|
-
this.push(buf);
|
|
389
|
-
this.push(null);
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
// unzip a cert bundle to the given path
|
|
395
|
-
const storeCertData = (certBundle, path) => new Promise((resolve, reject) => {
|
|
396
|
-
const certStream = bufToStream(certBundle);
|
|
397
|
-
|
|
398
|
-
const unzip = unzipper.Extract({ path });
|
|
399
|
-
certStream.pipe(unzip);
|
|
400
|
-
|
|
401
|
-
unzip.on('close', resolve);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
const storeTokens = (path, username, tokens) => new Promise((resolve, reject) => {
|
|
405
|
-
const pathPieces = path.split('/');
|
|
406
|
-
let pathParent = [];
|
|
407
|
-
for (let x in pathPieces) {
|
|
408
|
-
if (x == pathPieces.length - 1) {
|
|
409
|
-
break
|
|
410
|
-
} else {
|
|
411
|
-
pathParent.push(pathPieces[x]);
|
|
97
|
+
fs.mkdir(dir, { recursive: true }, () => { resolve(); });
|
|
412
98
|
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
guaranteeDir(pathParent.join('/')).then(() => {
|
|
416
|
-
const authData = {
|
|
417
|
-
username,
|
|
418
|
-
tokens
|
|
419
|
-
};
|
|
420
|
-
fs.writeFile(path, JSON.stringify(authData), (err) => {
|
|
421
|
-
if (err) {
|
|
422
|
-
reject('Failed to store tokens');
|
|
423
|
-
} else {
|
|
424
|
-
resolve();
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
const guaranteeCerts = (authPath, certPath) => new Promise((resolve, reject) => {
|
|
431
|
-
|
|
432
|
-
authWorkflow(authPath).then(authInfo => {
|
|
433
|
-
getCertData(authInfo.username, authInfo.tokens.accessToken).then(certData => {
|
|
434
|
-
validateCertData(certPath, authInfo.username, authInfo.tokens.accessToken).then((response) => {
|
|
435
|
-
const data = JSON.parse(response);
|
|
436
|
-
if (data.success) {
|
|
437
|
-
storeCertData(certData, certPath).then(() => {
|
|
438
|
-
resolve({
|
|
439
|
-
certPath: `${certPath}/cert.pem`,
|
|
440
|
-
keyPath: `${certPath}/key.pem`,
|
|
441
|
-
});
|
|
442
|
-
});
|
|
443
|
-
} else {
|
|
444
|
-
reject(data);
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
}).catch(err => {
|
|
448
|
-
reject({message: err});
|
|
449
|
-
});
|
|
450
|
-
}).catch(err => {
|
|
451
|
-
console.log(err);
|
|
452
|
-
});
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
const linkInit = (authPath) => new Promise((resolve, reject) => {
|
|
456
|
-
|
|
457
|
-
getLoginInfo(authPath).then((loginInfo) => {
|
|
458
|
-
const client = new WebSocket('wss://homegames.link:7080');
|
|
459
|
-
|
|
460
|
-
client.on('open', () => {
|
|
461
|
-
console.log('opened connection to link');
|
|
462
|
-
client.send(JSON.stringify({
|
|
463
|
-
ip: getLocalIP(),
|
|
464
|
-
username: loginInfo.username,
|
|
465
|
-
accessToken: loginInfo.tokens.accessToken
|
|
466
|
-
}));
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
client.on('error', (err) => {
|
|
470
|
-
console.log('some error happened');
|
|
471
|
-
console.log(err);
|
|
472
|
-
});
|
|
473
99
|
});
|
|
474
|
-
|
|
475
100
|
});
|
|
476
101
|
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
input: process.stdin,
|
|
480
|
-
output: process.stdout
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
rl.question('username:\n', (username) => {
|
|
484
|
-
rl.question('password:\n', (password) => {
|
|
485
|
-
resolve({
|
|
486
|
-
username,
|
|
487
|
-
password
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
});
|
|
491
|
-
});
|
|
102
|
+
const getAppDataPath = () => {
|
|
103
|
+
if (!process) return '';
|
|
492
104
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
pathParent.push(pathPieces[x]);
|
|
508
|
-
}
|
|
105
|
+
let _path;
|
|
106
|
+
switch (process.platform) {
|
|
107
|
+
case "darwin":
|
|
108
|
+
_path = process.env.HOME ? path.join(process.env.HOME, "Library", "Application Support", "homegames") : __dirname;
|
|
109
|
+
break;
|
|
110
|
+
case "win32":
|
|
111
|
+
_path = process.env.APPDATA ? path.join(process.env.APPDATA, "homegames") : __dirname;
|
|
112
|
+
break;
|
|
113
|
+
case "linux":
|
|
114
|
+
_path = process.env.HOME ? path.join(process.env.HOME, ".homegames") : __dirname;
|
|
115
|
+
break;
|
|
116
|
+
default:
|
|
117
|
+
console.log("Unsupported platform!");
|
|
118
|
+
process.exit(1);
|
|
509
119
|
}
|
|
510
120
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
console.log(lockPath);
|
|
514
|
-
fs.writeFile(lockPath, 'lock', 'utf-8', () => {
|
|
515
|
-
clearInterval(_interval);
|
|
516
|
-
fs.readFile(lockPath, (err, data) => {
|
|
517
|
-
if (err) {
|
|
518
|
-
console.log(err);
|
|
519
|
-
reject(err);
|
|
520
|
-
} else {
|
|
521
|
-
resolve();
|
|
522
|
-
}
|
|
523
|
-
});
|
|
524
|
-
});
|
|
525
|
-
});
|
|
526
|
-
} else {
|
|
527
|
-
console.log('waiting for lock');
|
|
528
|
-
const { birthtime } = fs.statSync(lockPath);
|
|
529
|
-
const fiveMinsAgo = Date.now() - ( 1000 * 60 * 5 );
|
|
530
|
-
console.log(birthtime);
|
|
531
|
-
if (new Date(birthtime).getTime() < fiveMinsAgo) {
|
|
532
|
-
fs.unlink(lockPath, (err) => {
|
|
533
|
-
console.log(err);
|
|
534
|
-
console.log('deleted');
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
_interval = setInterval(acquireLock, 1000);
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
const unlockFile = (path) => new Promise((resolve, reject) => {
|
|
546
|
-
const lockPath = `${path}.hglock`;
|
|
547
|
-
|
|
548
|
-
fs.readFile(lockPath, (err, data) => {
|
|
549
|
-
fs.unlink(lockPath, (err) => {
|
|
550
|
-
if (!err) {
|
|
551
|
-
resolve();
|
|
552
|
-
} else {
|
|
553
|
-
reject('Could not delete lock');
|
|
554
|
-
}
|
|
555
|
-
});
|
|
556
|
-
});
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
const authWorkflow = (authPath) => new Promise((resolve, reject) => {
|
|
560
|
-
if (!authPath) {
|
|
561
|
-
reject(`No authPath provided`);
|
|
121
|
+
if (!fs.existsSync(_path)) {
|
|
122
|
+
fs.mkdirSync(_path, { recursive: true });
|
|
562
123
|
}
|
|
563
124
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
login(loginInfo.username, loginInfo.password).then(tokens => {
|
|
567
|
-
storeTokens(authPath, loginInfo.username, tokens).then(() => {
|
|
568
|
-
verifyAccessToken(loginInfo.username, tokens.accessToken).then(() => {
|
|
569
|
-
unlockFile(authPath).then(() => {
|
|
570
|
-
resolve({
|
|
571
|
-
username: loginInfo.username,
|
|
572
|
-
tokens
|
|
573
|
-
});
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
});
|
|
577
|
-
}).catch(err => {
|
|
578
|
-
console.log('Failed to store auth tokens');
|
|
579
|
-
reject(err);
|
|
580
|
-
});
|
|
581
|
-
}).catch(err => {
|
|
582
|
-
console.log('Failed to login');
|
|
583
|
-
reject(err);
|
|
584
|
-
});
|
|
585
|
-
});
|
|
586
|
-
};
|
|
587
|
-
|
|
588
|
-
console.log('about to lock ' + authPath);
|
|
589
|
-
lockFile(authPath).then(() => {
|
|
590
|
-
getLoginInfo(authPath).then((loginInfo) => {
|
|
591
|
-
verifyAccessToken(loginInfo.username, loginInfo.tokens.accessToken).then(() => {
|
|
592
|
-
unlockFile(authPath).then(() => {
|
|
593
|
-
resolve(loginInfo);
|
|
594
|
-
});
|
|
595
|
-
}).catch(err => {
|
|
596
|
-
console.log('failed to verify access token');
|
|
597
|
-
_doLogin();
|
|
598
|
-
});
|
|
599
|
-
}).catch((err) => {
|
|
600
|
-
console.log(err);
|
|
601
|
-
if (err.type === 'DATA_NOT_FOUND') {
|
|
602
|
-
_doLogin();
|
|
603
|
-
}
|
|
604
|
-
});
|
|
605
|
-
}).catch(err => {
|
|
606
|
-
console.log(err);
|
|
607
|
-
console.log("Failed to acquire lock");
|
|
608
|
-
});
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
let electronLog = null;
|
|
612
|
-
try {
|
|
613
|
-
electronLog = require('electron-log');
|
|
614
|
-
} catch (err) {
|
|
615
|
-
console.log('not running with electron');
|
|
616
|
-
}
|
|
125
|
+
return _path;
|
|
126
|
+
};
|
|
617
127
|
|
|
618
|
-
const
|
|
128
|
+
const log = {
|
|
129
|
+
info: (msg) => console.log(msg),
|
|
130
|
+
error: (msg) => console.error(msg),
|
|
131
|
+
debug: (msg) => console.log(msg),
|
|
132
|
+
};
|
|
619
133
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
require(process.env.LOGGER_LOCATION) : defaultLog
|
|
624
|
-
) : electronLog;
|
|
625
|
-
|
|
626
|
-
log.info('doing this');
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Config
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
627
137
|
|
|
628
138
|
const getConfigValue = (key, _default = undefined) => {
|
|
629
139
|
const config = getConfig();
|
|
630
140
|
|
|
631
141
|
let envValue = process.env[key] && `${process.env[key]}`;
|
|
632
142
|
if (envValue !== undefined) {
|
|
633
|
-
if (envValue === 'true')
|
|
634
|
-
|
|
635
|
-
} else if (envValue === 'false') {
|
|
636
|
-
envValue = false;
|
|
637
|
-
}
|
|
143
|
+
if (envValue === 'true') envValue = true;
|
|
144
|
+
else if (envValue === 'false') envValue = false;
|
|
638
145
|
log.info(`Using environment value: ${envValue} for key: ${key}`);
|
|
639
146
|
return envValue;
|
|
640
147
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
148
|
+
|
|
149
|
+
if (config[key] === undefined && _default === undefined) {
|
|
150
|
+
throw new Error(`No value for ${key} found in config`);
|
|
151
|
+
} else if (config[key] === undefined && _default !== undefined) {
|
|
152
|
+
log.info(`Using default value (${_default}) for ${key}`);
|
|
153
|
+
return DEFAULT_CONFIG[key] || _default;
|
|
154
|
+
}
|
|
155
|
+
log.info(`Found value ${config[key]} for ${key} in config`);
|
|
156
|
+
return config[key];
|
|
649
157
|
};
|
|
650
158
|
|
|
651
159
|
let cachedConfig = {};
|
|
652
160
|
|
|
653
161
|
const getConfig = () => {
|
|
162
|
+
if (Object.keys(cachedConfig).length > 0) return cachedConfig;
|
|
654
163
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
}
|
|
164
|
+
const options = [getAppDataPath(), process.cwd()];
|
|
165
|
+
try { options.push(path.dirname(require.main.filename)); } catch (e) {}
|
|
166
|
+
try { options.push(path.dirname(process.mainModule.filename)); } catch (e) {}
|
|
167
|
+
options.push(__dirname);
|
|
658
168
|
|
|
659
|
-
const options = [getAppDataPath(), process.cwd(), require.main.filename, process.mainModule.filename, __dirname]
|
|
660
169
|
let _config = null;
|
|
661
|
-
let configPath = null;
|
|
662
|
-
|
|
663
170
|
for (let i = 0; i < options.length; i++) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
if (!_config) {
|
|
673
|
-
_config = DEFAULT_CONFIG;
|
|
171
|
+
try {
|
|
172
|
+
if (fs.existsSync(`${options[i]}/config.json`)) {
|
|
173
|
+
log.info(`Found config at ${options[i]}`);
|
|
174
|
+
_config = JSON.parse(fs.readFileSync(`${options[i]}/config.json`));
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
} catch (e) {}
|
|
674
178
|
}
|
|
675
179
|
|
|
676
|
-
|
|
677
|
-
log.info(_config);
|
|
180
|
+
if (!_config) _config = DEFAULT_CONFIG;
|
|
678
181
|
|
|
679
182
|
cachedConfig = _config;
|
|
680
|
-
|
|
681
183
|
return _config;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
const getLogLevel = (logLevel = null) => {
|
|
686
|
-
const _logLevel = logLevel || getConfigValue('LOG_LEVEL', 'INFO');
|
|
687
|
-
const levelList = ['DISABLED', 'INFO', 'DEBUG'];
|
|
688
|
-
|
|
689
|
-
return levelList.indexOf(_logLevel);
|
|
690
184
|
};
|
|
691
185
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Shared modules
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
695
189
|
|
|
696
|
-
const
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
let _path;
|
|
703
|
-
switch (process.platform) {
|
|
704
|
-
case "darwin": {
|
|
705
|
-
_path = process.env.HOME ? path.join(process.env.HOME, "Library", "Application Support", "homegames") : __dirname;
|
|
706
|
-
break;
|
|
707
|
-
}
|
|
708
|
-
case "win32": {
|
|
709
|
-
_path = process.env.APPDATA ? path.join(process.env.APPDATA, "homegames") : __dirname;
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
|
-
case "linux": {
|
|
713
|
-
_path = process.env.HOME ? path.join(process.env.HOME, ".homegames") : __dirname;
|
|
714
|
-
break;
|
|
715
|
-
}
|
|
716
|
-
default: {
|
|
717
|
-
console.log("Unsupported platform!");
|
|
718
|
-
process.exit(1);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
if (!fs.existsSync(_path)) {
|
|
723
|
-
fs.mkdirSync(_path);
|
|
724
|
-
}
|
|
190
|
+
const gameLoader = require('./game-loader');
|
|
191
|
+
const dockerHelper = require('./docker-helper');
|
|
192
|
+
const GameSession = require('./game-session');
|
|
193
|
+
const GameSessionManager = require('./game-session-manager');
|
|
725
194
|
|
|
726
|
-
|
|
727
|
-
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Exports
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
728
198
|
|
|
729
199
|
module.exports = {
|
|
730
|
-
|
|
731
|
-
login,
|
|
732
|
-
confirmUser,
|
|
733
|
-
getLoginInfo,
|
|
734
|
-
verifyAccessToken,
|
|
735
|
-
refreshAccessToken,
|
|
736
|
-
linkInit,
|
|
737
|
-
getUserHash,
|
|
738
|
-
authWorkflow,
|
|
200
|
+
// Utilities
|
|
739
201
|
guaranteeDir,
|
|
740
202
|
getUrl,
|
|
741
203
|
getConfigValue,
|
|
742
204
|
log,
|
|
743
|
-
getAppDataPath
|
|
744
|
-
};
|
|
205
|
+
getAppDataPath,
|
|
745
206
|
|
|
207
|
+
// Game loading
|
|
208
|
+
gameLoader,
|
|
209
|
+
squishMap: gameLoader.squishMap,
|
|
210
|
+
DEFAULT_SQUISH_VERSION: gameLoader.DEFAULT_SQUISH_VERSION,
|
|
746
211
|
|
|
212
|
+
// Docker
|
|
213
|
+
dockerHelper,
|
|
214
|
+
|
|
215
|
+
// Sessions
|
|
216
|
+
GameSession,
|
|
217
|
+
GameSessionManager,
|
|
218
|
+
};
|