@andespindola/brainlink 1.6.1 → 1.6.3
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/dist/application/frontend/client/graph-renderer.js +690 -0
- package/dist/application/frontend/client/worker-bootstrap.js +113 -41
- package/dist/application/frontend/client-js.js +2 -0
- package/dist/application/frontend/client-render-worker-js.js +14 -677
- package/dist/application/frontend/login-page.js +331 -0
- package/dist/application/server/routes.js +92 -1
- package/dist/application/server/web-auth.js +168 -0
- package/dist/application/start-server.js +7 -2
- package/dist/cli/commands/write/server-commands.js +17 -5
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ const mainThreadWebGlAvailable = () => {
|
|
|
12
12
|
// Uma vez que o controle do canvas é transferido para o worker (OffscreenCanvas),
|
|
13
13
|
// o elemento original não fornece mais nenhum contexto (2D ou WebGL). Quando o
|
|
14
14
|
// worker falha ao iniciar o WebGL, trocamos por um canvas novo para que o
|
|
15
|
-
// fallback 2D consiga desenhar
|
|
15
|
+
// renderer da thread principal (WebGL ou o fallback 2D) consiga desenhar.
|
|
16
16
|
const replaceGraphCanvas = () => {
|
|
17
17
|
const replacement = canvas.cloneNode(false)
|
|
18
18
|
if (canvas.parentNode) {
|
|
@@ -24,6 +24,8 @@ const replaceGraphCanvas = () => {
|
|
|
24
24
|
|
|
25
25
|
const enterFallbackMode = (rebindInput) => {
|
|
26
26
|
state.rendererMode = 'fallback'
|
|
27
|
+
state.renderWorker = null
|
|
28
|
+
state.workerReady = false
|
|
27
29
|
if (rebindInput) {
|
|
28
30
|
setupInput()
|
|
29
31
|
}
|
|
@@ -31,58 +33,126 @@ const enterFallbackMode = (rebindInput) => {
|
|
|
31
33
|
drawFallback()
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
// Renderiza com WebGL na própria thread principal quando o worker não está
|
|
37
|
+
// disponível ou falhou. Reaproveita exatamente o mesmo renderer do worker,
|
|
38
|
+
// dirigido por chamadas diretas em vez de mensagens de Worker: state.renderWorker
|
|
39
|
+
// recebe um shim com .postMessage/.terminate, então todos os call-sites do
|
|
40
|
+
// cliente (chunk/camera/pick/etc.) continuam iguais.
|
|
41
|
+
const setupMainThreadWebGl = (rebindInput) => {
|
|
42
|
+
if (!mainThreadWebGlAvailable()) {
|
|
43
|
+
enterFallbackMode(rebindInput)
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const renderer = createGraphRenderer({
|
|
49
|
+
postMessage: (message) => handleRendererMessage(message),
|
|
50
|
+
requestAnimationFrame: (callback) => window.requestAnimationFrame(callback)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
state.rendererMode = 'mainthread'
|
|
54
|
+
state.renderWorker = {
|
|
55
|
+
postMessage: (message) => renderer.handleMessage(message),
|
|
56
|
+
terminate: () => {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (rebindInput) {
|
|
60
|
+
setupInput()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
renderer.handleMessage({
|
|
64
|
+
type: 'init',
|
|
65
|
+
canvas,
|
|
66
|
+
width: state.viewport.width,
|
|
67
|
+
height: state.viewport.height,
|
|
68
|
+
devicePixelRatio: state.viewport.ratio,
|
|
69
|
+
camera: state.camera,
|
|
70
|
+
theme: graphTheme
|
|
71
|
+
})
|
|
72
|
+
return true
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error(error)
|
|
75
|
+
state.renderWorker = null
|
|
76
|
+
enterFallbackMode(rebindInput)
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Canal único de mensagens do renderer, compartilhado pelo worker e pela thread
|
|
82
|
+
// principal. As saídas (ready/pick-result/frame-stats/fatal) chegam aqui igual
|
|
83
|
+
// nos dois modos.
|
|
84
|
+
const handleRendererMessage = (payload) => {
|
|
85
|
+
if (!payload || typeof payload !== 'object') {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (payload.type === 'ready') {
|
|
90
|
+
state.workerReady = true
|
|
91
|
+
scheduleChunkFetch({ fit: true })
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (payload.type === 'pick-result') {
|
|
96
|
+
if (payload.node && typeof payload.node.id === 'string' && payload.node.id.length > 0) {
|
|
97
|
+
handlePickedNode(payload.node)
|
|
98
|
+
}
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (payload.type === 'frame-stats') {
|
|
103
|
+
state.lastVisibleNodes = Number.isFinite(payload.visibleNodes) ? payload.visibleNodes : state.lastVisibleNodes
|
|
104
|
+
state.lastVisibleEdges = Number.isFinite(payload.visibleEdges) ? payload.visibleEdges : state.lastVisibleEdges
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (payload.type === 'fatal') {
|
|
109
|
+
console.error(payload.message)
|
|
110
|
+
state.workerReady = false
|
|
111
|
+
|
|
112
|
+
// Já estamos no WebGL da thread principal: não há degrau acelerado
|
|
113
|
+
// adicional, então cai no canvas 2D.
|
|
114
|
+
if (state.rendererMode === 'mainthread') {
|
|
115
|
+
state.renderWorker = null
|
|
116
|
+
enterFallbackMode(true)
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// O WebGL falhou dentro do worker. O canvas já foi transferido para ele,
|
|
121
|
+
// então troca por um novo e tenta WebGL na thread principal antes de
|
|
122
|
+
// desistir para o fallback 2D.
|
|
123
|
+
if (state.renderWorker && typeof state.renderWorker.terminate === 'function') {
|
|
124
|
+
state.renderWorker.terminate()
|
|
125
|
+
}
|
|
126
|
+
state.renderWorker = null
|
|
127
|
+
replaceGraphCanvas()
|
|
128
|
+
setupMainThreadWebGl(true)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
34
132
|
const setupRenderWorker = () => {
|
|
35
133
|
const hasWorker = typeof Worker !== 'undefined'
|
|
36
134
|
const canTransfer = typeof canvas.transferControlToOffscreen === 'function'
|
|
37
135
|
|
|
38
|
-
|
|
136
|
+
// Sem WebGL em lugar nenhum: só resta o canvas 2D.
|
|
137
|
+
if (!mainThreadWebGlAvailable()) {
|
|
39
138
|
enterFallbackMode(false)
|
|
40
139
|
return
|
|
41
140
|
}
|
|
42
141
|
|
|
142
|
+
// Tem WebGL, mas não dá para usar o worker (sem Worker ou sem OffscreenCanvas):
|
|
143
|
+
// renderiza WebGL na thread principal em vez de cair direto no 2D.
|
|
144
|
+
if (!hasWorker || !canTransfer) {
|
|
145
|
+
setupMainThreadWebGl(false)
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
43
149
|
try {
|
|
44
150
|
const offscreen = canvas.transferControlToOffscreen()
|
|
45
151
|
const worker = new Worker('/render-worker.js')
|
|
152
|
+
state.rendererMode = 'worker'
|
|
46
153
|
state.renderWorker = worker
|
|
47
154
|
|
|
48
|
-
worker.onmessage = (event) =>
|
|
49
|
-
const payload = event.data
|
|
50
|
-
if (!payload || typeof payload !== 'object') {
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (payload.type === 'ready') {
|
|
55
|
-
state.workerReady = true
|
|
56
|
-
scheduleChunkFetch({ fit: true })
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (payload.type === 'pick-result') {
|
|
61
|
-
if (payload.node && typeof payload.node.id === 'string' && payload.node.id.length > 0) {
|
|
62
|
-
handlePickedNode(payload.node)
|
|
63
|
-
}
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (payload.type === 'frame-stats') {
|
|
68
|
-
state.lastVisibleNodes = Number.isFinite(payload.visibleNodes) ? payload.visibleNodes : state.lastVisibleNodes
|
|
69
|
-
state.lastVisibleEdges = Number.isFinite(payload.visibleEdges) ? payload.visibleEdges : state.lastVisibleEdges
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (payload.type === 'fatal') {
|
|
74
|
-
console.error(payload.message)
|
|
75
|
-
state.workerReady = false
|
|
76
|
-
if (state.renderWorker) {
|
|
77
|
-
state.renderWorker.terminate()
|
|
78
|
-
}
|
|
79
|
-
state.renderWorker = null
|
|
80
|
-
// O canvas já foi transferido para o worker: troca por um novo e
|
|
81
|
-
// religa os eventos de interação antes de cair no fallback 2D.
|
|
82
|
-
replaceGraphCanvas()
|
|
83
|
-
enterFallbackMode(true)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
155
|
+
worker.onmessage = (event) => handleRendererMessage(event && event.data)
|
|
86
156
|
|
|
87
157
|
worker.postMessage({
|
|
88
158
|
type: 'init',
|
|
@@ -95,8 +165,10 @@ const setupRenderWorker = () => {
|
|
|
95
165
|
}, [offscreen])
|
|
96
166
|
} catch (error) {
|
|
97
167
|
console.error(error)
|
|
168
|
+
// O canvas pode já ter sido transferido: troca por um novo e tenta WebGL
|
|
169
|
+
// na thread principal antes do fallback 2D.
|
|
98
170
|
replaceGraphCanvas()
|
|
99
|
-
|
|
171
|
+
setupMainThreadWebGl(false)
|
|
100
172
|
}
|
|
101
173
|
}
|
|
102
174
|
|
|
@@ -8,6 +8,7 @@ import { createChunkFetchJs } from './client/chunk-fetch.js';
|
|
|
8
8
|
import { createInputJs } from './client/input.js';
|
|
9
9
|
import { createUploadJs } from './client/upload.js';
|
|
10
10
|
import { createControlsJs } from './client/controls.js';
|
|
11
|
+
import { createGraphRendererJs } from './client/graph-renderer.js';
|
|
11
12
|
import { createWorkerBootstrapJs } from './client/worker-bootstrap.js';
|
|
12
13
|
export const createClientJs = () => [
|
|
13
14
|
createElementsJs(),
|
|
@@ -20,5 +21,6 @@ export const createClientJs = () => [
|
|
|
20
21
|
createInputJs(),
|
|
21
22
|
createUploadJs(),
|
|
22
23
|
createControlsJs(),
|
|
24
|
+
createGraphRendererJs(),
|
|
23
25
|
createWorkerBootstrapJs()
|
|
24
26
|
].join('');
|