@hydranium/client-theia 1.0.0-next.39 → 1.0.0-next.390
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/README.md +53 -81
- package/lib/browser/browser-capture.js.map +1 -1
- package/lib/browser/channel-logger.d.ts +4 -3
- package/lib/browser/channel-logger.d.ts.map +1 -1
- package/lib/browser/channel-logger.js +11 -19
- package/lib/browser/channel-logger.js.map +1 -1
- package/lib/browser/connection-diagnostics-contribution.d.ts +73 -0
- package/lib/browser/connection-diagnostics-contribution.d.ts.map +1 -0
- package/lib/browser/connection-diagnostics-contribution.js +162 -0
- package/lib/browser/connection-diagnostics-contribution.js.map +1 -0
- package/lib/browser/connection-reporter.d.ts +57 -0
- package/lib/browser/connection-reporter.d.ts.map +1 -0
- package/lib/browser/connection-reporter.js +104 -0
- package/lib/browser/connection-reporter.js.map +1 -0
- package/lib/browser/editor-disk-sync.d.ts +142 -0
- package/lib/browser/editor-disk-sync.d.ts.map +1 -0
- package/lib/browser/editor-disk-sync.js +250 -0
- package/lib/browser/editor-disk-sync.js.map +1 -0
- package/lib/browser/hydranium-file-service.d.ts +44 -0
- package/lib/browser/hydranium-file-service.d.ts.map +1 -0
- package/lib/browser/hydranium-file-service.js +61 -0
- package/lib/browser/hydranium-file-service.js.map +1 -0
- package/lib/browser/index.d.ts +5 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +5 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/log-level-preference.d.ts.map +1 -1
- package/lib/browser/log-level-preference.js +11 -0
- package/lib/browser/log-level-preference.js.map +1 -1
- package/lib/browser/memory-diagnostics-contribution.d.ts +1 -1
- package/lib/browser/memory-diagnostics-contribution.d.ts.map +1 -1
- package/lib/browser/memory-diagnostics-contribution.js +1 -1
- package/lib/browser/memory-diagnostics-contribution.js.map +1 -1
- package/lib/browser/session-aware-connection-source.d.ts +104 -0
- package/lib/browser/session-aware-connection-source.d.ts.map +1 -0
- package/lib/browser/session-aware-connection-source.js +193 -0
- package/lib/browser/session-aware-connection-source.js.map +1 -0
- package/lib/common/clock.d.ts +19 -0
- package/lib/common/clock.d.ts.map +1 -0
- package/lib/common/clock.js +13 -0
- package/lib/common/clock.js.map +1 -0
- package/lib/common/connection-resilience-options.d.ts +30 -0
- package/lib/common/connection-resilience-options.d.ts.map +1 -0
- package/lib/common/connection-resilience-options.js +11 -0
- package/lib/common/connection-resilience-options.js.map +1 -0
- package/lib/common/framed-socket-write-buffer.d.ts +173 -0
- package/lib/common/framed-socket-write-buffer.d.ts.map +1 -0
- package/lib/common/framed-socket-write-buffer.js +293 -0
- package/lib/common/framed-socket-write-buffer.js.map +1 -0
- package/lib/common/inbound-message-sequence.d.ts +56 -0
- package/lib/common/inbound-message-sequence.d.ts.map +1 -0
- package/lib/common/inbound-message-sequence.js +98 -0
- package/lib/common/inbound-message-sequence.js.map +1 -0
- package/lib/common/index.d.ts +13 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +32 -0
- package/lib/common/index.js.map +1 -0
- package/lib/node/abstract-socket-forwarding-connection-handler.d.ts +16 -12
- package/lib/node/abstract-socket-forwarding-connection-handler.d.ts.map +1 -1
- package/lib/node/abstract-socket-forwarding-connection-handler.js +94 -31
- package/lib/node/abstract-socket-forwarding-connection-handler.js.map +1 -1
- package/lib/node/index.d.ts +2 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +2 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/session-bound-frontend-connection-service.d.ts +122 -0
- package/lib/node/session-bound-frontend-connection-service.d.ts.map +1 -0
- package/lib/node/session-bound-frontend-connection-service.js +236 -0
- package/lib/node/session-bound-frontend-connection-service.js.map +1 -0
- package/lib/node/socket-channel-forwarder.d.ts +54 -0
- package/lib/node/socket-channel-forwarder.d.ts.map +1 -0
- package/lib/node/socket-channel-forwarder.js +95 -0
- package/lib/node/socket-channel-forwarder.js.map +1 -0
- package/lib/testing/stub-inversify-context.js.map +1 -1
- package/lib/testing/stub-output-channel.js.map +1 -1
- package/package.json +33 -34
- package/src/browser/browser-capture.ts +1 -1
- package/src/browser/channel-logger.ts +11 -19
- package/src/browser/connection-diagnostics-contribution.ts +146 -0
- package/src/browser/connection-reporter.ts +121 -0
- package/src/browser/editor-disk-sync.ts +253 -0
- package/src/browser/hydranium-file-service.ts +56 -0
- package/src/browser/index.ts +5 -0
- package/src/browser/log-level-preference.ts +11 -0
- package/src/browser/memory-diagnostics-contribution.ts +4 -3
- package/src/browser/session-aware-connection-source.ts +205 -0
- package/src/common/clock.ts +20 -0
- package/src/common/connection-resilience-options.ts +30 -0
- package/src/common/framed-socket-write-buffer.ts +345 -0
- package/src/common/inbound-message-sequence.ts +102 -0
- package/src/common/index.ts +16 -0
- package/src/node/abstract-socket-forwarding-connection-handler.ts +85 -36
- package/src/node/index.ts +2 -0
- package/src/node/session-bound-frontend-connection-service.ts +264 -0
- package/src/node/socket-channel-forwarder.ts +101 -0
package/README.md
CHANGED
|
@@ -1,51 +1,22 @@
|
|
|
1
1
|
# `@hydranium/client-theia`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[Hydranium](https://github.com/eclipse-emfcloud/hydranium)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Theia application
|
|
8
|
-
|
|
9
|
-
bridges a Theia frontend channel to a server socket. It carries no head-specific
|
|
10
|
-
dependency — `@hydranium/data-client-theia` and `@hydranium/glsp-client-theia`
|
|
11
|
-
both build on it. Install it if you are assembling a Theia extension around a
|
|
12
|
-
hydranium server; a non-Theia host does not need it.
|
|
3
|
+
The Theia pieces every
|
|
4
|
+
[Hydranium](https://github.com/eclipse-emfcloud/hydranium) head shares: the
|
|
5
|
+
Output-channel logger, the editor's save handling, the diagnostics commands and
|
|
6
|
+
the backend's socket bridge. Install it when your language's editors live in a
|
|
7
|
+
Theia application, beside `@hydranium/data-client-theia` or
|
|
8
|
+
`@hydranium/glsp-client-theia`.
|
|
13
9
|
|
|
14
10
|
## What it gives you
|
|
15
11
|
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
threshold is process-global, so applying it from a per-diagram container would
|
|
25
|
-
leak one preference listener per container.
|
|
26
|
-
- **`MemoryDiagnosticsContribution`** with `bindMemoryDiagnostics` — the whole
|
|
27
|
-
diagnostics command set, parameterised by three branding strings
|
|
28
|
-
(`MemoryDiagnosticsOptions`: `commandIdPrefix`, `category`, `channelName`):
|
|
29
|
-
Dump Server State, Dump Pod Memory, Dump Frontend State, Write Heap Snapshot
|
|
30
|
-
(Server), Start / Stop Profiling (Server), Record Performance Profile, and Dump
|
|
31
|
-
RPC/LSP Latency. Two more — Dump Backend State and Write Heap Snapshot
|
|
32
|
-
(Backend) — register only when the optional `HostMemoryDiagnosticsService` is
|
|
33
|
-
bound. You bind `MemoryDiagnosticsService` to your own connected data-server
|
|
34
|
-
frontend; the framework cannot, because that class is yours.
|
|
35
|
-
- **`captureBrowserRuntime` / `formatBrowserRuntime`** — the renderer's own memory
|
|
36
|
-
reading as a `BrowserRuntimeReport`, preferring the standardized
|
|
37
|
-
`performance.measureUserAgentSpecificMemory()` and falling back to Chromium's
|
|
38
|
-
coarse `performance.memory`.
|
|
39
|
-
- **`AbstractSocketForwardingConnectionHandler`** (Node side) — the abstract base for the
|
|
40
|
-
Theia _backend_ half of a head's transport. It discovers the server's listening
|
|
41
|
-
port by executing a registered command, opens a `net.Socket`, and relays bytes
|
|
42
|
-
between the frontend channel and it. The one abstract hook is which byte
|
|
43
|
-
forwarder bridges the two; port discovery, connect orchestration, and the
|
|
44
|
-
buffer-and-replay fix for frontend writes that arrive before the forwarder is
|
|
45
|
-
wired all live here.
|
|
46
|
-
- **`./testing`** — `makeStubOutputChannelManager` and `makeStubInversifyContext`,
|
|
47
|
-
the doubles that let the pieces above be unit-tested without a Theia
|
|
48
|
-
application.
|
|
12
|
+
- Your frontend's log lines in an Output channel you name, aligned with the
|
|
13
|
+
server's own log, and the log level driven by a Theia preference.
|
|
14
|
+
- Editors that stay correct when a server saves a file they show unsaved.
|
|
15
|
+
- Diagnostics commands for the server's memory, heap and profile, under your
|
|
16
|
+
own command prefix and category.
|
|
17
|
+
- Notifications while a head connects, and once when it fails.
|
|
18
|
+
- Messages held while the websocket is down, and the outage logged.
|
|
19
|
+
- The socket bridge the head packages build their backend handlers on.
|
|
49
20
|
|
|
50
21
|
## Install
|
|
51
22
|
|
|
@@ -53,61 +24,62 @@ hydranium server; a non-Theia host does not need it.
|
|
|
53
24
|
npm install @hydranium/client-theia
|
|
54
25
|
```
|
|
55
26
|
|
|
56
|
-
You must already have a Theia application (or a Theia extension inside one). The
|
|
57
|
-
declared peer dependencies are:
|
|
58
|
-
|
|
59
27
|
| Peer | Range |
|
|
60
28
|
| --------------------- | ------------- |
|
|
61
29
|
| `@hydranium/protocol` | `^1.0.0-next` |
|
|
62
30
|
| `@theia/core` | `^1.70.0` |
|
|
31
|
+
| `@theia/editor` | `^1.70.0` |
|
|
32
|
+
| `@theia/filesystem` | `^1.70.0` |
|
|
63
33
|
| `@theia/output` | `^1.70.0` |
|
|
64
|
-
| `inversify` | `^6.
|
|
34
|
+
| `inversify` | `^6.1.3` |
|
|
35
|
+
| `vscode-jsonrpc` | `^9.0.0` |
|
|
65
36
|
|
|
66
|
-
`@theia/output` is easy to miss: the
|
|
67
|
-
|
|
68
|
-
it has to add it.
|
|
37
|
+
`@theia/output` is easy to miss: the logger and the diagnostics commands both
|
|
38
|
+
write to an Output channel, so add it if your application does not have it yet.
|
|
69
39
|
|
|
70
40
|
## Wiring
|
|
71
41
|
|
|
72
|
-
This package is a
|
|
73
|
-
`theiaExtensions
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
42
|
+
This package is a library, not a Theia extension: it declares no
|
|
43
|
+
`theiaExtensions`. Your own extension declares them and binds from here.
|
|
44
|
+
|
|
45
|
+
- In a frontend module, call `bindChannelLogger` and `bindLogLevelPreference`.
|
|
46
|
+
Call `bindEditorDiskSync` whenever a server writes files an editor can have
|
|
47
|
+
open.
|
|
48
|
+
- For the diagnostics commands, bind `MemoryDiagnosticsService` to your own
|
|
49
|
+
data-server frontend, then call `bindMemoryDiagnostics`.
|
|
50
|
+
- For the websocket, call `bindConnectionResilience` in a `frontendPreload`
|
|
51
|
+
module and in a backend module, and `bindConnectionDiagnostics` beside the
|
|
52
|
+
logger. From a normal frontend module the first call comes too late and
|
|
53
|
+
silently does nothing; in Electron it does nothing by design.
|
|
54
|
+
- In the backend, you usually subclass a head-specific handler from
|
|
84
55
|
`@hydranium/data-client-theia` or `@hydranium/glsp-client-theia` rather than
|
|
85
|
-
|
|
56
|
+
the base here.
|
|
57
|
+
|
|
58
|
+
For the whole setup, see *Host in Theia* in
|
|
59
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
86
60
|
|
|
87
61
|
## Entry points
|
|
88
62
|
|
|
89
|
-
| Subpath |
|
|
90
|
-
| ----------- |
|
|
91
|
-
| `.` | Nothing
|
|
92
|
-
| `./browser` |
|
|
93
|
-
| `./
|
|
94
|
-
| `./
|
|
63
|
+
| Subpath | Use it for | Runs in |
|
|
64
|
+
| ----------- | ---------------------------------------------------------- | --------------- |
|
|
65
|
+
| `.` | Nothing; import a subpath | browser-neutral |
|
|
66
|
+
| `./browser` | The frontend bind helpers and the classes they bind | Theia frontend |
|
|
67
|
+
| `./common` | The pieces both sides share, such as the clock token | browser-neutral |
|
|
68
|
+
| `./node` | The backend socket bridge and the websocket hardening | Theia backend |
|
|
69
|
+
| `./testing` | Test doubles for the Output channel and Inversify contexts | browser-neutral |
|
|
95
70
|
|
|
96
|
-
|
|
97
|
-
`
|
|
98
|
-
|
|
99
|
-
browser with no `node:*` import, including transitive ones — and [what "gated neutral" does and does not promise](../../docs/concepts/browser-hosting.md#a-note-on-what-gated-neutral-does-and-does-not-promise).
|
|
100
|
-
`./node` is deliberately not gated — that tier is where Node-only code belongs.
|
|
71
|
+
The subpaths need a TypeScript `moduleResolution` that reads `exports`
|
|
72
|
+
(`NodeNext` or `Bundler`); see *Requirements* in
|
|
73
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
101
74
|
|
|
102
75
|
## Status
|
|
103
76
|
|
|
104
|
-
Alpha
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
[repository README](../../README.md) for current status and known limitations.
|
|
77
|
+
Alpha: every release is a prerelease that may break the API, so pin an exact
|
|
78
|
+
version. Guides and known limitations:
|
|
79
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
108
80
|
|
|
109
81
|
## License
|
|
110
82
|
|
|
111
|
-
`MIT` — see this package's [`LICENSE`](./LICENSE)
|
|
112
|
-
|
|
113
|
-
|
|
83
|
+
`MIT` — see this package's [`LICENSE`](./LICENSE), and the repository
|
|
84
|
+
[`NOTICE.md`](https://github.com/eclipse-emfcloud/hydranium/blob/main/NOTICE.md)
|
|
85
|
+
for third-party notices.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-capture.js","sourceRoot":"","sources":["../../src/browser/browser-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF
|
|
1
|
+
{"version":3,"file":"browser-capture.js","sourceRoot":"","sources":["../../src/browser/browser-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;AAmBlF;;;;;;;GAOG;AACI,KAAK;IACT,MAAM,IAAI,GAAG,UAAU,CAAC,WAAmD,CAAC;IAC5E,IAAI,IAAI,EAAE,8BAA8B,EAAE,CAAC;QACxC,IAAI,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,8BAA8B,EAAE,CAAC;YAC3D,OAAO,EAAE,MAAM,EAAE,gCAAgC,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QACzH,CAAC;QAAC,MAAM,CAAC;YACN,qEAAqE;QACxE,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QAChB,OAAO;YACJ,MAAM,EAAE,oBAAoB;YAC5B,KAAK,EAAE;gBACJ,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc;gBAC3C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;gBAC7C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;aAC/C;SACH,CAAC;IACL,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,EAAE,CAAC,KAAa;IACtB,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACrD,CAAC;AAED,yFAAyF;AACzF,8BAAqC,MAA4B;IAC9D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACzB,IAAI,MAAM,CAAC,MAAM,KAAK,gCAAgC,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACxF,OAAO,sCAAsC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,+BAA+B,CAAC;IACpG,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,oBAAoB,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QACjF,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC1C,OAAO,oBAAoB,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,+CAA+C,CAAC;IAC/H,CAAC;IACD,OAAO,8GAA8G,CAAC;AACzH,CAAC"}
|
|
@@ -61,9 +61,10 @@ export declare class ChannelLogger extends AbstractLogger {
|
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
63
|
* Inversify token for the browser `Tracer` — a {@link DefaultTracer} over
|
|
64
|
-
* the {@link ChannelLogger} (emit sink) +
|
|
65
|
-
*
|
|
66
|
-
*
|
|
64
|
+
* the {@link ChannelLogger} (emit sink) + the container's {@link Clock}, or a
|
|
65
|
+
* `SystemClock` when it binds none, + a browser heap reader. The browser head
|
|
66
|
+
* has no Langium `services.Tracer` slot, so this is how frontend services that
|
|
67
|
+
* time obtain a tracer: `@inject(ChannelTracer)`.
|
|
67
68
|
* Bound by {@link bindChannelLogger}.
|
|
68
69
|
*/
|
|
69
70
|
export declare const ChannelTracer: unique symbol;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-logger.d.ts","sourceRoot":"","sources":["../../src/browser/channel-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,cAAc,EAAiB,KAAK,QAAQ,EAAkC,MAAM,qBAAqB,CAAC;AACnH,OAAO,EAAc,KAAK,UAAU,EAAqB,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,KAAK,aAAa,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"channel-logger.d.ts","sourceRoot":"","sources":["../../src/browser/channel-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,cAAc,EAAiB,KAAK,QAAQ,EAAkC,MAAM,qBAAqB,CAAC;AACnH,OAAO,EAAc,KAAK,UAAU,EAAqB,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,KAAK,aAAa,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAGpG;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;sFACsF;AACtF,eAAO,MAAM,oBAAoB,eAAiC,CAAC;AAEnE;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,aAAc,SAAQ,cAAc;IAIb,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,oBAAoB;IACvD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB;IAJjF,SAAS,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAEnC,YACoD,cAAc,EAAE,oBAAoB,EACpC,OAAO,EAAE,oBAAoB,EACjE,SAAS,GAAE,MAAM,GAAG,SAA6B,EAGhE;IAED,SAAS,KAAK,OAAO,IAAI,aAAa,CAErC;IAED,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAG/F;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOxC;CACH;AAOD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,eAA0B,CAAC;AAErD;gDACgD;AAChD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,GAAG,MAAM,GAAG,SAAS,CAOpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAc5F"}
|
|
@@ -26,6 +26,7 @@ exports.bindChannelLogger = bindChannelLogger;
|
|
|
26
26
|
const protocol_1 = require("@hydranium/protocol");
|
|
27
27
|
const inversify_1 = require("@theia/core/shared/inversify");
|
|
28
28
|
const output_channel_1 = require("@theia/output/lib/browser/output-channel");
|
|
29
|
+
const clock_1 = require("../common/clock");
|
|
29
30
|
/** Inversify token for the {@link ChannelLoggerOptions} constant (merged with the
|
|
30
31
|
* interface name — the standard Theia "type + token under one identifier" idiom). */
|
|
31
32
|
exports.ChannelLoggerOptions = Symbol('ChannelLoggerOptions');
|
|
@@ -59,10 +60,8 @@ let ChannelLogger = class ChannelLogger extends protocol_1.AbstractLogger {
|
|
|
59
60
|
return (this._channel ??= this.outputChannels.getChannel(this.options.channelName));
|
|
60
61
|
}
|
|
61
62
|
emit(_level, label, message, args) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
// Pad to match the server's 5-char label width so timestamps align across sources.
|
|
65
|
-
this.channel.appendLine(`[${label.padEnd(5)} - ${this.timestamp()}]${componentSegment} ${message}${formattedArgs}`);
|
|
63
|
+
const formattedArgs = args.length > 0 ? ' ' + args.map(arg => this.formatArg(arg)).join(' ') : '';
|
|
64
|
+
this.channel.appendLine(`${this.formatLinePrefix(label)} ${message}${formattedArgs}`);
|
|
66
65
|
}
|
|
67
66
|
/**
|
|
68
67
|
* Allocates a free instance bypassing Inversify, so a derived logger inherits
|
|
@@ -89,9 +88,10 @@ exports.ChannelLogger = ChannelLogger = __decorate([
|
|
|
89
88
|
const ChannelLoggerBase = Symbol('ChannelLoggerBase');
|
|
90
89
|
/**
|
|
91
90
|
* Inversify token for the browser `Tracer` — a {@link DefaultTracer} over
|
|
92
|
-
* the {@link ChannelLogger} (emit sink) +
|
|
93
|
-
*
|
|
94
|
-
*
|
|
91
|
+
* the {@link ChannelLogger} (emit sink) + the container's {@link Clock}, or a
|
|
92
|
+
* `SystemClock` when it binds none, + a browser heap reader. The browser head
|
|
93
|
+
* has no Langium `services.Tracer` slot, so this is how frontend services that
|
|
94
|
+
* time obtain a tracer: `@inject(ChannelTracer)`.
|
|
95
95
|
* Bound by {@link bindChannelLogger}.
|
|
96
96
|
*/
|
|
97
97
|
exports.ChannelTracer = Symbol('ChannelTracer');
|
|
@@ -127,7 +127,10 @@ function bindChannelLogger(bind, options) {
|
|
|
127
127
|
return parentName ? base.for(parentName) : base;
|
|
128
128
|
});
|
|
129
129
|
bind(exports.ChannelTracer)
|
|
130
|
-
.toDynamicValue(ctx =>
|
|
130
|
+
.toDynamicValue(ctx => {
|
|
131
|
+
const clock = ctx.container.isBound(clock_1.Clock) ? ctx.container.get(clock_1.Clock) : new protocol_1.SystemClock();
|
|
132
|
+
return new protocol_1.DefaultTracer(ctx.container.get(ChannelLoggerBase), clock, readBrowserMemory);
|
|
133
|
+
})
|
|
131
134
|
.inSingletonScope();
|
|
132
135
|
}
|
|
133
136
|
/** Browser heap reader for {@link ChannelTracer}, backed by Chromium's non-standard `performance.memory`. */
|
|
@@ -135,15 +138,4 @@ const readBrowserMemory = () => {
|
|
|
135
138
|
const mem = performance.memory;
|
|
136
139
|
return mem ? { usedBytes: mem.usedJSHeapSize, totalBytes: mem.totalJSHeapSize } : undefined;
|
|
137
140
|
};
|
|
138
|
-
function stringifyArg(arg) {
|
|
139
|
-
if (typeof arg === 'string') {
|
|
140
|
-
return arg;
|
|
141
|
-
}
|
|
142
|
-
try {
|
|
143
|
-
return JSON.stringify(arg);
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
return String(arg);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
141
|
//# sourceMappingURL=channel-logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-logger.js","sourceRoot":"","sources":["../../src/browser/channel-logger.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF
|
|
1
|
+
{"version":3,"file":"channel-logger.js","sourceRoot":"","sources":["../../src/browser/channel-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { type Stopwatch } from '@hydranium/protocol';
|
|
10
|
+
import { MessageService } from '@theia/core';
|
|
11
|
+
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
|
|
12
|
+
import { ConnectionStatus, ConnectionStatusService } from '@theia/core/lib/browser/connection-status-service';
|
|
13
|
+
import { WebSocketConnectionSource } from '@theia/core/lib/browser/messaging/ws-connection-source';
|
|
14
|
+
import { type interfaces } from '@theia/core/shared/inversify';
|
|
15
|
+
import { Clock } from '../common/clock';
|
|
16
|
+
import { type ConnectionBufferOverflow } from '../common/framed-socket-write-buffer';
|
|
17
|
+
import { ChannelLogger } from './channel-logger';
|
|
18
|
+
/**
|
|
19
|
+
* Records the browser side of the websocket lifecycle into the adopter's Output
|
|
20
|
+
* channel, and tells the user the one thing they cannot recover from on their
|
|
21
|
+
* own.
|
|
22
|
+
*
|
|
23
|
+
* Theia reports an outage only as an "Offline" status-bar item, which cannot
|
|
24
|
+
* distinguish a plain network drop from the server having stopped answering on a
|
|
25
|
+
* socket that is still up. The latter is what a connection defect looks like
|
|
26
|
+
* from here, so the two are logged differently — that distinction is what says
|
|
27
|
+
* whether reopening an editor helps or only a reload does.
|
|
28
|
+
*
|
|
29
|
+
* Purely observational apart from the overflow message: nothing here changes how
|
|
30
|
+
* the connection behaves.
|
|
31
|
+
*/
|
|
32
|
+
export declare class ConnectionDiagnosticsContribution implements FrontendApplicationContribution {
|
|
33
|
+
protected readonly connectionSource: WebSocketConnectionSource;
|
|
34
|
+
protected readonly connectionStatus: ConnectionStatusService;
|
|
35
|
+
protected readonly logger: ChannelLogger;
|
|
36
|
+
protected readonly messageService: MessageService;
|
|
37
|
+
/** Times the outages the log reports: the container's {@link Clock}, or a `SystemClock`. */
|
|
38
|
+
protected readonly clock: Clock;
|
|
39
|
+
/** Main channels created so far; more than one means the server did not recognise this frontend. */
|
|
40
|
+
protected channelCount: number;
|
|
41
|
+
protected sinceSocketClosed?: Stopwatch;
|
|
42
|
+
protected sinceOffline?: Stopwatch;
|
|
43
|
+
initialize(): void;
|
|
44
|
+
protected handleSocketOpen(): void;
|
|
45
|
+
protected handleSocketClose(): void;
|
|
46
|
+
/**
|
|
47
|
+
* A second channel means the reconnect was refused and the session discarded.
|
|
48
|
+
* Only reachable with `reloadOnReconnect` off — with it on, Theia reloads the
|
|
49
|
+
* page instead of opening another channel.
|
|
50
|
+
*/
|
|
51
|
+
protected handleChannelOpen(): void;
|
|
52
|
+
protected handleStatusChange(status: ConnectionStatus): void;
|
|
53
|
+
/**
|
|
54
|
+
* The outage outlasted what the buffer can hold, so changes made from here on
|
|
55
|
+
* are being thrown away rather than queued. Reconnecting resumes sending but
|
|
56
|
+
* cannot bring those back, which leaves the editor disagreeing with the
|
|
57
|
+
* server — and without a message the user would see nothing but an editor
|
|
58
|
+
* that has quietly stopped saving, so say it plainly.
|
|
59
|
+
*/
|
|
60
|
+
protected handleBufferOverflow(overflow: ConnectionBufferOverflow): void;
|
|
61
|
+
protected socketId(): string;
|
|
62
|
+
protected statusName(status: ConnectionStatus): string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Bind {@link ConnectionDiagnosticsContribution} as a `FrontendApplicationContribution`.
|
|
66
|
+
*
|
|
67
|
+
* Needs a {@link ChannelLogger} binding, so call it from a module that has also
|
|
68
|
+
* called `bindChannelLogger`. Unlike `bindConnectionResilience` this belongs in a
|
|
69
|
+
* normal frontend module: it only observes, so it has no reason to run during
|
|
70
|
+
* preload, and `MessageService` is not available that early.
|
|
71
|
+
*/
|
|
72
|
+
export declare function bindConnectionDiagnostics(bind: interfaces.Bind): void;
|
|
73
|
+
//# sourceMappingURL=connection-diagnostics-contribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-diagnostics-contribution.d.ts","sourceRoot":"","sources":["../../src/browser/connection-diagnostics-contribution.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,SAAS,EAAe,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAO,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,+BAA+B,EAAE,MAAM,2DAA2D,CAAC;AAC5G,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC9G,OAAO,EAAE,yBAAyB,EAAE,MAAM,wDAAwD,CAAC;AACnG,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD;;;;;;;;;;;;;GAaG;AACH,qBACa,iCAAkC,YAAW,+BAA+B;IACnD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IACvE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IACxC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IAC1E,4FAA4F;IACjE,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAqB;IAE/E,oGAAoG;IACpG,SAAS,CAAC,YAAY,SAAK;IAC3B,SAAS,CAAC,iBAAiB,CAAC,EAAE,SAAS,CAAC;IACxC,SAAS,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAEnC,UAAU,IAAI,IAAI,CAWjB;IAED,SAAS,CAAC,gBAAgB,IAAI,IAAI,CAIjC;IAED,SAAS,CAAC,iBAAiB,IAAI,IAAI,CAGlC;IAED;;;;OAIG;IACH,SAAS,CAAC,iBAAiB,IAAI,IAAI,CAUlC;IAED,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAiB3D;IAED;;;;;;OAMG;IACH,SAAS,CAAC,oBAAoB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAQvE;IAED,SAAS,CAAC,QAAQ,IAAI,MAAM,CAE3B;IAED,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAErD;CACH;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,GAAG,IAAI,CAGrE"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
+
};
|
|
16
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
17
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.ConnectionDiagnosticsContribution = void 0;
|
|
21
|
+
exports.bindConnectionDiagnostics = bindConnectionDiagnostics;
|
|
22
|
+
const protocol_1 = require("@hydranium/protocol");
|
|
23
|
+
const core_1 = require("@theia/core");
|
|
24
|
+
const frontend_application_contribution_1 = require("@theia/core/lib/browser/frontend-application-contribution");
|
|
25
|
+
const connection_status_service_1 = require("@theia/core/lib/browser/connection-status-service");
|
|
26
|
+
const ws_connection_source_1 = require("@theia/core/lib/browser/messaging/ws-connection-source");
|
|
27
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
28
|
+
const clock_1 = require("../common/clock");
|
|
29
|
+
const channel_logger_1 = require("./channel-logger");
|
|
30
|
+
const session_aware_connection_source_1 = require("./session-aware-connection-source");
|
|
31
|
+
/**
|
|
32
|
+
* Records the browser side of the websocket lifecycle into the adopter's Output
|
|
33
|
+
* channel, and tells the user the one thing they cannot recover from on their
|
|
34
|
+
* own.
|
|
35
|
+
*
|
|
36
|
+
* Theia reports an outage only as an "Offline" status-bar item, which cannot
|
|
37
|
+
* distinguish a plain network drop from the server having stopped answering on a
|
|
38
|
+
* socket that is still up. The latter is what a connection defect looks like
|
|
39
|
+
* from here, so the two are logged differently — that distinction is what says
|
|
40
|
+
* whether reopening an editor helps or only a reload does.
|
|
41
|
+
*
|
|
42
|
+
* Purely observational apart from the overflow message: nothing here changes how
|
|
43
|
+
* the connection behaves.
|
|
44
|
+
*/
|
|
45
|
+
let ConnectionDiagnosticsContribution = class ConnectionDiagnosticsContribution {
|
|
46
|
+
connectionSource;
|
|
47
|
+
connectionStatus;
|
|
48
|
+
logger;
|
|
49
|
+
messageService;
|
|
50
|
+
/** Times the outages the log reports: the container's {@link Clock}, or a `SystemClock`. */
|
|
51
|
+
clock = new protocol_1.SystemClock();
|
|
52
|
+
/** Main channels created so far; more than one means the server did not recognise this frontend. */
|
|
53
|
+
channelCount = 0;
|
|
54
|
+
sinceSocketClosed;
|
|
55
|
+
sinceOffline;
|
|
56
|
+
initialize() {
|
|
57
|
+
this.connectionSource.onSocketDidOpen(() => this.handleSocketOpen());
|
|
58
|
+
this.connectionSource.onSocketDidClose(() => this.handleSocketClose());
|
|
59
|
+
this.connectionSource.onConnectionDidOpen(() => this.handleChannelOpen());
|
|
60
|
+
this.connectionStatus.onStatusChange(status => this.handleStatusChange(status));
|
|
61
|
+
if (this.connectionSource instanceof session_aware_connection_source_1.SessionAwareConnectionSource) {
|
|
62
|
+
this.connectionSource.onBufferOverflow(overflow => this.handleBufferOverflow(overflow));
|
|
63
|
+
}
|
|
64
|
+
// The socket is opened by the preloader, before this contribution exists, so the first
|
|
65
|
+
// `onSocketDidOpen` has already fired; state the current situation instead.
|
|
66
|
+
this.logger.debug(`diagnostics active; socket ${this.socketId()}, backend ${this.statusName(this.connectionStatus.currentStatus)}`);
|
|
67
|
+
}
|
|
68
|
+
handleSocketOpen() {
|
|
69
|
+
const downFor = this.sinceSocketClosed === undefined ? '' : ` after ${Math.round(this.sinceSocketClosed.elapsedMs)} ms down`;
|
|
70
|
+
this.sinceSocketClosed = undefined;
|
|
71
|
+
this.logger.info(`websocket connected: socket ${this.socketId()}${downFor}`);
|
|
72
|
+
}
|
|
73
|
+
handleSocketClose() {
|
|
74
|
+
this.sinceSocketClosed = this.clock.stopwatch();
|
|
75
|
+
this.logger.info(`websocket disconnected: socket ${this.socketId()}; outgoing messages are buffered until it returns`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A second channel means the reconnect was refused and the session discarded.
|
|
79
|
+
* Only reachable with `reloadOnReconnect` off — with it on, Theia reloads the
|
|
80
|
+
* page instead of opening another channel.
|
|
81
|
+
*/
|
|
82
|
+
handleChannelOpen() {
|
|
83
|
+
this.channelCount++;
|
|
84
|
+
if (this.channelCount === 1) {
|
|
85
|
+
this.logger.debug(`initial channel opened on socket ${this.socketId()}`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.logger.warn(`new channel #${this.channelCount} on socket ${this.socketId()}: the backend did not recognise this frontend, ` +
|
|
89
|
+
'so its session was discarded and every pending request rejected');
|
|
90
|
+
}
|
|
91
|
+
handleStatusChange(status) {
|
|
92
|
+
if (status === connection_status_service_1.ConnectionStatus.ONLINE) {
|
|
93
|
+
const offlineFor = this.sinceOffline === undefined ? '' : ` after ${Math.round(this.sinceOffline.elapsedMs)} ms`;
|
|
94
|
+
this.sinceOffline = undefined;
|
|
95
|
+
this.logger.info(`backend reachable again${offlineFor}`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.sinceOffline = this.clock.stopwatch();
|
|
99
|
+
const socket = this.connectionSource.socket;
|
|
100
|
+
if (socket?.connected) {
|
|
101
|
+
this.logger.warn(`backend stopped answering while socket ${socket.id} is still connected: nothing this session sends will ` +
|
|
102
|
+
'arrive, and socket.io will not reconnect on its own. Reload the page to recover.');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.logger.info(`backend unreachable; websocket is disconnected (socket ${this.socketId()})`);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The outage outlasted what the buffer can hold, so changes made from here on
|
|
109
|
+
* are being thrown away rather than queued. Reconnecting resumes sending but
|
|
110
|
+
* cannot bring those back, which leaves the editor disagreeing with the
|
|
111
|
+
* server — and without a message the user would see nothing but an editor
|
|
112
|
+
* that has quietly stopped saving, so say it plainly.
|
|
113
|
+
*/
|
|
114
|
+
handleBufferOverflow(overflow) {
|
|
115
|
+
this.logger.error(`buffer full at ${overflow.maxBytes} bytes holding ${overflow.messages} message(s)`);
|
|
116
|
+
this.messageService.error(core_1.nls.localize('hydranium/connection/offlineLimitReached', 'Disconnected for too long: recent changes were not sent. Reload the page before continuing.'));
|
|
117
|
+
}
|
|
118
|
+
socketId() {
|
|
119
|
+
return this.connectionSource.socket?.id ?? ws_connection_source_1.WebSocketConnectionSource.NO_CONNECTION;
|
|
120
|
+
}
|
|
121
|
+
statusName(status) {
|
|
122
|
+
return status === connection_status_service_1.ConnectionStatus.ONLINE ? 'online' : 'offline';
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
exports.ConnectionDiagnosticsContribution = ConnectionDiagnosticsContribution;
|
|
126
|
+
__decorate([
|
|
127
|
+
(0, inversify_1.inject)(ws_connection_source_1.WebSocketConnectionSource),
|
|
128
|
+
__metadata("design:type", ws_connection_source_1.WebSocketConnectionSource)
|
|
129
|
+
], ConnectionDiagnosticsContribution.prototype, "connectionSource", void 0);
|
|
130
|
+
__decorate([
|
|
131
|
+
(0, inversify_1.inject)(connection_status_service_1.ConnectionStatusService),
|
|
132
|
+
__metadata("design:type", Object)
|
|
133
|
+
], ConnectionDiagnosticsContribution.prototype, "connectionStatus", void 0);
|
|
134
|
+
__decorate([
|
|
135
|
+
(0, inversify_1.inject)(channel_logger_1.ChannelLogger),
|
|
136
|
+
__metadata("design:type", channel_logger_1.ChannelLogger)
|
|
137
|
+
], ConnectionDiagnosticsContribution.prototype, "logger", void 0);
|
|
138
|
+
__decorate([
|
|
139
|
+
(0, inversify_1.inject)(core_1.MessageService),
|
|
140
|
+
__metadata("design:type", core_1.MessageService)
|
|
141
|
+
], ConnectionDiagnosticsContribution.prototype, "messageService", void 0);
|
|
142
|
+
__decorate([
|
|
143
|
+
(0, inversify_1.inject)(clock_1.Clock),
|
|
144
|
+
(0, inversify_1.optional)(),
|
|
145
|
+
__metadata("design:type", Object)
|
|
146
|
+
], ConnectionDiagnosticsContribution.prototype, "clock", void 0);
|
|
147
|
+
exports.ConnectionDiagnosticsContribution = ConnectionDiagnosticsContribution = __decorate([
|
|
148
|
+
(0, inversify_1.injectable)()
|
|
149
|
+
], ConnectionDiagnosticsContribution);
|
|
150
|
+
/**
|
|
151
|
+
* Bind {@link ConnectionDiagnosticsContribution} as a `FrontendApplicationContribution`.
|
|
152
|
+
*
|
|
153
|
+
* Needs a {@link ChannelLogger} binding, so call it from a module that has also
|
|
154
|
+
* called `bindChannelLogger`. Unlike `bindConnectionResilience` this belongs in a
|
|
155
|
+
* normal frontend module: it only observes, so it has no reason to run during
|
|
156
|
+
* preload, and `MessageService` is not available that early.
|
|
157
|
+
*/
|
|
158
|
+
function bindConnectionDiagnostics(bind) {
|
|
159
|
+
bind(ConnectionDiagnosticsContribution).toSelf().inSingletonScope();
|
|
160
|
+
bind(frontend_application_contribution_1.FrontendApplicationContribution).toService(ConnectionDiagnosticsContribution);
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=connection-diagnostics-contribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-diagnostics-contribution.js","sourceRoot":"","sources":["../../src/browser/connection-diagnostics-contribution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { MessageService, type Progress } from '@theia/core';
|
|
10
|
+
import { type interfaces } from '@theia/core/shared/inversify';
|
|
11
|
+
/** What a head connects to, as the whole sentences reported about it. */
|
|
12
|
+
export interface ConnectionTarget {
|
|
13
|
+
readonly connectingMessage: string;
|
|
14
|
+
readonly connectedMessage: string;
|
|
15
|
+
}
|
|
16
|
+
/** One connection attempt; it reports exactly one end. */
|
|
17
|
+
export interface ConnectionAttempt {
|
|
18
|
+
connected(): void;
|
|
19
|
+
/** Ends the attempt with nothing to report, as when its head is disposed
|
|
20
|
+
* or a newer attempt takes over. */
|
|
21
|
+
cancelled(): void;
|
|
22
|
+
/**
|
|
23
|
+
* `message` is the whole sentence to report. `retry`, when given, starts a
|
|
24
|
+
* fresh attempt at once; a head without one keeps retrying on its own.
|
|
25
|
+
*/
|
|
26
|
+
failed(message: string, retry?: () => void): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* How a head's connection attempts reach the user. A head calls
|
|
30
|
+
* {@link connecting} for every attempt, a reconnect included, and keeps the
|
|
31
|
+
* attempt's retries and bounds itself; this decides only what is shown. Rebind
|
|
32
|
+
* the slot to show nothing, or something other than notifications.
|
|
33
|
+
*/
|
|
34
|
+
export interface ConnectionReporter {
|
|
35
|
+
connecting(target: ConnectionTarget): ConnectionAttempt;
|
|
36
|
+
}
|
|
37
|
+
export declare const ConnectionReporter: unique symbol;
|
|
38
|
+
/**
|
|
39
|
+
* Reports through Theia notifications: an attempt still running after
|
|
40
|
+
* {@link connectingNoticeDelayMs} shows its progress, and an attempt ends in at
|
|
41
|
+
* most one notification. A failure is shown once per target until it connects
|
|
42
|
+
* again, so a head that keeps retrying does not raise one per attempt.
|
|
43
|
+
*/
|
|
44
|
+
export declare class DefaultConnectionReporter implements ConnectionReporter {
|
|
45
|
+
protected readonly messageService: MessageService;
|
|
46
|
+
protected readonly connectingNoticeDelayMs: number;
|
|
47
|
+
/** Targets whose last reported attempt failed. */
|
|
48
|
+
protected readonly failing: Set<ConnectionTarget>;
|
|
49
|
+
connecting(target: ConnectionTarget): ConnectionAttempt;
|
|
50
|
+
protected showConnecting(target: ConnectionTarget): Promise<Progress>;
|
|
51
|
+
protected showConnected(target: ConnectionTarget): void;
|
|
52
|
+
protected showFailed(target: ConnectionTarget, message: string, retry?: () => void): Promise<void>;
|
|
53
|
+
protected retryLabel(): string;
|
|
54
|
+
}
|
|
55
|
+
/** Bind {@link DefaultConnectionReporter} unless the slot is bound already; every head calls this. */
|
|
56
|
+
export declare function bindConnectionReporter(bind: interfaces.Bind, isBound: interfaces.IsBound): void;
|
|
57
|
+
//# sourceMappingURL=connection-reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-reporter.d.ts","sourceRoot":"","sources":["../../src/browser/connection-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,cAAc,EAAO,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAEnF,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACpC;AAED,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAC/B,SAAS,IAAI,IAAI,CAAC;IAClB;yCACqC;IACrC,SAAS,IAAI,IAAI,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CACpD;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAChC,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;CAC1D;AACD,eAAO,MAAM,kBAAkB,eAA+B,CAAC;AAE/D;;;;;GAKG;AACH,qBACa,yBAA0B,YAAW,kBAAkB;IACzC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAG,cAAc,CAAC;IAE3E,SAAS,CAAC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAS;IAC3D,kDAAkD;IAClD,SAAS,CAAC,QAAQ,CAAC,OAAO,wBAA+B;IAEzD,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CA+BtD;IAED,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEpE;IAED,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAEtD;IAED,UAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvG;IAED,SAAS,CAAC,UAAU,IAAI,MAAM,CAE7B;CACH;AAED,sGAAsG;AACtG,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,GAAG,IAAI,CAI/F"}
|