@difizen/libro-kernel 0.0.2-alpha.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.
Files changed (188) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/es/basemanager.d.ts +94 -0
  4. package/es/basemanager.d.ts.map +1 -0
  5. package/es/basemanager.js +110 -0
  6. package/es/contents/contents-drive.d.ts +189 -0
  7. package/es/contents/contents-drive.d.ts.map +1 -0
  8. package/es/contents/contents-drive.js +792 -0
  9. package/es/contents/contents-manager.d.ts +229 -0
  10. package/es/contents/contents-manager.d.ts.map +1 -0
  11. package/es/contents/contents-manager.js +551 -0
  12. package/es/contents/contents-module.d.ts +3 -0
  13. package/es/contents/contents-module.d.ts.map +1 -0
  14. package/es/contents/contents-module.js +4 -0
  15. package/es/contents/contents-protocol.d.ts +487 -0
  16. package/es/contents/contents-protocol.d.ts.map +1 -0
  17. package/es/contents/contents-protocol.js +1 -0
  18. package/es/contents/index.d.ts +6 -0
  19. package/es/contents/index.d.ts.map +1 -0
  20. package/es/contents/index.js +5 -0
  21. package/es/contents/validate.d.ts +10 -0
  22. package/es/contents/validate.d.ts.map +1 -0
  23. package/es/contents/validate.js +22 -0
  24. package/es/index.d.ts +10 -0
  25. package/es/index.d.ts.map +1 -0
  26. package/es/index.js +9 -0
  27. package/es/index.less +0 -0
  28. package/es/kernel/comm.d.ts +92 -0
  29. package/es/kernel/comm.d.ts.map +1 -0
  30. package/es/kernel/comm.js +216 -0
  31. package/es/kernel/future.d.ts +178 -0
  32. package/es/kernel/future.d.ts.map +1 -0
  33. package/es/kernel/future.js +587 -0
  34. package/es/kernel/index.d.ts +8 -0
  35. package/es/kernel/index.d.ts.map +1 -0
  36. package/es/kernel/index.js +8 -0
  37. package/es/kernel/kernel-connection.d.ts +550 -0
  38. package/es/kernel/kernel-connection.d.ts.map +1 -0
  39. package/es/kernel/kernel-connection.js +1957 -0
  40. package/es/kernel/kernel-module.d.ts +3 -0
  41. package/es/kernel/kernel-module.d.ts.map +1 -0
  42. package/es/kernel/kernel-module.js +32 -0
  43. package/es/kernel/libro-kernel-manager.d.ts +69 -0
  44. package/es/kernel/libro-kernel-manager.d.ts.map +1 -0
  45. package/es/kernel/libro-kernel-manager.js +349 -0
  46. package/es/kernel/libro-kernel-protocol.d.ts +675 -0
  47. package/es/kernel/libro-kernel-protocol.d.ts.map +1 -0
  48. package/es/kernel/libro-kernel-protocol.js +60 -0
  49. package/es/kernel/libro-kernel-utils.d.ts +95 -0
  50. package/es/kernel/libro-kernel-utils.d.ts.map +1 -0
  51. package/es/kernel/libro-kernel-utils.js +130 -0
  52. package/es/kernel/libro-kernel.d.ts +14 -0
  53. package/es/kernel/libro-kernel.d.ts.map +1 -0
  54. package/es/kernel/libro-kernel.js +54 -0
  55. package/es/kernel/messages.d.ts +845 -0
  56. package/es/kernel/messages.d.ts.map +1 -0
  57. package/es/kernel/messages.js +457 -0
  58. package/es/kernel/restapi.d.ts +78 -0
  59. package/es/kernel/restapi.d.ts.map +1 -0
  60. package/es/kernel/restapi.js +367 -0
  61. package/es/kernel/serialize.d.ts +10 -0
  62. package/es/kernel/serialize.d.ts.map +1 -0
  63. package/es/kernel/serialize.js +214 -0
  64. package/es/kernel/validate.d.ts +15 -0
  65. package/es/kernel/validate.d.ts.map +1 -0
  66. package/es/kernel/validate.js +125 -0
  67. package/es/kernelspec/index.d.ts +5 -0
  68. package/es/kernelspec/index.d.ts.map +1 -0
  69. package/es/kernelspec/index.js +4 -0
  70. package/es/kernelspec/kernelspec-module.d.ts +3 -0
  71. package/es/kernelspec/kernelspec-module.d.ts.map +1 -0
  72. package/es/kernelspec/kernelspec-module.js +4 -0
  73. package/es/kernelspec/kernelspec.d.ts +33 -0
  74. package/es/kernelspec/kernelspec.d.ts.map +1 -0
  75. package/es/kernelspec/kernelspec.js +1 -0
  76. package/es/kernelspec/manager.d.ts +81 -0
  77. package/es/kernelspec/manager.d.ts.map +1 -0
  78. package/es/kernelspec/manager.js +248 -0
  79. package/es/kernelspec/restapi.d.ts +71 -0
  80. package/es/kernelspec/restapi.d.ts.map +1 -0
  81. package/es/kernelspec/restapi.js +107 -0
  82. package/es/kernelspec/validate.d.ts +10 -0
  83. package/es/kernelspec/validate.d.ts.map +1 -0
  84. package/es/kernelspec/validate.js +69 -0
  85. package/es/libro-kernel-connection-manager.d.ts +19 -0
  86. package/es/libro-kernel-connection-manager.d.ts.map +1 -0
  87. package/es/libro-kernel-connection-manager.js +142 -0
  88. package/es/module.d.ts +3 -0
  89. package/es/module.d.ts.map +1 -0
  90. package/es/module.js +9 -0
  91. package/es/page-config.d.ts +36 -0
  92. package/es/page-config.d.ts.map +1 -0
  93. package/es/page-config.js +129 -0
  94. package/es/protocol.d.ts +13 -0
  95. package/es/protocol.d.ts.map +1 -0
  96. package/es/protocol.js +8 -0
  97. package/es/server/connection-error.d.ts +36 -0
  98. package/es/server/connection-error.d.ts.map +1 -0
  99. package/es/server/connection-error.js +109 -0
  100. package/es/server/index.d.ts +6 -0
  101. package/es/server/index.d.ts.map +1 -0
  102. package/es/server/index.js +5 -0
  103. package/es/server/server-connection-protocol.d.ts +49 -0
  104. package/es/server/server-connection-protocol.d.ts.map +1 -0
  105. package/es/server/server-connection-protocol.js +0 -0
  106. package/es/server/server-connection.d.ts +25 -0
  107. package/es/server/server-connection.d.ts.map +1 -0
  108. package/es/server/server-connection.js +159 -0
  109. package/es/server/server-manager.d.ts +22 -0
  110. package/es/server/server-manager.d.ts.map +1 -0
  111. package/es/server/server-manager.js +163 -0
  112. package/es/server/server-module.d.ts +3 -0
  113. package/es/server/server-module.d.ts.map +1 -0
  114. package/es/server/server-module.js +4 -0
  115. package/es/session/index.d.ts +5 -0
  116. package/es/session/index.d.ts.map +1 -0
  117. package/es/session/index.js +4 -0
  118. package/es/session/libro-session-manager.d.ts +71 -0
  119. package/es/session/libro-session-manager.d.ts.map +1 -0
  120. package/es/session/libro-session-manager.js +539 -0
  121. package/es/session/libro-session-protocol.d.ts +50 -0
  122. package/es/session/libro-session-protocol.d.ts.map +1 -0
  123. package/es/session/libro-session-protocol.js +21 -0
  124. package/es/session/libro-session.d.ts +12 -0
  125. package/es/session/libro-session.d.ts.map +1 -0
  126. package/es/session/libro-session.js +19 -0
  127. package/es/session/restapi.d.ts +28 -0
  128. package/es/session/restapi.d.ts.map +1 -0
  129. package/es/session/restapi.js +214 -0
  130. package/es/session/session-module.d.ts +3 -0
  131. package/es/session/session-module.d.ts.map +1 -0
  132. package/es/session/session-module.js +18 -0
  133. package/es/session/validate.d.ts +14 -0
  134. package/es/session/validate.d.ts.map +1 -0
  135. package/es/session/validate.js +37 -0
  136. package/es/utils.d.ts +4 -0
  137. package/es/utils.d.ts.map +1 -0
  138. package/es/utils.js +29 -0
  139. package/es/validate-property.d.ts +2 -0
  140. package/es/validate-property.d.ts.map +1 -0
  141. package/es/validate-property.js +35 -0
  142. package/package.json +62 -0
  143. package/src/basemanager.ts +133 -0
  144. package/src/contents/contents-drive.ts +495 -0
  145. package/src/contents/contents-manager.ts +465 -0
  146. package/src/contents/contents-module.ts +6 -0
  147. package/src/contents/contents-protocol.ts +604 -0
  148. package/src/contents/index.ts +5 -0
  149. package/src/contents/validate.ts +29 -0
  150. package/src/index.tsx +9 -0
  151. package/src/kernel/comm.ts +220 -0
  152. package/src/kernel/future.ts +474 -0
  153. package/src/kernel/index.ts +7 -0
  154. package/src/kernel/kernel-connection.ts +1770 -0
  155. package/src/kernel/kernel-module.ts +50 -0
  156. package/src/kernel/libro-kernel-manager.ts +199 -0
  157. package/src/kernel/libro-kernel-protocol.ts +858 -0
  158. package/src/kernel/libro-kernel-utils.ts +152 -0
  159. package/src/kernel/libro-kernel.ts +39 -0
  160. package/src/kernel/messages.ts +1104 -0
  161. package/src/kernel/restapi.ts +183 -0
  162. package/src/kernel/serialize.ts +262 -0
  163. package/src/kernel/validate.ts +101 -0
  164. package/src/kernelspec/index.ts +5 -0
  165. package/src/kernelspec/kernelspec-module.ts +9 -0
  166. package/src/kernelspec/kernelspec.ts +37 -0
  167. package/src/kernelspec/manager.ts +173 -0
  168. package/src/kernelspec/restapi.ts +104 -0
  169. package/src/kernelspec/validate.ts +80 -0
  170. package/src/libro-kernel-connection-manager.ts +73 -0
  171. package/src/module.ts +19 -0
  172. package/src/page-config.ts +106 -0
  173. package/src/protocol.ts +24 -0
  174. package/src/server/connection-error.ts +60 -0
  175. package/src/server/index.ts +5 -0
  176. package/src/server/server-connection-protocol.ts +57 -0
  177. package/src/server/server-connection.ts +144 -0
  178. package/src/server/server-manager.ts +76 -0
  179. package/src/server/server-module.ts +9 -0
  180. package/src/session/index.ts +4 -0
  181. package/src/session/libro-session-manager.ts +377 -0
  182. package/src/session/libro-session-protocol.ts +61 -0
  183. package/src/session/libro-session.ts +33 -0
  184. package/src/session/restapi.ts +126 -0
  185. package/src/session/session-module.ts +26 -0
  186. package/src/session/validate.ts +39 -0
  187. package/src/utils.ts +28 -0
  188. package/src/validate-property.ts +38 -0
