import * as os_path from "path" ; import { delay } from "awaiting" ; import { Router } from "express" ; import { exists } from "./async-utils-node" ; import { get_blob_store , BlobStore } from "./jupyter-blobs-sqlite" ; import { get_kernel_data } from "./kernel-data" ; import { startswith } from "@cocalc/util/misc" ; import Logger from "@cocalc/backend/logger" ; const winston = Logger ( "jupyter-http-server" ) ; const BASE = "/.smc/jupyter/" ; function get_kernel ( kernel_data , name ) { for ( const k of kernel_data ) { if ( k . name == name ) return k ; } return null ; } function jupyter_kernel_info_handler ( router ) { router . get ( BASE + "kernelspecs/*" , async function ( req , res ) : Promise < void > { try { const kernel_data = await get_kernel_data ( ) ; let path = req . path . slice ( ( BASE + "kernelspecs/" ) . length ) . trim ( ) ; if ( path . length === 0 ) { res . json ( kernel_data ) ; return ; } const segments = path . split ( "/" ) ; const name = segments [ 0 ] ; const kernel = get_kernel ( kernel_data , name ) ; if ( kernel == null ) { const msg = `no such kernel '${ name }'` ; throw Error ( msg ) ; } const resource_dir = kernel . resource_dir ; path = os_path . join ( resource_dir , segments . slice ( 1 ) . join ( "/" ) ) ; path = os_path . resolve ( path ) ; if ( ! startswith ( path , resource_dir ) ) { throw Error ( `suspicious path '${ path }'` ) ; } if ( await exists ( path ) ) { res . sendFile ( path ) ; } else { throw Error ( `no such path '${ path }'` ) ; } } catch ( err ) { res . send ( err ) ; return ; } } ) ; } export default async function init ( ) { while ( true ) { const blob_store = get_blob_store ( ) ; if ( blob_store != null ) { const router = blob_store . express_router ( BASE ) ; jupyter_kernel_info_handler ( router ) ; return router ; } else { winston . warn ( "delaying setup, because BlobStore not available yet" ) ; await delay ( 5000 ) ; } } }