UNPKG

@fails-components/jupyter-filesystem-extension

Version:

A collection of extensions, that redirect's filesystems access to fails and let fails puppeteer Jupyter lite.

209 lines (208 loc) 7.3 kB
import { ServerConnection } from '@jupyterlab/services'; import { Signal } from '@lumino/signaling'; // portions used from Jupyterlab: /* ----------------------------------------------------------------------------- | Copyright (c) Jupyter Development Team. | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ // This code contains portions from or is inspired by Jupyter lab and lite // especially the Drive implementation const jsonMime = 'application/json'; class FailsDrive { constructor(options) { var _a; this._fileContent = JSON.stringify(FailsDrive.EMPTY_NB); this._isDisposed = false; this._fileChanged = new Signal(this); this._fileName = 'unloaded.ipynb'; this._serverSettings = (_a = options.serverSettings) !== null && _a !== void 0 ? _a : ServerConnection.makeSettings(); } dispose() { if (this.isDisposed) { return; } this._isDisposed = true; Signal.clearData(this); } get isDisposed() { return this._isDisposed; } get name() { return 'JupyterFailsSingleFileDrive'; } get serverSettings() { return this._serverSettings; } get fileChanged() { return this._fileChanged; } async getDownloadUrl(path) { throw new Error('Method not implemented.'); } async onMessage(event) { // todo handle events switch (event.task) { case 'loadFile': { const loadevent = event; this._fileContent = JSON.stringify(loadevent.fileData || FailsDrive.EMPTY_NB); this._fileName = loadevent.fileName; this._fileChanged.emit({ type: 'save', oldValue: null, newValue: { name: this._fileName, path: this._fileName, last_modified: new Date(0).toISOString(), created: new Date(0).toISOString(), format: 'json', mimetype: jsonMime, content: JSON.parse(this._fileContent), size: 0, writable: true, type: 'notebook' } }); } break; case 'savedFile': { const savedevent = event; if (this._fileName !== savedevent.fileName) { return { error: 'Filename not found' }; } return { fileData: JSON.parse(this._fileContent) }; } break; } } async get(path, options) { // remove leading slash path = decodeURIComponent(path.replace(/^\//, '')); const serverFile = { name: this._fileName, path: this._fileName, last_modified: new Date(0).toISOString(), created: new Date(0).toISOString(), format: 'json', mimetype: jsonMime, content: JSON.parse(this._fileContent), size: 0, writable: true, type: 'notebook' }; if (path === '') { // the local directory, return the info about the proxy notebook return { name: '', path, last_modified: new Date(0).toISOString(), created: new Date(0).toISOString(), format: 'json', mimetype: jsonMime, content: [serverFile], size: 0, writable: true, type: 'directory' }; } if (path === this._fileName) { return serverFile; } throw Error(`Could not find content with path ${path}`); } async save(path, options = {}) { path = decodeURIComponent(path); if (path !== this._fileName) { // we only allow the proxy object throw Error(`File ${path} is not the proxy file`); } const chunk = options.chunk; const chunked = chunk ? chunk > 1 || chunk === -1 : false; let item = await this.get(path, { content: chunked }); if (!item) { throw Error(`Could not find file with path ${path}`); } const modified = new Date().toISOString(); // override with the new values item = { ...item, ...options, last_modified: modified }; if (options.content && options.format === 'base64') { const lastChunk = chunk ? chunk === -1 : true; const modified = new Date().toISOString(); // override with the new values item = { ...item, ...options, last_modified: modified }; const originalContent = item.content; const escaped = decodeURIComponent(escape(atob(options.content))); const newcontent = chunked ? originalContent + escaped : escaped; item = { ...item, content: lastChunk ? JSON.parse(newcontent) : newcontent, format: 'json', type: 'notebook', size: newcontent.length }; this._fileContent = JSON.stringify(newcontent); // no parsing this._fileChanged.emit({ type: 'save', oldValue: null, newValue: item }); return item; } this._fileContent = JSON.stringify(item.content); // no parsing this._fileChanged.emit({ type: 'save', oldValue: null, newValue: item }); return item; } // For fails creating a new file is not allowed, so no need to implment it async newUntitled(options) { throw new Error('NewUntitled not implemented'); } async rename(oldLocalPath, newLocalPath) { throw new Error('rename not implemented'); } async delete(path) { throw new Error('delete not implemented'); } async copy(path, toDir) { throw new Error('copy not implemented'); } async createCheckpoint(path) { throw new Error('createCheckpoint not (yet?) implemented'); } async listCheckpoints(path) { // throw new Error('listCheckpoints not (yet?) implemented'); return [{ id: 'fakeCheckpoint', last_modified: new Date().toISOString() }]; } async restoreCheckpoint(path, checkpointID) { throw new Error('restoreCheckpoint not (yet?) implemented'); } async deleteCheckpoint(path, checkpointID) { throw new Error('deleteCheckpoint not (yet?) implemented'); } } FailsDrive.EMPTY_NB = { metadata: { orig_nbformat: 4 }, nbformat_minor: 5, nbformat: 4, cells: [] }; export { FailsDrive };