@@ -0,0 +1,220 @@
1
+ import type { JSONObject } from '@difizen/libro-common';
2
+
3
+ import type {
4
+ IComm,
5
+ IShellFuture,
6
+ IKernelConnection,
7
+ } from './libro-kernel-protocol.js';
8
+ import * as KernelMessage from './messages.js';
9
+
10
+ /**
11
+ * Comm channel handler.
12
+ */
13
+ export class CommHandler implements IComm {
14
+ protected _target = '';
15
+ protected _id = '';
16
+ protected _kernel: IKernelConnection;
17
+ protected _onClose: (
18
+ msg: KernelMessage.ICommCloseMsg<'iopub' | 'shell'>,
19
+ ) => void | PromiseLike<void>;
20
+ protected _onMsg: (msg: KernelMessage.ICommMsgMsg) => void | PromiseLike<void>;
21
+
22
+ protected disposeCb: () => void;
23
+ disposed = false;
24
+
25
+ /**
26
+ * Construct a new comm channel.
27
+ */
28
+ constructor(
29
+ target: string,
30
+ id: string,
31
+ kernel: IKernelConnection,
32
+ disposeCb: () => void,
33
+ ) {
34
+ this.disposeCb = disposeCb;
35
+ this._id = id;
36
+ this._target = target;
37
+ this._kernel = kernel;
38
+ }
39
+ dispose() {
40
+ this.disposeCb();
41
+ this.disposed = true;
42
+ }
43
+
44
+ /**
45
+ * The unique id for the comm channel.
46
+ */
47
+ get commId(): string {
48
+ return this._id;
49
+ }
50
+
51
+ /**
52
+ * The target name for the comm channel.
53
+ */
54
+ get targetName(): string {
55
+ return this._target;
56
+ }
57
+
58
+ /**
59
+ * Get the callback for a comm close event.
60
+ *
61
+ * #### Notes
62
+ * This is called when the comm is closed from either the server or client.
63
+ *
64
+ * **See also:** [[ICommClose]], [[close]]
65
+ */
66
+ get onClose(): (msg: KernelMessage.ICommCloseMsg) => void | PromiseLike<void> {
67
+ return this._onClose;
68
+ }
69
+
70
+ /**
71
+ * Set the callback for a comm close event.
72
+ *
73
+ * #### Notes
74
+ * This is called when the comm is closed from either the server or client. If
75
+ * the function returns a promise, and the kernel was closed from the server,
76
+ * kernel message processing will pause until the returned promise is
77
+ * fulfilled.
78
+ *
79
+ * **See also:** [[close]]
80
+ */
81
+ set onClose(cb: (msg: KernelMessage.ICommCloseMsg) => void | PromiseLike<void>) {
82
+ this._onClose = cb;
83
+ }
84
+
85
+ /**
86
+ * Get the callback for a comm message received event.
87
+ */
88
+ get onMsg(): (msg: KernelMessage.ICommMsgMsg) => void | PromiseLike<void> {
89
+ return this._onMsg;
90
+ }
91
+
92
+ /**
93
+ * Set the callback for a comm message received event.
94
+ *
95
+ * #### Notes
96
+ * This is called when a comm message is received. If the function returns a
97
+ * promise, kernel message processing will pause until it is fulfilled.
98
+ */
99
+ set onMsg(cb: (msg: KernelMessage.ICommMsgMsg) => void | PromiseLike<void>) {
100
+ this._onMsg = cb;
101
+ }
102
+
103
+ /**
104
+ * Open a comm with optional data and metadata.
105
+ *
106
+ * #### Notes
107
+ * This sends a `comm_open` message to the server.
108
+ *
109
+ * **See also:** [[ICommOpen]]
110
+ */
111
+ open(
112
+ data?: JSONObject,
113
+ metadata?: JSONObject,
114
+ buffers: (ArrayBuffer | ArrayBufferView)[] = [],
115
+ ): IShellFuture {
116
+ if (this.disposed || this._kernel.disposed) {
117
+ throw new Error('Cannot open');
118
+ }
119
+ const msg = KernelMessage.createMessage({
120
+ msgType: 'comm_open',
121
+ channel: 'shell',
122
+ username: this._kernel.username,
123
+ session: this._kernel.clientId,
124
+ content: {
125
+ comm_id: this._id,
126
+ target_name: this._target,
127
+ data: data ?? {},
128
+ },
129
+ metadata,
130
+ buffers,
131
+ });
132
+ return this._kernel.sendShellMessage(msg, false, true);
133
+ }
134
+
135
+ /**
136
+ * Send a `comm_msg` message to the kernel.
137
+ *
138
+ * #### Notes
139
+ * This is a no-op if the comm has been closed.
140
+ *
141
+ * **See also:** [[ICommMsg]]
142
+ */
143
+ send(
144
+ data: JSONObject,
145
+ metadata?: JSONObject,
146
+ buffers: (ArrayBuffer | ArrayBufferView)[] = [],
147
+ disposeOnDone = true,
148
+ ): IShellFuture {
149
+ if (this.disposed || this._kernel.disposed) {
150
+ throw new Error('Cannot send');
151
+ }
152
+ const msg = KernelMessage.createMessage({
153
+ msgType: 'comm_msg',
154
+ channel: 'shell',
155
+ username: this._kernel.username,
156
+ session: this._kernel.clientId,
157
+ content: {
158
+ comm_id: this._id,
159
+ data: data,
160
+ },
161
+ metadata,
162
+ buffers,
163
+ });
164
+ return this._kernel.sendShellMessage(msg, false, disposeOnDone);
165
+ }
166
+
167
+ /**
168
+ * Close the comm.
169
+ *
170
+ * #### Notes
171
+ * This will send a `comm_close` message to the kernel, and call the
172
+ * `onClose` callback if set.
173
+ *
174
+ * This is a no-op if the comm is already closed.
175
+ *
176
+ * **See also:** [[ICommClose]], [[onClose]]
177
+ */
178
+ close(
179
+ data?: JSONObject,
180
+ metadata?: JSONObject,
181
+ buffers: (ArrayBuffer | ArrayBufferView)[] = [],
182
+ ): IShellFuture {
183
+ if (this.disposed || this._kernel.disposed) {
184
+ throw new Error('Cannot close');
185
+ }
186
+ const msg = KernelMessage.createMessage({
187
+ msgType: 'comm_close',
188
+ channel: 'shell',
189
+ username: this._kernel.username,
190
+ session: this._kernel.clientId,
191
+ content: {
192
+ comm_id: this._id,
193
+ data: data ?? {},
194
+ },
195
+ metadata,
196
+ buffers,
197
+ });
198
+ const future = this._kernel.sendShellMessage(msg, false, true);
199
+ const onClose = this._onClose;
200
+ if (onClose) {
201
+ const ioMsg = KernelMessage.createMessage({
202
+ msgType: 'comm_close',
203
+ channel: 'iopub',
204
+ username: this._kernel.username,
205
+ session: this._kernel.clientId,
206
+ content: {
207
+ comm_id: this._id,
208
+ data: data ?? {},
209
+ },
210
+ metadata,
211
+ buffers,
212
+ });
213
+ // In the future, we may want to communicate back to the user the possible
214
+ // promise returned from onClose.
215
+ void onClose(ioMsg);
216
+ }
217
+ this.dispose();
218
+ return future;
219
+ }
220
+ }
@@ -0,0 +1,474 @@
1
+ import type { Disposable } from '@difizen/mana-app';
2
+ import { Deferred } from '@difizen/mana-app';
3
+
4
+ import type {
5
+ IKernelConnection,
6
+ IControlFuture,
7
+ IShellFuture,
8
+ IFuture,
9
+ } from './libro-kernel-protocol.js';
10
+ import { isStatusMsg } from './libro-kernel-utils.js';
11
+ import type * as KernelMessage from './messages.js';
12
+
13
+ declare let setImmediate: any;
14
+
15
+ namespace Private {
16
+ /**
17
+ * A no-op function.
18
+ */
19
+ export const noOp = (): void => {
20
+ /* no-op */
21
+ };
22
+
23
+ /**
24
+ * Defer a computation.
25
+ *
26
+ * #### NOTES
27
+ * We can't just use requestAnimationFrame since it is not available in node.
28
+ * This implementation is from Phosphor:
29
+ * https://github.com/phosphorjs/phosphor/blob/e88e4321289bb1198f3098e7bda40736501f2ed8/tests/test-messaging/src/index.spec.ts#L63
30
+ */
31
+ const defer = (() => {
32
+ const ok = typeof requestAnimationFrame === 'function';
33
+ return ok ? requestAnimationFrame : setImmediate;
34
+ })();
35
+
36
+ export class HookList<T> {
37
+ /**
38
+ * Register a hook.
39
+ *
40
+ * @param hook - The callback to register.
41
+ */
42
+ add(hook: (msg: T) => boolean | PromiseLike<boolean>): void {
43
+ this.remove(hook);
44
+ this._hooks.push(hook);
45
+ }
46
+
47
+ /**
48
+ * Remove a hook, if it exists in the hook list.
49
+ *
50
+ * @param hook - The callback to remove.
51
+ */
52
+ remove(hook: (msg: T) => boolean | PromiseLike<boolean>): void {
53
+ const index = this._hooks.indexOf(hook);
54
+ if (index >= 0) {
55
+ this._hooks[index] = null;
56
+ this._scheduleCompact();
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Process a message through the hooks.
62
+ *
63
+ * @returns a promise resolving to false if any hook resolved as false,
64
+ * otherwise true
65
+ *
66
+ * #### Notes
67
+ * The most recently registered hook is run first. A hook can return a
68
+ * boolean or a promise to a boolean, in which case processing pauses until
69
+ * the promise is fulfilled. If a hook return value resolves to false, any
70
+ * later hooks will not run and the function will return a promise resolving
71
+ * to false. If a hook throws an error, the error is logged to the console
72
+ * and the next hook is run. If a hook is registered during the hook
73
+ * processing, it will not run until the next message. If a hook is removed
74
+ * during the hook processing, it will be deactivated immediately.
75
+ */
76
+ async process(msg: T): Promise<boolean> {
77
+ // Wait until we can start a new process run.
78
+ await this._processing;
79
+
80
+ // Start the next process run.
81
+ const processing = new Deferred<void>();
82
+ this._processing = processing.promise;
83
+
84
+ let continueHandling: boolean;
85
+
86
+ // Call the end hook (most recently-added) first. Starting at the end also
87
+ // guarantees that hooks added during the processing will not be run in
88
+ // this process run.
89
+ for (let i = this._hooks.length - 1; i >= 0; i--) {
90
+ const hook = this._hooks[i];
91
+
92
+ // If the hook has been removed, continue to the next one.
93
+ if (hook === null) {
94
+ continue;
95
+ }
96
+
97
+ // Execute the hook and log any errors.
98
+ try {
99
+ // tslint:disable-next-line:await-promise
100
+ continueHandling = await hook(msg);
101
+ } catch (err) {
102
+ continueHandling = true;
103
+ console.error(err);
104
+ }
105
+
106
+ // If the hook resolved to false, stop processing and return.
107
+ if (continueHandling === false) {
108
+ processing.resolve(undefined);
109
+ return false;
110
+ }
111
+ }
112
+
113
+ // All hooks returned true (or errored out), so return true.
114
+ processing.resolve(undefined);
115
+ return true;
116
+ }
117
+
118
+ /**
119
+ * Schedule a cleanup of the list, removing any hooks that have been nulled out.
120
+ */
121
+ protected _scheduleCompact(): void {
122
+ if (!this._compactScheduled) {
123
+ this._compactScheduled = true;
124
+
125
+ // Schedule a compaction in between processing runs. We do the
126
+ // scheduling in an animation frame to rate-limit our compactions. If we
127
+ // need to compact more frequently, we can change this to directly
128
+ // schedule the compaction.
129
+ defer(() => {
130
+ this._processing = this._processing.then(() => {
131
+ this._compactScheduled = false;
132
+ this._compact();
133
+ return;
134
+ });
135
+ });
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Compact the list, removing any nulls.
141
+ */
142
+ protected _compact(): void {
143
+ let numNulls = 0;
144
+ for (let i = 0, len = this._hooks.length; i < len; i++) {
145
+ const hook = this._hooks[i];
146
+ if (this._hooks[i] === null) {
147
+ numNulls++;
148
+ } else {
149
+ this._hooks[i - numNulls] = hook;
150
+ }
151
+ }
152
+ this._hooks.length -= numNulls;
153
+ }
154
+
155
+ protected _hooks: (((msg: T) => boolean | PromiseLike<boolean>) | null)[] = [];
156
+ protected _compactScheduled: boolean;
157
+ protected _processing: Promise<void>;
158
+ }
159
+
160
+ /**
161
+ * Bit flags for the kernel future state.
162
+ */
163
+ export enum KernelFutureFlag {
164
+ GotReply = 0x1,
165
+ GotIdle = 0x2,
166
+ IsDone = 0x4,
167
+ DisposeOnDone = 0x8,
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Implementation of a kernel future.
173
+ *
174
+ * If a reply is expected, the Future is considered done when both a `reply`
175
+ * message and an `idle` iopub status message have been received. Otherwise, it
176
+ * is considered done when the `idle` status is received.
177
+ *
178
+ */
179
+ export abstract class KernelFutureHandler<
180
+ REQUEST extends KernelMessage.IShellControlMessage,
181
+ REPLY extends KernelMessage.IShellControlMessage,
182
+ >
183
+ implements Disposable, IFuture<REQUEST, REPLY>
184
+ {
185
+ protected disposeCb: () => void;
186
+ disposed = false;
187
+ /**
188
+ * Construct a new KernelFutureHandler.
189
+ */
190
+ constructor(
191
+ cb: () => void,
192
+ msg: REQUEST,
193
+ expectReply: boolean,
194
+ disposeOnDone: boolean,
195
+ kernel: IKernelConnection,
196
+ ) {
197
+ this.disposeCb = cb;
198
+ this._msg = msg;
199
+ if (!expectReply) {
200
+ this._setFlag(Private.KernelFutureFlag.GotReply);
201
+ }
202
+ this._disposeOnDone = disposeOnDone;
203
+ this._kernel = kernel;
204
+ }
205
+
206
+ /**
207
+ * Get the original outgoing message.
208
+ */
209
+ get msg(): REQUEST {
210
+ return this._msg;
211
+ }
212
+
213
+ /**
214
+ * A promise that resolves when the future is done.
215
+ */
216
+ get done(): Promise<REPLY> {
217
+ return this._done.promise;
218
+ }
219
+
220
+ /**
221
+ * Get the reply handler.
222
+ */
223
+ get onReply(): (msg: REPLY) => void | PromiseLike<void> {
224
+ return this._reply;
225
+ }
226
+
227
+ /**
228
+ * Set the reply handler.
229
+ */
230
+ set onReply(cb: (msg: REPLY) => void | PromiseLike<void>) {
231
+ this._reply = cb;
232
+ }
233
+
234
+ /**
235
+ * Get the iopub handler.
236
+ */
237
+ get onIOPub(): (msg: KernelMessage.IIOPubMessage) => void | PromiseLike<void> {
238
+ return this._iopub;
239
+ }
240
+
241
+ /**
242
+ * Set the iopub handler.
243
+ */
244
+ set onIOPub(cb: (msg: KernelMessage.IIOPubMessage) => void | PromiseLike<void>) {
245
+ this._iopub = cb;
246
+ }
247
+
248
+ /**
249
+ * Get the stdin handler.
250
+ */
251
+ get onStdin(): (msg: KernelMessage.IStdinMessage) => void | PromiseLike<void> {
252
+ return this._stdin;
253
+ }
254
+
255
+ /**
256
+ * Set the stdin handler.
257
+ */
258
+ set onStdin(cb: (msg: KernelMessage.IStdinMessage) => void | PromiseLike<void>) {
259
+ this._stdin = cb;
260
+ }
261
+
262
+ /**
263
+ * Register hook for IOPub messages.
264
+ *
265
+ * @param hook - The callback invoked for an IOPub message.
266
+ *
267
+ * #### Notes
268
+ * The IOPub hook system allows you to preempt the handlers for IOPub
269
+ * messages handled by the future.
270
+ *
271
+ * The most recently registered hook is run first. A hook can return a
272
+ * boolean or a promise to a boolean, in which case all kernel message
273
+ * processing pauses until the promise is fulfilled. If a hook return value
274
+ * resolves to false, any later hooks will not run and the function will
275
+ * return a promise resolving to false. If a hook throws an error, the error
276
+ * is logged to the console and the next hook is run. If a hook is
277
+ * registered during the hook processing, it will not run until the next
278
+ * message. If a hook is removed during the hook processing, it will be
279
+ * deactivated immediately.
280
+ */
281
+ registerMessageHook(
282
+ hook: (msg: KernelMessage.IIOPubMessage) => boolean | PromiseLike<boolean>,
283
+ ): void {
284
+ if (this.disposed) {
285
+ throw new Error('Kernel future is disposed');
286
+ }
287
+ this._hooks.add(hook);
288
+ }
289
+
290
+ /**
291
+ * Remove a hook for IOPub messages.
292
+ *
293
+ * @param hook - The hook to remove.
294
+ *
295
+ * #### Notes
296
+ * If a hook is removed during the hook processing, it will be deactivated immediately.
297
+ */
298
+ removeMessageHook(
299
+ hook: (msg: KernelMessage.IIOPubMessage) => boolean | PromiseLike<boolean>,
300
+ ): void {
301
+ if (this.disposed) {
302
+ return;
303
+ }
304
+ this._hooks.remove(hook);
305
+ }
306
+
307
+ /**
308
+ * Send an `input_reply` message.
309
+ */
310
+ sendInputReply(
311
+ content: KernelMessage.IInputReplyMsg['content'],
312
+ parent_header: KernelMessage.IInputReplyMsg['parent_header'],
313
+ ): void {
314
+ this._kernel.sendInputReply(content, parent_header);
315
+ }
316
+
317
+ /**
318
+ * Dispose and unregister the future.
319
+ */
320
+ dispose(): void {
321
+ this._stdin = Private.noOp;
322
+ this._iopub = Private.noOp;
323
+ this._reply = Private.noOp;
324
+ this._hooks = null!;
325
+ if (!this._testFlag(Private.KernelFutureFlag.IsDone)) {
326
+ // TODO: Uncomment the following logging code, and check for any tests that trigger it.
327
+ // let status = [];
328
+ // if (!this._testFlag(Private.KernelFutureFlag.GotIdle)) {
329
+ // status.push('idle');
330
+ // }
331
+ // if (!this._testFlag(Private.KernelFutureFlag.GotReply)) {
332
+ // status.push('reply');
333
+ // }
334
+ // console.warn(
335
+ // `*************** DISPOSED BEFORE DONE: K${this._kernel.id.slice(
336
+ // 0,
337
+ // 6
338
+ // )} M${this._msg.header.msg_id.slice(0, 6)} missing ${status.join(' ')}`
339
+ // );
340
+
341
+ // Reject the `done` promise, but catch its error here in case no one else
342
+ // is waiting for the promise to resolve. This prevents the error from
343
+ // being displayed in the console, but does not prevent it from being
344
+ // caught by a client who is waiting for it.
345
+ this._done.promise.catch(() => {
346
+ /* no-op */
347
+ });
348
+ this._done.reject(
349
+ new Error(
350
+ `Canceled future for ${this.msg.header.msg_type} message before replies were done`,
351
+ ),
352
+ );
353
+ }
354
+ this.disposeCb();
355
+ this.disposed = true;
356
+ }
357
+
358
+ /**
359
+ * Handle an incoming kernel message.
360
+ */
361
+ async handleMsg(msg: KernelMessage.IMessage): Promise<void> {
362
+ switch (msg.channel) {
363
+ case 'control':
364
+ case 'shell':
365
+ if (
366
+ msg.channel === this.msg.channel &&
367
+ (msg.parent_header as KernelMessage.IHeader<KernelMessage.MessageType>)
368
+ .msg_id === this.msg.header.msg_id
369
+ ) {
370
+ await this._handleReply(msg as REPLY);
371
+ }
372
+ break;
373
+ case 'stdin':
374
+ await this._handleStdin(msg as KernelMessage.IStdinMessage);
375
+ break;
376
+ case 'iopub':
377
+ await this._handleIOPub(msg as KernelMessage.IIOPubMessage);
378
+ break;
379
+ default:
380
+ break;
381
+ }
382
+ }
383
+
384
+ protected async _handleReply(msg: REPLY): Promise<void> {
385
+ const reply = this._reply;
386
+ if (reply) {
387
+ // tslint:disable-next-line:await-promise
388
+ await reply(msg);
389
+ }
390
+ this._replyMsg = msg;
391
+ this._setFlag(Private.KernelFutureFlag.GotReply);
392
+ if (this._testFlag(Private.KernelFutureFlag.GotIdle)) {
393
+ this._handleDone();
394
+ }
395
+ }
396
+
397
+ protected async _handleStdin(msg: KernelMessage.IStdinMessage): Promise<void> {
398
+ this._kernel.hasPendingInput = true;
399
+ const stdin = this._stdin;
400
+ if (stdin) {
401
+ // tslint:disable-next-line:await-promise
402
+ await stdin(msg);
403
+ }
404
+ }
405
+
406
+ protected async _handleIOPub(msg: KernelMessage.IIOPubMessage): Promise<void> {
407
+ const process = await this._hooks.process(msg);
408
+ const iopub = this._iopub;
409
+ if (process && iopub) {
410
+ // tslint:disable-next-line:await-promise
411
+ await iopub(msg);
412
+ }
413
+ if (isStatusMsg(msg) && msg.content.execution_state === 'idle') {
414
+ this._setFlag(Private.KernelFutureFlag.GotIdle);
415
+ if (this._testFlag(Private.KernelFutureFlag.GotReply)) {
416
+ this._handleDone();
417
+ }
418
+ }
419
+ }
420
+
421
+ protected _handleDone(): void {
422
+ if (this._testFlag(Private.KernelFutureFlag.IsDone)) {
423
+ return;
424
+ }
425
+ this._setFlag(Private.KernelFutureFlag.IsDone);
426
+ this._done.resolve(this._replyMsg);
427
+ if (this._disposeOnDone) {
428
+ this.dispose();
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Test whether the given future flag is set.
434
+ */
435
+ protected _testFlag(flag: Private.KernelFutureFlag): boolean {
436
+ // tslint:disable-next-line
437
+ return (this._status & flag) !== 0;
438
+ }
439
+
440
+ /**
441
+ * Set the given future flag.
442
+ */
443
+ protected _setFlag(flag: Private.KernelFutureFlag): void {
444
+ // tslint:disable-next-line
445
+ this._status |= flag;
446
+ }
447
+
448
+ protected _msg: REQUEST;
449
+ protected _status = 0;
450
+ protected _stdin: (msg: KernelMessage.IStdinMessage) => void | PromiseLike<void> =
451
+ Private.noOp;
452
+ protected _iopub: (msg: KernelMessage.IIOPubMessage) => void | PromiseLike<void> =
453
+ Private.noOp;
454
+ protected _reply: (msg: REPLY) => void | PromiseLike<void> = Private.noOp;
455
+ protected _done = new Deferred<REPLY>();
456
+ protected _replyMsg: REPLY;
457
+ protected _hooks = new Private.HookList<KernelMessage.IIOPubMessage>();
458
+ protected _disposeOnDone = true;
459
+ protected _kernel: IKernelConnection;
460
+ }
461
+
462
+ export class KernelControlFutureHandler<
463
+ REQUEST extends KernelMessage.IControlMessage = KernelMessage.IControlMessage,
464
+ REPLY extends KernelMessage.IControlMessage = KernelMessage.IControlMessage,
465
+ >
466
+ extends KernelFutureHandler<REQUEST, REPLY>
467
+ implements IControlFuture<REQUEST, REPLY> {}
468
+
469
+ export class KernelShellFutureHandler<
470
+ REQUEST extends KernelMessage.IShellMessage = KernelMessage.IShellMessage,
471
+ REPLY extends KernelMessage.IShellMessage = KernelMessage.IShellMessage,
472
+ >
473
+ extends KernelFutureHandler<REQUEST, REPLY>
474
+ implements IShellFuture<REQUEST, REPLY> {}
@@ -0,0 +1,7 @@
1
+ export * from './kernel-connection.js';
2
+ export * from './kernel-module.js';
3
+ export * as KernelMessage from './messages.js';
4
+ export * from './libro-kernel-manager.js';
5
+ export * from './libro-kernel-protocol.js';
6
+ export * from './libro-kernel-utils.js';
7
+ export * from './restapi.js';