import * as fs from 'fs' import * as mime from 'mime-types' import * as path from 'path' import {FilesystemOperationNotSupported, ReadOnlyFilesystem} from './ReadOnlyFilesystem' import {UniversalPath} from '../path' import {Awaitable, Maybe} from '../types' import {Readable} from 'stream' import {FileMetadata, Stat} from './Filesystem' import {Collection} from '../../collection/Collection' import {RequestInfo, RequestInit, Response} from 'node-fetch' import {unsafeESMImport} from '../../unsafe' const fetch = (url: RequestInfo, init?: RequestInit): Promise => unsafeESMImport('node-fetch').then(({default: nodeFetch}) => nodeFetch(url, init)) /** * A filesystem implementation that reads files over HTTPS. */ export class HTTPFilesystem extends ReadOnlyFilesystem { getPrefix(): string { return 'https://' } async getStoreFileAsTemp(args: { storePath: string }): Promise { const temp = this.tempName() const write = fs.createWriteStream(temp) const read = await this.getStoreFileAsStream(args) return new Promise((res, rej) => { write.on('finish', () => { res(new UniversalPath(temp)) }) write.on('error', rej) read.on('error', rej) read.pipe(write) }) } async getStoreFileAsStream(args: { storePath: string }): Promise { if ( args.storePath.startsWith('/') ) { args.storePath = args.storePath.slice(1) } const result = await fetch(`${this.getPrefix()}${args.storePath}`) if ( result.body ) { return (new Readable()).wrap(result.body) } return Readable.from([]) } async stat(args: { storePath: string }): Promise { if ( args.storePath.startsWith('/') ) { args.storePath = args.storePath.slice(1) } let response: Maybe = undefined try { response = await fetch(`${this.getPrefix()}${args.storePath}`) } catch (e) {} // eslint-disable-line no-empty return { path: new UniversalPath(args.storePath, this), exists: Boolean(response?.ok), sizeInBytes: response?.size || 0, mimeType: mime.lookup(path.basename(args.storePath)) || undefined, tags: [], accessed: undefined, modified: undefined, created: undefined, isFile: true, isDirectory: false, } } getMetadata(storePath: string): Awaitable { const mimeType = mime.lookup(path.basename(storePath)) return { ...(mimeType ? { mimeType } : {}), } } list(): Awaitable> { throw new FilesystemOperationNotSupported(this, 'list') } }