Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 1x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 3x 1x 1x 2x 2x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 2x 2x 4x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 1x 1x 1x 1x 1x | // @ts-check // SPDX-License-Identifier: Zlib // SPDX-FileCopyrightText: 2024 CERN (home.cern) // SPDX-FileContributor: Author: Sylvain Fargier <sylvain.fargier@cern.ch> import axios from "axios"; import d from "debug"; const debug = d("cam:sshot"); /** * @typedef {import('express').IRouter} expressIRouter * @typedef {import('express-ws').WithWebsocketMethod & expressIRouter} IRouter * * @typedef {import('express').Request} Request * @typedef {import('express').Response} Response */ class SShotService { /** * @param {CamExpress.InternalGroupConfig} groups * @param {CamExpress.Credentials} credentials */ constructor(groups, credentials) { this.groups = groups; this.creds = credentials; } /** @param {IRouter} router */ register(router) { /** * @swagger * /cameras/{group}/{camera}/screenshot: * get: * tags: ['screenshot'] * summary: get a camera screenshot * description: | * Take a screenshot of the current video stream, highest quality possible * parameters: * - in: path * name: group * schema: * type: string * description: name of the group defined in the config * required: true * - in: path * name: camera * schema: * type: string * description: name of the camera defined in the config * required: true * produces: * - image/jpeg * responses: * 200: * description: video stream screenshot * 500: * description: error message */ router.get("/cameras/:group/:camera/screenshot", this.getSShot.bind(this)); } /** * @param {Request} req * @param {Response} res */ getSShot(req, res) { const camera = this.getCamera(req); if (!camera) { res.status(404).send("no such camera"); } else if (!camera.screenshot) { res.status(500).send("no screenshot for camera"); } else { debug("taking screenshot for %s", camera.name); const opts = { timeout: 10000, responseType: "stream" }; const auth = this.creds[camera.name]; if (auth) { opts.auth = { username: auth.user, password: auth.password }; } axios.get(camera.screenshot, opts) .then( (response) => response.data.pipe(res), (err) => { const msg = err?.response?.statusText || err?.message; debug("screenshot error: %s", msg ?? "?"); res.status(err?.response?.status ?? 500) .send(msg ? ("internal error: " + msg) : "internal error"); }); } } /** * @param {Request} req * @return {CamExpress.CameraConfig&{id:string|number}|undefined} */ getCamera(req) { const group = req?.params?.group; const camera = req?.params?.camera; return this.groups?.[group]?.cameras?.[camera]; } release() {} } export default SShotService; |