vimp-engine 0.37.0 → 0.38.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/package.json +1 -1
- package/src/client/boot.js +1 -1
- package/src/client/components/controller/LobbyAuth.js +97 -15
- package/src/client/components/controller/Profile.js +85 -0
- package/src/client/components/model/Games.js +1 -1
- package/src/client/components/model/LobbyAuth.js +344 -115
- package/src/client/components/model/Profile.js +142 -0
- package/src/client/components/view/LobbyAuth.js +150 -62
- package/src/client/components/view/Profile.js +373 -0
- package/src/client/lib/authApi.js +97 -0
- package/src/client/lib/pkce.js +23 -0
- package/src/client/lib/roomLink.js +1 -1
- package/src/client/lib/signalingErrors.js +3 -3
- package/src/client/lib/turnstile.js +130 -0
- package/src/client/main.js +89 -24
- package/src/client/network/TokenRenewer.js +90 -0
- package/src/client/session/GuestSession.js +79 -19
- package/src/client/style.css +119 -16
- package/src/client/views/includes/lobby.pug +11 -6
- package/src/client/views/includes/lobbyAuth.pug +34 -16
- package/src/client/views/includes/profile.pug +73 -0
- package/src/client/views/index.pug +1 -0
- package/src/config/authClient.js +54 -30
- package/src/config/chatMessages.js +1 -2
- package/src/config/env.js +2 -2
- package/src/config/lobby.js +50 -1
- package/src/config/master.js +15 -8
- package/src/config/wsports.js +4 -1
- package/src/devtools/builtinScenario.js +1 -1
- package/src/devtools/contract/rules/a2-package-scripts.js +1 -1
- package/src/devtools/contract/rules/a4-vite-config.js +1 -1
- package/src/devtools/contract/rules/b8-system-messages.js +1 -1
- package/src/devtools/invariants.js +1 -1
- package/src/devtools/pluginLoader.js +1 -1
- package/src/host/GameCoreAdapter.js +0 -3
- package/src/host/HostGame.js +28 -0
- package/src/host/PortMachine.js +50 -1
- package/src/host/meta/SocketManager.js +0 -13
- package/src/host/meta/core/RoundManager.js +0 -19
- package/src/host/meta/modules/PlayerDataSync.js +29 -3
- package/src/host/meta/modules/chat/systemMessages.js +1 -4
- package/src/lib/loadGamePackage.js +1 -1
- package/src/lib/validators.js +8 -0
- package/src/standalone/index.js +1 -1
package/package.json
CHANGED
package/src/client/boot.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Режим загрузки клиента движка (Этап 2 плана standalone-sdk). Клиент один
|
|
2
2
|
// на все контуры, а различает их этот модуль:
|
|
3
3
|
//
|
|
4
|
-
// lobby — прод: каталог игр и сигналинг мастера, лобби за
|
|
4
|
+
// lobby — прод: каталог игр и сигналинг мастера, лобби за экраном профиля;
|
|
5
5
|
// solo — standalone SDK: хост в этой же вкладке (inline, без Worker'а),
|
|
6
6
|
// мастера нет вовсе;
|
|
7
7
|
// dedicated — Node-сервер: прямой WebSocket к игровому процессу.
|
|
@@ -3,7 +3,23 @@
|
|
|
3
3
|
let lobbyAuthCtrl;
|
|
4
4
|
|
|
5
5
|
export default class LobbyAuthCtrl {
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} model - LobbyAuthModel.
|
|
8
|
+
* @param {Object} view - LobbyAuthView.
|
|
9
|
+
* @param {Object} deps
|
|
10
|
+
* @param {Object} deps.turnstile - client/lib/turnstile.js.
|
|
11
|
+
* @param {Function} [deps.navigate] - переход вкладки на URL.
|
|
12
|
+
*/
|
|
13
|
+
constructor(
|
|
14
|
+
model,
|
|
15
|
+
view,
|
|
16
|
+
{
|
|
17
|
+
turnstile,
|
|
18
|
+
navigate = url => {
|
|
19
|
+
window.location.href = url;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
) {
|
|
7
23
|
if (lobbyAuthCtrl) {
|
|
8
24
|
return lobbyAuthCtrl;
|
|
9
25
|
}
|
|
@@ -12,30 +28,96 @@ export default class LobbyAuthCtrl {
|
|
|
12
28
|
|
|
13
29
|
this._model = model;
|
|
14
30
|
this._view = view;
|
|
31
|
+
this._turnstile = turnstile;
|
|
32
|
+
this._navigate = navigate;
|
|
33
|
+
this._busy = false;
|
|
15
34
|
|
|
16
35
|
const vp = view.publisher;
|
|
17
36
|
|
|
18
|
-
vp.on('
|
|
19
|
-
vp.on('
|
|
20
|
-
vp.on('
|
|
37
|
+
vp.on('register', 'register', this);
|
|
38
|
+
vp.on('turnstile-retry', 'retryRegister', this);
|
|
39
|
+
vp.on('restore', 'restore', this);
|
|
40
|
+
vp.on('retry', 'retry', this);
|
|
21
41
|
}
|
|
22
42
|
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
// ник проверяется на клиенте до Turnstile и сервера; Turnstile — до
|
|
44
|
+
// запроса регистрации
|
|
45
|
+
async register(rawNick) {
|
|
46
|
+
if (this._busy) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const view = this._view;
|
|
51
|
+
const nick = rawNick.trim();
|
|
52
|
+
|
|
53
|
+
view.renderRegisterError(null);
|
|
54
|
+
view.showTurnstileRetry(false);
|
|
55
|
+
|
|
56
|
+
if (!this._model.validateNick(nick)) {
|
|
57
|
+
view.renderRegisterError('invalidNick');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this._busy = true;
|
|
62
|
+
view.setBusy(true);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const { turnstile } = this._model.getClientConfig();
|
|
66
|
+
let token = null;
|
|
67
|
+
|
|
68
|
+
if (turnstile.enabled) {
|
|
69
|
+
try {
|
|
70
|
+
token = await this._turnstile.getToken(
|
|
71
|
+
view.getTurnstileContainer(),
|
|
72
|
+
turnstile.siteKey,
|
|
73
|
+
);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
view.renderRegisterError(
|
|
76
|
+
error?.code === 'expired' ? 'turnstileFailed' : 'turnstileBlocked',
|
|
77
|
+
);
|
|
78
|
+
view.showTurnstileRetry(true);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const ok = await this._model.register(nick, token);
|
|
84
|
+
|
|
85
|
+
// токен Turnstile одноразовый и уже израсходован проверкой на сервере;
|
|
86
|
+
// новый берётся следующей отправкой формы, а не впрок: за 300 с жизни
|
|
87
|
+
// он истёк бы, пока игрок подбирает ник
|
|
88
|
+
if (!ok) {
|
|
89
|
+
this._turnstile.reset();
|
|
90
|
+
}
|
|
91
|
+
} finally {
|
|
92
|
+
this._busy = false;
|
|
93
|
+
view.setBusy(false);
|
|
94
|
+
|
|
95
|
+
// отказ возвращает игрока к полю с его ником
|
|
96
|
+
view.focusNick();
|
|
97
|
+
}
|
|
28
98
|
}
|
|
29
99
|
|
|
30
|
-
|
|
31
|
-
|
|
100
|
+
retryRegister() {
|
|
101
|
+
return this.register(this._view.getNickValue());
|
|
32
102
|
}
|
|
33
103
|
|
|
34
|
-
|
|
35
|
-
|
|
104
|
+
async restore(provider) {
|
|
105
|
+
// двойной клик перезаписал бы verifier попытки, уже ушедшей на auth
|
|
106
|
+
if (this._busy) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this._busy = true;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
this._navigate(await this._model.restoreUrl(provider));
|
|
114
|
+
} catch {
|
|
115
|
+
this._busy = false;
|
|
116
|
+
this._view.renderRestoreError('failed');
|
|
117
|
+
}
|
|
36
118
|
}
|
|
37
119
|
|
|
38
|
-
|
|
39
|
-
this._model.
|
|
120
|
+
retry() {
|
|
121
|
+
return this._model.boot();
|
|
40
122
|
}
|
|
41
123
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import Publisher from '../../../lib/Publisher.js';
|
|
2
|
+
|
|
3
|
+
// Singleton ProfileCtrl
|
|
4
|
+
|
|
5
|
+
let profileCtrl;
|
|
6
|
+
|
|
7
|
+
// Контроллер панели профиля: связывает события вида с моделью, как GamesCtrl.
|
|
8
|
+
// Сетевого I/O не делает. Наружу (main.js) пробрасывает 'left' — выход или
|
|
9
|
+
// удаление профиля, после которых вкладка перезагружается
|
|
10
|
+
export default class ProfileCtrl {
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} model - ProfileModel.
|
|
13
|
+
* @param {Object} view - ProfileView.
|
|
14
|
+
* @param {Object} [deps]
|
|
15
|
+
* @param {Function} [deps.navigate] - уход вкладки на URL провайдера.
|
|
16
|
+
*/
|
|
17
|
+
constructor(
|
|
18
|
+
model,
|
|
19
|
+
view,
|
|
20
|
+
{
|
|
21
|
+
navigate = url => {
|
|
22
|
+
window.location.href = url;
|
|
23
|
+
},
|
|
24
|
+
} = {},
|
|
25
|
+
) {
|
|
26
|
+
if (profileCtrl) {
|
|
27
|
+
return profileCtrl;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
profileCtrl = this;
|
|
31
|
+
|
|
32
|
+
this._model = model;
|
|
33
|
+
this._view = view;
|
|
34
|
+
this._navigate = navigate;
|
|
35
|
+
|
|
36
|
+
this.publisher = new Publisher();
|
|
37
|
+
|
|
38
|
+
const vp = view.publisher;
|
|
39
|
+
const mp = model.publisher;
|
|
40
|
+
|
|
41
|
+
vp.on('open', 'open', this);
|
|
42
|
+
vp.on('link', 'link', this);
|
|
43
|
+
vp.on('unlink', 'unlink', this);
|
|
44
|
+
vp.on('sign-out', 'signOut', this);
|
|
45
|
+
vp.on('export', 'exportData', this);
|
|
46
|
+
vp.on('delete', 'deleteProfile', this);
|
|
47
|
+
|
|
48
|
+
mp.on('left', () => this.publisher.emit('left'));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
open() {
|
|
52
|
+
this._view.show();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// кнопки вида неактивны без согласий; проверка здесь — второй рубеж
|
|
56
|
+
async link(provider) {
|
|
57
|
+
if (!this._view.consentGiven()) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this._navigate(await this._model.linkUrl(provider));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
unlink(provider) {
|
|
65
|
+
return this._model.unlink(provider);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
signOut() {
|
|
69
|
+
return this._model.signOut();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exportData() {
|
|
73
|
+
return this._model.exportData();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
deleteProfile(confirmNick) {
|
|
77
|
+
return this._model.deleteProfile(confirmNick);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// вкладка вернулась от провайдера: итог привязки показывает сама панель
|
|
81
|
+
openWithLinkResult(result) {
|
|
82
|
+
this._view.show();
|
|
83
|
+
this._view.renderLinkResult(result);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -12,7 +12,7 @@ const REQUEST_FAILED = 'requestFailed';
|
|
|
12
12
|
// вызывающего, очередь модерации и «Test» новой версии. В отличие от
|
|
13
13
|
// LobbyModel сетевые запросы делает сама — это простой REST к мастеру,
|
|
14
14
|
// сигнальный сокет здесь ни при чём (тот же приём, что у LobbyAuthModel с
|
|
15
|
-
//
|
|
15
|
+
// REST к auth-сервису). DOM не трогает.
|
|
16
16
|
export default class GamesModel {
|
|
17
17
|
/**
|
|
18
18
|
* @param {Object} config - Блок `games` конфига лобби (urls, statuses).
|