import { Notebook , stringifyNotebook } from "@nteract/commutable" ; import { FileType , IContent , IContentProvider , IGetParams , ServerConfig } from "@nteract/types" ; import * as fs from "fs" ; import { readFileObservable , statObservable , writeFileObservable } from "fs-observable" ; import * as path from "path" ; import { Observable , of } from "rxjs" ; import { AjaxResponse } from "rxjs/ajax" ; import { catchError , map , mergeMap } from "rxjs/operators" ; export class LocalContentProvider implements IContentProvider { public remove ( serverConfig , path ) { throw new Error ( "Not implemented" ) ; } public get ( serverConfig , filePath , params ) { return statObservable ( filePath ) . pipe ( mergeMap ( ( stat ) => { if ( ! stat . isFile ( ) ) { return of ( this . createErrorAjaxResponse ( 400 , new Error ( "Attempted to open something which is not a file" ) ) ) ; } if ( params . content === 0 ) { const notebook = this . createNotebookModel ( filePath , stat ) ; return of ( this . createSuccessAjaxResponse ( notebook ) ) ; } return readFileObservable ( filePath ) . pipe ( map ( ( content ) => { const notebook = this . createNotebookModel ( filePath , stat , content . toString ( ) ) ; return this . createSuccessAjaxResponse ( notebook ) ; } ) , catchError ( error => of ( this . createErrorAjaxResponse ( 404 , error ) ) ) ) ; } ) , catchError ( error => of ( this . createErrorAjaxResponse ( 404 , error ) ) ) ) ; } public update < FT extends FileType > ( serverConfig , path , model ) { throw new Error ( "Not implemented" ) ; } public create < FT extends FileType > ( serverConfig , path , model ) { throw new Error ( "Not implemented" ) ; } public save < FT extends FileType > ( serverConfig , filePath , model ) { const notebook = model . content as Notebook ; if ( ! notebook || model . type !== "notebook" ) { return of ( this . createErrorAjaxResponse ( 400 , new Error ( "No notebook found to save" ) ) ) ; } const serializedNotebook = stringifyNotebook ( notebook ) ; return writeFileObservable ( filePath , serializedNotebook ) . pipe ( mergeMap ( ( ) => { return statObservable ( filePath ) . pipe ( map ( ( stat ) => { const notebook = this . createNotebookModel ( filePath , stat , serializedNotebook ) ; return this . createSuccessAjaxResponse ( notebook ) ; } ) , catchError ( error => of ( this . createErrorAjaxResponse ( 404 , error ) ) ) ) ; } ) , catchError ( error => of ( this . createErrorAjaxResponse ( 500 , error ) ) ) ) ; } public listCheckpoints ( serverConfig , path ) { throw new Error ( "Not implemented" ) ; } public createCheckpoint ( serverConfig , path ) { throw new Error ( "Not implemented" ) ; } public deleteCheckpoint ( serverConfig , path , checkpointID ) { throw new Error ( "Not implemented" ) ; } public restoreFromCheckpoint ( serverConfig , path , checkpointID ) { throw new Error ( "Not implemented" ) ; } private createNotebookModel ( filePath , stat , content ? ) { const parsedFilePath = path . parse ( filePath ) ; const name = parsedFilePath . base ; const writable = Boolean ( fs . constants . W_OK & stat . mode ) ; const created = stat . birthtime . toString ( ) ; const last_modified = stat . mtime . toString ( ) ; return { name , path : filePath , type : "notebook" , writable , created , last_modified , mimetype : "application/x-ipynb+json" , content : content ? JSON . parse ( content ) : null , format : "json" } ; } private createSuccessAjaxResponse ( notebook ) { return { originalEvent : new Event ( "no-op" ) , xhr : new XMLHttpRequest ( ) , request : { } , status : 200 , response : notebook , responseText : JSON . stringify ( notebook ) , responseType : "json" } ; } private createErrorAjaxResponse ( status , error ) { return { originalEvent : new Event ( "no-op" ) , xhr : new XMLHttpRequest ( ) , request : { } , status , response : error , responseText : JSON . stringify ( error ) , responseType : "json" } ; } }