import path from 'path' import AWS from 'aws-sdk' import { PassThrough } from 'stream' const { spawn } = require('child_process') const encodeS3URI = require('node-s3-url-encode') const bucketName = 'sn-capture' const bucketRegion = 'us-east-1' const contentType = 'image/png' const bucketUrl = 'https://sn-capture.s3.amazonaws.com/' const s3PathPrefix = process.env.NODE_ENV === 'development' ? 'dev/' : '' let capturing = false AWS.config.update({ region: bucketRegion }) export default async function handler (req, res) { return new Promise(resolve => { const joinedPath = path.join(...(req.query.path || [])) const searchQ = req.query.q ? `?q=${req.query.q}` : '' const s3PathPUT = s3PathPrefix + (joinedPath === '.' ? '_' : joinedPath) + searchQ const s3PathGET = s3PathPrefix + (joinedPath === '.' ? '_' : joinedPath) + encodeS3URI(searchQ) const url = process.env.PUBLIC_URL + '/' + joinedPath + searchQ const aws = new AWS.S3({ apiVersion: '2006-03-01' }) // check to see if we have a recent version of the object aws.headObject({ Bucket: bucketName, Key: s3PathPUT, IfModifiedSince: new Date(new Date().getTime() - 15 * 60000) }).promise().then(() => { // this path is cached so return it res.writeHead(302, { Location: bucketUrl + s3PathGET }).end() resolve() }).catch(() => { // we don't have it cached, so capture it and cache it if (capturing) { return res.writeHead(503, { 'Retry-After': 1 }).end() } capturing = true const pass = new PassThrough() aws.upload({ Bucket: bucketName, Key: s3PathPUT, ACL: 'public-read', Body: pass, ContentType: contentType }).promise().catch(console.log) res.setHeader('Content-Type', contentType) const capture = spawn( 'node', ['./spawn/capture.js', url], { maxBuffer: 1024 * 1024 * 5 }) capture.on('close', code => { if (code !== 0) { res.status(500).end() } else { res.status(200).end() } pass.end() capture.removeAllListeners() capturing = false resolve() }) capture.on('error', err => console.log('error', err)) capture.stderr.on('data', data => console.log('error stderr', data.toString())) capture.stdout.on('data', data => { res.write(data) pass.write(data) }) }) }) }