Skip to content
Snippets Groups Projects
Select Git revision
  • df9efd05e6dc8abd67def6c39ed2ae180521af9f
  • master default protected
  • rednatco-v2
  • base-pairs-ladder
  • rednatco
  • test
  • ntc-tube-uniform-color
  • ntc-tube-missing-atoms
  • restore-vertex-array-per-program
  • watlas2
  • dnatco_new
  • cleanup-old-nodejs
  • webmmb
  • fix_auth_seq_id
  • update_deps
  • ext_dev
  • ntc_balls
  • nci-2
  • plugin
  • bugfix-0.4.5
  • nci
  • v0.5.0-dev.1
  • v0.4.5
  • v0.4.4
  • v0.4.3
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • v0.3.3
  • v0.3.2
  • v0.3.1
  • v0.3.0
41 results

render-object.ts

Blame
  • api-web.ts 5.07 KiB
    /**
     * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
     *
     * @author David Sehnal <david.sehnal@gmail.com>
     */
    
    import * as fs from 'fs';
    import * as path from 'path';
    import * as express from 'express';
    import Config from '../config';
    import { ConsoleLogger } from 'mol-util/console-logger';
    import { resolveJob } from './query';
    import { JobManager } from './jobs';
    import { UUID } from 'mol-util';
    import { LandingPage } from './landing';
    
    function makePath(p: string) {
        return Config.appPrefix + '/' + p;
    }
    
    function wrapResponse(fn: string, res: express.Response) {
        const w = {
            doError(this: any, code = 404, message = 'Not Found.') {
                if (!this.headerWritten) {
                    res.status(code).send(message);
                    this.headerWritten = true;
                }
                this.end();
            },
            writeHeader(this: any, binary: boolean) {
                if (this.headerWritten) return;
                res.writeHead(200, {
                    'Content-Type': binary ? 'application/octet-stream' : 'text/plain; charset=utf-8',
                    'Access-Control-Allow-Origin': '*',
                    'Access-Control-Allow-Headers': 'X-Requested-With',
                    'Content-Disposition': `inline; filename="${fn}"`
                });
                this.headerWritten = true;
            },
            writeBinary(this: any, data: Uint8Array) {
                if (!this.headerWritten) this.writeHeader(true);
                return res.write(new Buffer(data.buffer));
            },
            writeString(this: any, data: string) {
                if (!this.headerWritten) this.writeHeader(false);
                return res.write(data);
            },
            end(this: any) {
                if (this.ended) return;
                res.end();
                this.ended = true;
            },
            ended: false,
            headerWritten: false
        };
    
        return w;
    }
    
    const responseMap = new Map<UUID, express.Response>();
    
    async function processNextJob() {
        if (!JobManager.hasNext()) return;
    
        const job = JobManager.getNext();
        const response = responseMap.get(job.id)!;
        responseMap.delete(job.id);
    
        const filenameBase = `${job.entryId}_${job.queryDefinition.name.replace(/\s/g, '_')}`
        const writer = wrapResponse(job.responseFormat.isBinary ? `${filenameBase}.bcif` : `${filenameBase}.cif`, response);
    
        try {
            const encoder = await resolveJob(job);
            writer.writeHeader(job.responseFormat.isBinary);
            encoder.writeTo(writer);
        } catch (e) {
            ConsoleLogger.errorId(job.id, '' + e);
            writer.doError(404, '' + e);
        } finally {
            writer.end();
            ConsoleLogger.logId(job.id, 'Query', 'Finished.');
            setImmediate(processNextJob);
        }
    }
    
    // function mapQuery(app: express.Express, queryName: string, queryDefinition: QueryDefinition) {
    //     app.get(makePath(':entryId/' + queryName), (req, res) => {
    //         ConsoleLogger.log('Server', `Query '${req.params.entryId}/${queryName}'...`);
    
    //         if (JobManager.size >= Config.maxQueueLength) {
    //             res.status(503).send('Too many queries, please try again later.');
    //             res.end();
    //             return;
    //         }
    
    //         const jobId = JobManager.add('pdb', req.params.entryId, queryName, req.query);
    //         responseMap.set(jobId, res);
    //         if (JobManager.size === 1) processNextJob();
    //     });
    // }
    
    export function initWebApi(app: express.Express) {
        app.get(makePath('static/:format/:id'), async (req, res) => {
            const binary = req.params.format === 'bcif';
            const id = req.params.id;
            const fn = Config.mapFile(binary ? 'pdb-bcif' : 'pdb-cif', id);
            if (!fn || !fs.existsSync(fn)) {
                res.status(404);
                res.end();
                return;
            }
            fs.readFile(fn, (err, data) => {
                if (err) {
                    res.status(404);
                    res.end();
                    return;
                }
    
                const f = path.parse(fn);
                res.writeHead(200, {
                    'Content-Type': binary ? 'application/octet-stream' : 'text/plain; charset=utf-8',
                    'Access-Control-Allow-Origin': '*',
                    'Access-Control-Allow-Headers': 'X-Requested-With',
                    'Content-Disposition': `inline; filename="${f.name}${f.ext}"`
                });
                res.write(data);
                res.end();
            });
        })
    
        app.get(makePath('api/v1'), (req, res) => {
            const query = /\?(.*)$/.exec(req.url)![1];
            const args = JSON.parse(decodeURIComponent(query));
            const name = args.name;
            const entryId = args.id;
            const queryParams = args.params || { };
            const jobId = JobManager.add({
                sourceId: 'pdb',
                entryId,
                queryName: name,
                queryParams,
                options: { modelNums: args.modelNums, binary: args.binary }
            });
            responseMap.set(jobId, res);
            if (JobManager.size === 1) processNextJob();
        });
    
        app.get('*', (req, res) => {
            res.send(LandingPage);
        });
    
        // for (const q of QueryList) {
        //     mapQuery(app, q.name, q.definition);
        // }
    }