@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.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/es/basemanager.d.ts +94 -0
- package/es/basemanager.d.ts.map +1 -0
- package/es/basemanager.js +110 -0
- package/es/contents/contents-drive.d.ts +189 -0
- package/es/contents/contents-drive.d.ts.map +1 -0
- package/es/contents/contents-drive.js +792 -0
- package/es/contents/contents-manager.d.ts +229 -0
- package/es/contents/contents-manager.d.ts.map +1 -0
- package/es/contents/contents-manager.js +551 -0
- package/es/contents/contents-module.d.ts +3 -0
- package/es/contents/contents-module.d.ts.map +1 -0
- package/es/contents/contents-module.js +4 -0
- package/es/contents/contents-protocol.d.ts +487 -0
- package/es/contents/contents-protocol.d.ts.map +1 -0
- package/es/contents/contents-protocol.js +1 -0
- package/es/contents/index.d.ts +6 -0
- package/es/contents/index.d.ts.map +1 -0
- package/es/contents/index.js +5 -0
- package/es/contents/validate.d.ts +10 -0
- package/es/contents/validate.d.ts.map +1 -0
- package/es/contents/validate.js +22 -0
- package/es/index.d.ts +10 -0
- package/es/index.d.ts.map +1 -0
- package/es/index.js +9 -0
- package/es/index.less +0 -0
- package/es/kernel/comm.d.ts +92 -0
- package/es/kernel/comm.d.ts.map +1 -0
- package/es/kernel/comm.js +216 -0
- package/es/kernel/future.d.ts +178 -0
- package/es/kernel/future.d.ts.map +1 -0
- package/es/kernel/future.js +587 -0
- package/es/kernel/index.d.ts +8 -0
- package/es/kernel/index.d.ts.map +1 -0
- package/es/kernel/index.js +8 -0
- package/es/kernel/kernel-connection.d.ts +550 -0
- package/es/kernel/kernel-connection.d.ts.map +1 -0
- package/es/kernel/kernel-connection.js +1957 -0
- package/es/kernel/kernel-module.d.ts +3 -0
- package/es/kernel/kernel-module.d.ts.map +1 -0
- package/es/kernel/kernel-module.js +32 -0
- package/es/kernel/libro-kernel-manager.d.ts +69 -0
- package/es/kernel/libro-kernel-manager.d.ts.map +1 -0
- package/es/kernel/libro-kernel-manager.js +349 -0
- package/es/kernel/libro-kernel-protocol.d.ts +675 -0
- package/es/kernel/libro-kernel-protocol.d.ts.map +1 -0
- package/es/kernel/libro-kernel-protocol.js +60 -0
- package/es/kernel/libro-kernel-utils.d.ts +95 -0
- package/es/kernel/libro-kernel-utils.d.ts.map +1 -0
- package/es/kernel/libro-kernel-utils.js +130 -0
- package/es/kernel/libro-kernel.d.ts +14 -0
- package/es/kernel/libro-kernel.d.ts.map +1 -0
- package/es/kernel/libro-kernel.js +54 -0
- package/es/kernel/messages.d.ts +845 -0
- package/es/kernel/messages.d.ts.map +1 -0
- package/es/kernel/messages.js +457 -0
- package/es/kernel/restapi.d.ts +78 -0
- package/es/kernel/restapi.d.ts.map +1 -0
- package/es/kernel/restapi.js +367 -0
- package/es/kernel/serialize.d.ts +10 -0
- package/es/kernel/serialize.d.ts.map +1 -0
- package/es/kernel/serialize.js +214 -0
- package/es/kernel/validate.d.ts +15 -0
- package/es/kernel/validate.d.ts.map +1 -0
- package/es/kernel/validate.js +125 -0
- package/es/kernelspec/index.d.ts +5 -0
- package/es/kernelspec/index.d.ts.map +1 -0
- package/es/kernelspec/index.js +4 -0
- package/es/kernelspec/kernelspec-module.d.ts +3 -0
- package/es/kernelspec/kernelspec-module.d.ts.map +1 -0
- package/es/kernelspec/kernelspec-module.js +4 -0
- package/es/kernelspec/kernelspec.d.ts +33 -0
- package/es/kernelspec/kernelspec.d.ts.map +1 -0
- package/es/kernelspec/kernelspec.js +1 -0
- package/es/kernelspec/manager.d.ts +81 -0
- package/es/kernelspec/manager.d.ts.map +1 -0
- package/es/kernelspec/manager.js +248 -0
- package/es/kernelspec/restapi.d.ts +71 -0
- package/es/kernelspec/restapi.d.ts.map +1 -0
- package/es/kernelspec/restapi.js +107 -0
- package/es/kernelspec/validate.d.ts +10 -0
- package/es/kernelspec/validate.d.ts.map +1 -0
- package/es/kernelspec/validate.js +69 -0
- package/es/libro-kernel-connection-manager.d.ts +19 -0
- package/es/libro-kernel-connection-manager.d.ts.map +1 -0
- package/es/libro-kernel-connection-manager.js +142 -0
- package/es/module.d.ts +3 -0
- package/es/module.d.ts.map +1 -0
- package/es/module.js +9 -0
- package/es/page-config.d.ts +36 -0
- package/es/page-config.d.ts.map +1 -0
- package/es/page-config.js +129 -0
- package/es/protocol.d.ts +13 -0
- package/es/protocol.d.ts.map +1 -0
- package/es/protocol.js +8 -0
- package/es/server/connection-error.d.ts +36 -0
- package/es/server/connection-error.d.ts.map +1 -0
- package/es/server/connection-error.js +109 -0
- package/es/server/index.d.ts +6 -0
- package/es/server/index.d.ts.map +1 -0
- package/es/server/index.js +5 -0
- package/es/server/server-connection-protocol.d.ts +49 -0
- package/es/server/server-connection-protocol.d.ts.map +1 -0
- package/es/server/server-connection-protocol.js +0 -0
- package/es/server/server-connection.d.ts +25 -0
- package/es/server/server-connection.d.ts.map +1 -0
- package/es/server/server-connection.js +159 -0
- package/es/server/server-manager.d.ts +22 -0
- package/es/server/server-manager.d.ts.map +1 -0
- package/es/server/server-manager.js +163 -0
- package/es/server/server-module.d.ts +3 -0
- package/es/server/server-module.d.ts.map +1 -0
- package/es/server/server-module.js +4 -0
- package/es/session/index.d.ts +5 -0
- package/es/session/index.d.ts.map +1 -0
- package/es/session/index.js +4 -0
- package/es/session/libro-session-manager.d.ts +71 -0
- package/es/session/libro-session-manager.d.ts.map +1 -0
- package/es/session/libro-session-manager.js +539 -0
- package/es/session/libro-session-protocol.d.ts +50 -0
- package/es/session/libro-session-protocol.d.ts.map +1 -0
- package/es/session/libro-session-protocol.js +21 -0
- package/es/session/libro-session.d.ts +12 -0
- package/es/session/libro-session.d.ts.map +1 -0
- package/es/session/libro-session.js +19 -0
- package/es/session/restapi.d.ts +28 -0
- package/es/session/restapi.d.ts.map +1 -0
- package/es/session/restapi.js +214 -0
- package/es/session/session-module.d.ts +3 -0
- package/es/session/session-module.d.ts.map +1 -0
- package/es/session/session-module.js +18 -0
- package/es/session/validate.d.ts +14 -0
- package/es/session/validate.d.ts.map +1 -0
- package/es/session/validate.js +37 -0
- package/es/utils.d.ts +4 -0
- package/es/utils.d.ts.map +1 -0
- package/es/utils.js +29 -0
- package/es/validate-property.d.ts +2 -0
- package/es/validate-property.d.ts.map +1 -0
- package/es/validate-property.js +35 -0
- package/package.json +62 -0
- package/src/basemanager.ts +133 -0
- package/src/contents/contents-drive.ts +495 -0
- package/src/contents/contents-manager.ts +465 -0
- package/src/contents/contents-module.ts +6 -0
- package/src/contents/contents-protocol.ts +604 -0
- package/src/contents/index.ts +5 -0
- package/src/contents/validate.ts +29 -0
- package/src/index.tsx +9 -0
- package/src/kernel/comm.ts +220 -0
- package/src/kernel/future.ts +474 -0
- package/src/kernel/index.ts +7 -0
- package/src/kernel/kernel-connection.ts +1770 -0
- package/src/kernel/kernel-module.ts +50 -0
- package/src/kernel/libro-kernel-manager.ts +199 -0
- package/src/kernel/libro-kernel-protocol.ts +858 -0
- package/src/kernel/libro-kernel-utils.ts +152 -0
- package/src/kernel/libro-kernel.ts +39 -0
- package/src/kernel/messages.ts +1104 -0
- package/src/kernel/restapi.ts +183 -0
- package/src/kernel/serialize.ts +262 -0
- package/src/kernel/validate.ts +101 -0
- package/src/kernelspec/index.ts +5 -0
- package/src/kernelspec/kernelspec-module.ts +9 -0
- package/src/kernelspec/kernelspec.ts +37 -0
- package/src/kernelspec/manager.ts +173 -0
- package/src/kernelspec/restapi.ts +104 -0
- package/src/kernelspec/validate.ts +80 -0
- package/src/libro-kernel-connection-manager.ts +73 -0
- package/src/module.ts +19 -0
- package/src/page-config.ts +106 -0
- package/src/protocol.ts +24 -0
- package/src/server/connection-error.ts +60 -0
- package/src/server/index.ts +5 -0
- package/src/server/server-connection-protocol.ts +57 -0
- package/src/server/server-connection.ts +144 -0
- package/src/server/server-manager.ts +76 -0
- package/src/server/server-module.ts +9 -0
- package/src/session/index.ts +4 -0
- package/src/session/libro-session-manager.ts +377 -0
- package/src/session/libro-session-protocol.ts +61 -0
- package/src/session/libro-session.ts +33 -0
- package/src/session/restapi.ts +126 -0
- package/src/session/session-module.ts +26 -0
- package/src/session/validate.ts +39 -0
- package/src/utils.ts +28 -0
- package/src/validate-property.ts +38 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { deepEqual, Poll } from '@difizen/libro-common';
|
|
2
|
+
import type { Event as ManaEvent } from '@difizen/mana-app';
|
|
3
|
+
import { Emitter, Deferred } from '@difizen/mana-app';
|
|
4
|
+
import { inject, singleton } from '@difizen/mana-app';
|
|
5
|
+
import { prop } from '@difizen/mana-app';
|
|
6
|
+
|
|
7
|
+
import { BaseManager } from '../basemanager.js';
|
|
8
|
+
import { ServerManager } from '../server/server-manager.js';
|
|
9
|
+
|
|
10
|
+
import type * as KernelSpec from './kernelspec.js';
|
|
11
|
+
import type { ISpecModels } from './restapi.js';
|
|
12
|
+
import { KernelSpecRestAPI } from './restapi.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* An implementation of a kernel spec manager.
|
|
16
|
+
*/
|
|
17
|
+
@singleton()
|
|
18
|
+
export class KernelSpecManager extends BaseManager implements KernelSpec.IManager {
|
|
19
|
+
@inject(ServerManager)
|
|
20
|
+
protected serverManager: ServerManager;
|
|
21
|
+
@inject(KernelSpecRestAPI)
|
|
22
|
+
protected kernelSpecRestAPI: KernelSpecRestAPI;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Construct a new kernel spec manager.
|
|
26
|
+
*
|
|
27
|
+
* @param options - The default options for kernel.
|
|
28
|
+
*/
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
// Initialize internal data.
|
|
33
|
+
this._ready = Promise.all([this.requestSpecs()])
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
35
|
+
.then((_) => undefined)
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
37
|
+
.catch((_) => undefined)
|
|
38
|
+
.then(() => {
|
|
39
|
+
if (this.isDisposed) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this._isReady = true;
|
|
43
|
+
return;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this._pollSpecs = new Poll({
|
|
47
|
+
auto: false,
|
|
48
|
+
factory: () => this.requestSpecs(),
|
|
49
|
+
frequency: {
|
|
50
|
+
interval: 61 * 1000,
|
|
51
|
+
backoff: true,
|
|
52
|
+
max: 300 * 1000,
|
|
53
|
+
},
|
|
54
|
+
name: `@jupyterlab/services:KernelSpecManager#specs`,
|
|
55
|
+
standby: 'when-hidden',
|
|
56
|
+
// standby: options.standby ?? 'when-hidden',
|
|
57
|
+
});
|
|
58
|
+
void this.ready.then(() => {
|
|
59
|
+
void this._pollSpecs.start();
|
|
60
|
+
return;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The server settings for the manager.
|
|
66
|
+
*/
|
|
67
|
+
// readonly serverSettings: ServerConnection.ISettings;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Test whether the manager is ready.
|
|
71
|
+
*/
|
|
72
|
+
// get isReady(): boolean {
|
|
73
|
+
// return this._isReady;
|
|
74
|
+
// }
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A promise that fulfills when the manager is ready.
|
|
78
|
+
*/
|
|
79
|
+
// get ready(): Promise<void> {
|
|
80
|
+
// return this._ready;
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
get specsReady() {
|
|
84
|
+
return this.specsDeferred.promise;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get the most recently fetched kernel specs.
|
|
89
|
+
*/
|
|
90
|
+
get specs(): ISpecModels | null {
|
|
91
|
+
return this._specs;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A signal emitted when the specs change.
|
|
96
|
+
*/
|
|
97
|
+
get specsChanged(): ManaEvent<ISpecModels> {
|
|
98
|
+
return this.specsChangedEmitter.event;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* A signal emitted when there is a connection failure.
|
|
103
|
+
*/
|
|
104
|
+
override get connectionFailure(): ManaEvent<Error> {
|
|
105
|
+
return this.connectionFailureEmitter.event;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Dispose of the resources used by the manager.
|
|
110
|
+
*/
|
|
111
|
+
override dispose(): void {
|
|
112
|
+
this._pollSpecs.dispose();
|
|
113
|
+
super.dispose();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Force a refresh of the specs from the server.
|
|
118
|
+
*
|
|
119
|
+
* @returns A promise that resolves when the specs are fetched.
|
|
120
|
+
*
|
|
121
|
+
* #### Notes
|
|
122
|
+
* This is intended to be called only in response to a user action,
|
|
123
|
+
* since the manager maintains its internal state.
|
|
124
|
+
*/
|
|
125
|
+
async refreshSpecs(): Promise<void> {
|
|
126
|
+
await this._pollSpecs.refresh();
|
|
127
|
+
await this._pollSpecs.tick;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Execute a request to the server to poll specs and update state.
|
|
132
|
+
*/
|
|
133
|
+
protected async requestSpecs(): Promise<void> {
|
|
134
|
+
const specs = await this.kernelSpecRestAPI.getSpecs(this.serverSettings);
|
|
135
|
+
if (specs) {
|
|
136
|
+
this.specsDeferred.resolve(specs);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.isDisposed) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!this._specs || !deepEqual(specs, this._specs)) {
|
|
143
|
+
this._specs = specs;
|
|
144
|
+
this.specsChangedEmitter.fire(specs);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// protected _isReady = false;
|
|
149
|
+
protected override connectionFailureEmitter = new Emitter<Error>();
|
|
150
|
+
|
|
151
|
+
protected _pollSpecs: Poll;
|
|
152
|
+
// protected _ready: Promise<void>;
|
|
153
|
+
|
|
154
|
+
@prop()
|
|
155
|
+
protected _specs: ISpecModels | null = null;
|
|
156
|
+
protected specsChangedEmitter = new Emitter<ISpecModels>();
|
|
157
|
+
protected specsDeferred = new Deferred<ISpecModels>();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The namespace for `KernelManager` class statics.
|
|
162
|
+
*/
|
|
163
|
+
export namespace KernelSpecManager {
|
|
164
|
+
/**
|
|
165
|
+
* The options used to initialize a KernelManager.
|
|
166
|
+
*/
|
|
167
|
+
export interface IOptions extends BaseManager.IOptions {
|
|
168
|
+
/**
|
|
169
|
+
* When the manager stops polling the API. Defaults to `when-hidden`.
|
|
170
|
+
*/
|
|
171
|
+
standby?: Poll.Standby | (() => boolean | Poll.Standby);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// import { URL } from '@difizen/libro-common';
|
|
2
|
+
import type { PartialJSONObject } from '@difizen/libro-common';
|
|
3
|
+
import { inject, singleton } from '@difizen/mana-app';
|
|
4
|
+
|
|
5
|
+
import { createResponseError } from '../server/connection-error.js';
|
|
6
|
+
import type { ISettings } from '../server/server-connection-protocol.js';
|
|
7
|
+
import { ServerConnection } from '../server/server-connection.js';
|
|
8
|
+
|
|
9
|
+
import { validateSpecModels } from './validate.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The url for the kernelspec service.
|
|
13
|
+
*/
|
|
14
|
+
const KERNELSPEC_SERVICE_URL = 'api/kernelspecs';
|
|
15
|
+
@singleton()
|
|
16
|
+
export class KernelSpecRestAPI {
|
|
17
|
+
@inject(ServerConnection) serverConnection: ServerConnection;
|
|
18
|
+
/**
|
|
19
|
+
* Fetch all of the kernel specs.
|
|
20
|
+
*
|
|
21
|
+
* @param settings - The optional server settings.
|
|
22
|
+
* @param useCache - Whether to use the cache. If false, always request.
|
|
23
|
+
*
|
|
24
|
+
* @returns A promise that resolves with the kernel specs.
|
|
25
|
+
*
|
|
26
|
+
* #### Notes
|
|
27
|
+
* Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs).
|
|
28
|
+
*/
|
|
29
|
+
async getSpecs(serverSettings?: Partial<ISettings>): Promise<ISpecModels> {
|
|
30
|
+
const settings = { ...this.serverConnection.settings, ...serverSettings };
|
|
31
|
+
const url = settings.baseUrl + KERNELSPEC_SERVICE_URL;
|
|
32
|
+
// TODO: 当前URL.join 方法是坏的
|
|
33
|
+
// const url = URL.join(settings.baseUrl, KERNELSPEC_SERVICE_URL);
|
|
34
|
+
|
|
35
|
+
const response = await this.serverConnection.makeRequest(url, {}, settings);
|
|
36
|
+
if (response.status !== 200) {
|
|
37
|
+
const err = await createResponseError(response);
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
return validateSpecModels(data);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Kernel Spec interface.
|
|
47
|
+
*
|
|
48
|
+
* #### Notes
|
|
49
|
+
* See [Kernel specs](https://jupyter-client.readthedocs.io/en/latest/kernels.html#kernelspecs).
|
|
50
|
+
*/
|
|
51
|
+
export interface ISpecModel extends PartialJSONObject {
|
|
52
|
+
/**
|
|
53
|
+
* The name of the kernel spec.
|
|
54
|
+
*/
|
|
55
|
+
readonly name: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The name of the language of the kernel.
|
|
59
|
+
*/
|
|
60
|
+
readonly language: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A list of command line arguments used to start the kernel.
|
|
64
|
+
*/
|
|
65
|
+
readonly argv: string[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The kernel’s name as it should be displayed in the UI.
|
|
69
|
+
*/
|
|
70
|
+
readonly display_name: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A dictionary of environment variables to set for the kernel.
|
|
74
|
+
*/
|
|
75
|
+
readonly env?: PartialJSONObject;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A mapping of resource file name to download path.
|
|
79
|
+
*/
|
|
80
|
+
readonly resources: Record<string, string>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A dictionary of additional attributes about this kernel; used by clients to aid in kernel selection.
|
|
84
|
+
*/
|
|
85
|
+
readonly metadata?: PartialJSONObject;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The available kernelSpec models.
|
|
90
|
+
*
|
|
91
|
+
* #### Notes
|
|
92
|
+
* See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs).
|
|
93
|
+
*/
|
|
94
|
+
export interface ISpecModels extends PartialJSONObject {
|
|
95
|
+
/**
|
|
96
|
+
* The name of the default kernel spec.
|
|
97
|
+
*/
|
|
98
|
+
default: string;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A mapping of kernel spec name to spec.
|
|
102
|
+
*/
|
|
103
|
+
readonly kernelspecs: Record<string, ISpecModel | undefined>;
|
|
104
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* eslint-disable no-prototype-builtins */
|
|
2
|
+
import { validateProperty } from '../validate-property.js';
|
|
3
|
+
|
|
4
|
+
import type { ISpecModel, ISpecModels } from './restapi.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validate a server kernelspec model to a client side model.
|
|
8
|
+
*/
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
10
|
+
export function validateSpecModel(data: any): ISpecModel {
|
|
11
|
+
const spec = data.spec;
|
|
12
|
+
if (!spec) {
|
|
13
|
+
throw new Error('Invalid kernel spec');
|
|
14
|
+
}
|
|
15
|
+
validateProperty(data, 'name', 'string');
|
|
16
|
+
validateProperty(data, 'resources', 'object');
|
|
17
|
+
validateProperty(spec, 'language', 'string');
|
|
18
|
+
validateProperty(spec, 'display_name', 'string');
|
|
19
|
+
validateProperty(spec, 'argv', 'array');
|
|
20
|
+
|
|
21
|
+
let metadata: any = null;
|
|
22
|
+
if (spec.hasOwnProperty('metadata')) {
|
|
23
|
+
validateProperty(spec, 'metadata', 'object');
|
|
24
|
+
metadata = spec.metadata;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let env: any = null;
|
|
28
|
+
if (spec.hasOwnProperty('env')) {
|
|
29
|
+
validateProperty(spec, 'env', 'object');
|
|
30
|
+
env = spec.env;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
name: data.name,
|
|
34
|
+
resources: data.resources,
|
|
35
|
+
language: spec.language,
|
|
36
|
+
display_name: spec.display_name,
|
|
37
|
+
argv: spec.argv,
|
|
38
|
+
metadata,
|
|
39
|
+
env,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validate a `Kernel.ISpecModels` object.
|
|
45
|
+
*/
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
47
|
+
export function validateSpecModels(data: any): ISpecModels {
|
|
48
|
+
if (!data.hasOwnProperty('kernelspecs')) {
|
|
49
|
+
throw new Error('No kernelspecs found');
|
|
50
|
+
}
|
|
51
|
+
let keys = Object.keys(data.kernelspecs);
|
|
52
|
+
const kernelspecs: Record<string, ISpecModel> = Object.create(null);
|
|
53
|
+
let defaultSpec = data.default;
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < keys.length; i++) {
|
|
56
|
+
const ks = data.kernelspecs[keys[i]];
|
|
57
|
+
try {
|
|
58
|
+
kernelspecs[keys[i]] = validateSpecModel(ks);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
// Remove the errant kernel spec.
|
|
61
|
+
console.warn(`Removing errant kernel spec: ${keys[i]}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
keys = Object.keys(kernelspecs);
|
|
65
|
+
if (!keys.length) {
|
|
66
|
+
throw new Error('No valid kernelspecs found');
|
|
67
|
+
}
|
|
68
|
+
if (
|
|
69
|
+
!defaultSpec ||
|
|
70
|
+
typeof defaultSpec !== 'string' ||
|
|
71
|
+
!(defaultSpec in kernelspecs)
|
|
72
|
+
) {
|
|
73
|
+
defaultSpec = keys[0];
|
|
74
|
+
console.warn(`Default kernel not found, using '${keys[0]}'`);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
default: defaultSpec,
|
|
78
|
+
kernelspecs,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { inject, singleton } from '@difizen/mana-app';
|
|
2
|
+
import { prop } from '@difizen/mana-app';
|
|
3
|
+
|
|
4
|
+
import type { IContentsModel } from './contents/index.js';
|
|
5
|
+
import { LibroKernelManager } from './kernel/libro-kernel-manager.js';
|
|
6
|
+
import type { IKernelConnection } from './kernel/libro-kernel-protocol.js';
|
|
7
|
+
import { LibroSessionManager } from './session/libro-session-manager.js';
|
|
8
|
+
|
|
9
|
+
@singleton()
|
|
10
|
+
export class LibroKernelConnectionManager {
|
|
11
|
+
protected sessionManager: LibroSessionManager;
|
|
12
|
+
protected kernelManager: LibroKernelManager;
|
|
13
|
+
|
|
14
|
+
@prop()
|
|
15
|
+
private kernelConnectionMap: Map<string, IKernelConnection>;
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
@inject(LibroSessionManager) sessionManager: LibroSessionManager,
|
|
19
|
+
@inject(LibroKernelManager) kernelManager: LibroKernelManager,
|
|
20
|
+
) {
|
|
21
|
+
this.sessionManager = sessionManager;
|
|
22
|
+
this.kernelManager = kernelManager;
|
|
23
|
+
this.kernelConnectionMap = new Map<string, IKernelConnection>();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async startNew(fileInfo: IContentsModel): Promise<IKernelConnection | undefined> {
|
|
27
|
+
const connection = await this.sessionManager.startNew(fileInfo);
|
|
28
|
+
if (!connection) {
|
|
29
|
+
throw new Error('start new kernel connection failed');
|
|
30
|
+
}
|
|
31
|
+
this.kernelConnectionMap.set(fileInfo.name, connection);
|
|
32
|
+
return connection;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async changeKernel(
|
|
36
|
+
fileInfo: IContentsModel,
|
|
37
|
+
reuseKernelInfo: { id?: string; name: string },
|
|
38
|
+
) {
|
|
39
|
+
const connection = await this.sessionManager.changeKernel(
|
|
40
|
+
fileInfo,
|
|
41
|
+
reuseKernelInfo,
|
|
42
|
+
);
|
|
43
|
+
if (!connection) {
|
|
44
|
+
throw new Error('change kernel connection failed');
|
|
45
|
+
}
|
|
46
|
+
this.kernelConnectionMap.set(fileInfo.name, connection);
|
|
47
|
+
return connection;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async shutdownKC(fileInfo: IContentsModel) {
|
|
51
|
+
const fileName = fileInfo.name;
|
|
52
|
+
const kc = this.kernelConnectionMap.get(fileName);
|
|
53
|
+
|
|
54
|
+
if (!kc) {
|
|
55
|
+
throw new Error('interrupt connection failed');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await this.sessionManager.shutdownKC(fileInfo, kc);
|
|
59
|
+
this.kernelConnectionMap.delete(fileName);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getAllKernelConnections() {
|
|
63
|
+
return this.kernelConnectionMap;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getKernelConnection(fileInfo: IContentsModel) {
|
|
67
|
+
const connection = this.kernelConnectionMap.get(fileInfo.name);
|
|
68
|
+
if (connection && !connection.isDisposed) {
|
|
69
|
+
return connection;
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/module.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ManaModule } from '@difizen/mana-app';
|
|
2
|
+
|
|
3
|
+
import { BaseManager } from './basemanager.js';
|
|
4
|
+
import { LibroContentsModule } from './contents/contents-module.js';
|
|
5
|
+
import { LibroKernelModule } from './kernel/kernel-module.js';
|
|
6
|
+
import { LibroKernelSpecModule } from './kernelspec/index.js';
|
|
7
|
+
import { LibroKernelConnectionManager } from './libro-kernel-connection-manager.js';
|
|
8
|
+
import { LibroServerModule } from './server/index.js';
|
|
9
|
+
import { LibroSessionModule } from './session/session-module.js';
|
|
10
|
+
|
|
11
|
+
export const LibroKernelManageModule = ManaModule.create()
|
|
12
|
+
.dependOn(
|
|
13
|
+
LibroSessionModule,
|
|
14
|
+
LibroKernelModule,
|
|
15
|
+
LibroServerModule,
|
|
16
|
+
LibroKernelSpecModule,
|
|
17
|
+
LibroContentsModule,
|
|
18
|
+
)
|
|
19
|
+
.register(BaseManager, LibroKernelConnectionManager);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isObject, URL } from '@difizen/libro-common';
|
|
2
|
+
import { isWeb } from '@difizen/mana-app';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* page config data for the Jupyter application.
|
|
6
|
+
*/
|
|
7
|
+
let configData: Record<string, string> | null = null;
|
|
8
|
+
|
|
9
|
+
export class PageConfig {
|
|
10
|
+
static defaultWorkspace = 'default';
|
|
11
|
+
/**
|
|
12
|
+
* Get a url-encoded item from `body.data` and decode it
|
|
13
|
+
* We should never have any encoded URLs anywhere else in code
|
|
14
|
+
* until we are building an actual request.
|
|
15
|
+
*/
|
|
16
|
+
static getBodyData(key: string): string {
|
|
17
|
+
if (typeof document === 'undefined' || !document.body) {
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
20
|
+
const val = document.body.dataset[key];
|
|
21
|
+
if (typeof val === 'undefined') {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
return decodeURIComponent(val);
|
|
25
|
+
}
|
|
26
|
+
static getOption(name: string): string {
|
|
27
|
+
if (configData) {
|
|
28
|
+
return configData[name] || PageConfig.getBodyData(name);
|
|
29
|
+
}
|
|
30
|
+
configData = Object.create(null);
|
|
31
|
+
// Use script tag if available.
|
|
32
|
+
if (isWeb) {
|
|
33
|
+
const el = document.getElementById('jupyter-config-data');
|
|
34
|
+
if (el) {
|
|
35
|
+
configData = JSON.parse(el.textContent || '') as Record<string, string>;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!isObject(configData)) {
|
|
40
|
+
configData = Object.create(null);
|
|
41
|
+
} else {
|
|
42
|
+
for (const key in configData) {
|
|
43
|
+
// PageConfig expects strings
|
|
44
|
+
if (typeof configData[key] !== 'string') {
|
|
45
|
+
configData[key] = JSON.stringify(configData[key]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return configData![name] || PageConfig.getBodyData(name);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Set global configuration data for the Jupyter application.
|
|
54
|
+
*
|
|
55
|
+
* @param name - The name of the configuration option.
|
|
56
|
+
* @param value - The value to set the option to.
|
|
57
|
+
*
|
|
58
|
+
* @returns The last config value or an empty string if it doesn't exist.
|
|
59
|
+
*/
|
|
60
|
+
static setOption(name: string, value: string): string {
|
|
61
|
+
const last = PageConfig.getOption(name);
|
|
62
|
+
|
|
63
|
+
configData![name] = value;
|
|
64
|
+
return last;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the base url for a Jupyter application, or the base url of the page.
|
|
69
|
+
*/
|
|
70
|
+
static getBaseUrl(): string {
|
|
71
|
+
return URL.normalize(PageConfig.getOption('baseUrl') || '/');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get the base websocket url for a Jupyter application, or an empty string.
|
|
76
|
+
*/
|
|
77
|
+
static getWsUrl(baseUrl?: string): string {
|
|
78
|
+
let wsUrl = PageConfig.getOption('wsUrl');
|
|
79
|
+
if (!wsUrl) {
|
|
80
|
+
baseUrl = baseUrl ? URL.normalize(baseUrl) : PageConfig.getBaseUrl();
|
|
81
|
+
if (baseUrl.indexOf('http') !== 0) {
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
wsUrl = 'ws' + baseUrl.slice(4);
|
|
85
|
+
}
|
|
86
|
+
return URL.normalize(wsUrl);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get the authorization token for a Jupyter application.
|
|
91
|
+
*/
|
|
92
|
+
static getToken(): string {
|
|
93
|
+
return PageConfig.getOption('token') || PageConfig.getBodyData('jupyterApiToken');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get the Notebook version info [major, minor, patch].
|
|
98
|
+
*/
|
|
99
|
+
static getNotebookVersion(): [number, number, number] {
|
|
100
|
+
const notebookVersion = PageConfig.getOption('notebookVersion');
|
|
101
|
+
if (notebookVersion === '') {
|
|
102
|
+
return [0, 0, 0];
|
|
103
|
+
}
|
|
104
|
+
return JSON.parse(notebookVersion);
|
|
105
|
+
}
|
|
106
|
+
}
|
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { NotebookModel } from '@difizen/libro-core';
|
|
2
|
+
|
|
3
|
+
import type { IContentsModel } from './contents/index.js';
|
|
4
|
+
import type { IKernelConnection } from './kernel/index.js';
|
|
5
|
+
|
|
6
|
+
export const ExecutableNotebookModel = {
|
|
7
|
+
is: (arg: Record<any, any> | undefined): arg is ExecutableNotebookModel => {
|
|
8
|
+
return (
|
|
9
|
+
!!arg &&
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
'filePath' in arg &&
|
|
12
|
+
typeof (arg as any).filePath === 'string' &&
|
|
13
|
+
'currentFileContents' in arg &&
|
|
14
|
+
typeof (arg as any).currentFileContents === 'object'
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface ExecutableNotebookModel extends NotebookModel {
|
|
20
|
+
filePath: string;
|
|
21
|
+
currentFileContents: IContentsModel;
|
|
22
|
+
kernelConnection?: IKernelConnection;
|
|
23
|
+
kcReady: Promise<IKernelConnection>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A wrapped error for a fetch response.
|
|
3
|
+
*/
|
|
4
|
+
export class ResponseError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* The response associated with the error.
|
|
7
|
+
*/
|
|
8
|
+
response: Response;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The traceback associated with the error.
|
|
12
|
+
*/
|
|
13
|
+
traceback: string;
|
|
14
|
+
/**
|
|
15
|
+
* Create a new response error.
|
|
16
|
+
*/
|
|
17
|
+
constructor(
|
|
18
|
+
response: Response,
|
|
19
|
+
message = `The response is invalid: ${response.status} ${response.statusText}`,
|
|
20
|
+
traceback = '',
|
|
21
|
+
) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.response = response;
|
|
24
|
+
this.traceback = traceback;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A wrapped error for a network error.
|
|
30
|
+
*/
|
|
31
|
+
export class NetworkError extends TypeError {
|
|
32
|
+
/**
|
|
33
|
+
* Create a new network error.
|
|
34
|
+
*/
|
|
35
|
+
constructor(original: TypeError) {
|
|
36
|
+
super(original.message);
|
|
37
|
+
this.stack = original.stack;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a ResponseError from a response, handling the traceback and message
|
|
43
|
+
* as appropriate.
|
|
44
|
+
*
|
|
45
|
+
* @param response The response object.
|
|
46
|
+
*
|
|
47
|
+
* @returns A promise that resolves with a `ResponseError` object.
|
|
48
|
+
*/
|
|
49
|
+
export const createResponseError = async (response: Response) => {
|
|
50
|
+
try {
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
if (data.message) {
|
|
53
|
+
return new ResponseError(response, data.message);
|
|
54
|
+
}
|
|
55
|
+
return new ResponseError(response);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
console.warn(e);
|
|
58
|
+
return new ResponseError(response);
|
|
59
|
+
}
|
|
60
|
+
};
|