diff --git a/node-sources/.gitignore b/node-sources/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/node-sources/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/node-sources/README.md b/node-sources/README.md new file mode 100644 index 00000000..2bf41323 --- /dev/null +++ b/node-sources/README.md @@ -0,0 +1,33 @@ +# interact with letterbox using nodejs + +A small set of modules to send UDP packets that consist of the contents of a node-canvas to the octopus server. + +## setup + +run `npm install` + +## run examples + +### render + +stuff on canvas and send contents to octopus + +- `node render.js []` + +### scan image + +load image stuff on canvas and send contents to octopus +preserves the image ratio and scans from top to bottom + +- `node scan-image.js []` + + +## convert protobuf schema + +There is a shell script to convert the latest .proto file to an es6 module used with all example scripts. +Calling this will output / overwrite [packet.js](./packet.js). + +``` +./convert-proto.js ../protobuf/schema.proto +``` + diff --git a/node-sources/convert-proto.js b/node-sources/convert-proto.js new file mode 100755 index 00000000..2543ae4e --- /dev/null +++ b/node-sources/convert-proto.js @@ -0,0 +1,28 @@ +#!/usr/bin/env node + +import { readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { argv } from 'node:process'; +import { parseSchema } from 'pbjs'; + +// convert .proto to es6 module + +console.log(argv) +const p = resolve(argv[2]) +console.log(p) + +if (!p.endsWith('.proto')) { + process.exit(1) +} + +const raw = readFileSync(p) +console.log(raw.toString()) +const replaced = raw.toString().replace(/( \[[^\]]+\])/g, '') +console.log(replaced) + +const f = parseSchema(Buffer.from(replaced)) +try { + writeFileSync('packet.js', f.toJavaScript({es6:true})) +} catch (e) { + console.error(e) +} diff --git a/node-sources/package-lock.json b/node-sources/package-lock.json new file mode 100644 index 00000000..e1f1f768 --- /dev/null +++ b/node-sources/package-lock.json @@ -0,0 +1,1089 @@ +{ + "name": "canvas-letterbox", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "canvas-letterbox", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "canvas": "^2.11.2", + "got": "^13.0.0", + "pbjs": "^0.0.14", + "protobufjs": "^7.2.3", + "skia-canvas": "^1.0.1" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@sindresorhus/is": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.4.1.tgz", + "integrity": "sha512-axlrvsHlHlFmKKMEg4VyvMzFr93JWJj4eIfXY1STVuO2fsImCa7ncaiG5gC8HKOX590AW5RtRsC41/B+OfrSqw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "node_modules/@types/node": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", + "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", + "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", + "dependencies": { + "@types/http-cache-semantics": "^4.0.1", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.2", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/canvas/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/canvas/node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/cargo-cp-artifact": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/cargo-cp-artifact/-/cargo-cp-artifact-0.1.8.tgz", + "integrity": "sha512-3j4DaoTrsCD1MRkTF2Soacii0Nx7UHCce0EwUf4fHnggwiE4fbmF2AbnfzayR36DF8KGadfh7M/Yfy625kgPlA==", + "bin": { + "cargo-cp-artifact": "bin/cargo-cp-artifact.js" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/commander": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.0.1.tgz", + "integrity": "sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/parenthesis": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz", + "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==" + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pbjs": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/pbjs/-/pbjs-0.0.14.tgz", + "integrity": "sha512-F4aA0ojrQ37kxFPOg4yRLP/vxb76rYQwMQigmVEljYlA7hZKmjaWjP6IkRn4nA0NdIj4Xxe4iqWrrIhJy+MwWQ==", + "dependencies": { + "commander": "4.0.1", + "protocol-buffers-schema": "3.1.0" + }, + "bin": { + "pbjs": "cli.js" + } + }, + "node_modules/protobufjs": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", + "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protocol-buffers-schema": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.1.0.tgz", + "integrity": "sha512-1g9zFjLFhGN1Dc5UVO8D2loVslp6sVxk5sJqgD66CuWUITh2gOaTLRN/pIakGFfB6e0nNF6hImrYFDurEsA1UQ==" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/skia-canvas": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/skia-canvas/-/skia-canvas-1.0.1.tgz", + "integrity": "sha512-/HtZlmib2BD3Fi6P4ZywSq7VquPl2A1Frc0pA+xD5hJSvSzN7FoOJpBWDpDd0e1ByzrVO6ZIjO98dNSQ2XqlKw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.9", + "cargo-cp-artifact": "^0.1", + "glob": "^8.0.3", + "path-browserify": "^1.0.1", + "simple-get": "^4.0.1", + "string-split-by": "^1.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-split-by": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz", + "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==", + "dependencies": { + "parenthesis": "^3.1.5" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/node-sources/package.json b/node-sources/package.json new file mode 100644 index 00000000..76ae68ab --- /dev/null +++ b/node-sources/package.json @@ -0,0 +1,20 @@ +{ + "name": "canvas-letterbox", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "canvas": "^2.11.2", + "got": "^13.0.0", + "pbjs": "^0.0.14", + "protobufjs": "^7.2.3", + "skia-canvas": "^1.0.1" + } +} diff --git a/node-sources/packet.js b/node-sources/packet.js new file mode 100644 index 00000000..a924a307 --- /dev/null +++ b/node-sources/packet.js @@ -0,0 +1,1341 @@ +export const encodeInputType = { + BUTTON_1: 0, + BUTTON_2: 1, + BUTTON_3: 2, + BUTTON_4: 3, + BUTTON_5: 4, + BUTTON_6: 5, + BUTTON_7: 6, + BUTTON_8: 7, + BUTTON_9: 8, + BUTTON_10: 9, + AXIS_X_1: 10, + AXIS_Y_1: 11, + AXIS_X_2: 12, + AXIS_Y_2: 13, +}; + +export const decodeInputType = { + 0: "BUTTON_1", + 1: "BUTTON_2", + 2: "BUTTON_3", + 3: "BUTTON_4", + 4: "BUTTON_5", + 5: "BUTTON_6", + 6: "BUTTON_7", + 7: "BUTTON_8", + 8: "BUTTON_9", + 9: "BUTTON_10", + 10: "AXIS_X_1", + 11: "AXIS_Y_1", + 12: "AXIS_X_2", + 13: "AXIS_Y_2", +}; + +export const encodeEasingMode = { + LINEAR: 0, + EASE_IN_QUAD: 1, + EASE_OUT_QUAD: 2, + EASE_IN_OUT_QUAD: 3, + EASE_IN_CUBIC: 4, + EASE_OUT_CUBIC: 5, + EASE_IN_OUT_CUBIC: 6, + EASE_IN_QUART: 7, + EASE_OUT_QUART: 8, + EASE_IN_OUT_QUART: 9, + EASE_IN_QUINT: 10, + EASE_OUT_QUINT: 11, + EASE_IN_OUT_QUINT: 12, + EASE_IN_EXPO: 13, + EASE_OUT_EXPO: 14, + EASE_IN_OUT_EXPO: 15, +}; + +export const decodeEasingMode = { + 0: "LINEAR", + 1: "EASE_IN_QUAD", + 2: "EASE_OUT_QUAD", + 3: "EASE_IN_OUT_QUAD", + 4: "EASE_IN_CUBIC", + 5: "EASE_OUT_CUBIC", + 6: "EASE_IN_OUT_CUBIC", + 7: "EASE_IN_QUART", + 8: "EASE_OUT_QUART", + 9: "EASE_IN_OUT_QUART", + 10: "EASE_IN_QUINT", + 11: "EASE_OUT_QUINT", + 12: "EASE_IN_OUT_QUINT", + 13: "EASE_IN_EXPO", + 14: "EASE_OUT_EXPO", + 15: "EASE_IN_OUT_EXPO", +}; + +export function encodePacket(message) { + let bb = popByteBuffer(); + _encodePacket(message, bb); + return toUint8Array(bb); +} + +function _encodePacket(message, bb) { + // optional Frame frame = 2; + let $frame = message.frame; + if ($frame !== undefined) { + writeVarint32(bb, 18); + let nested = popByteBuffer(); + _encodeFrame($frame, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional WFrame w_frame = 3; + let $w_frame = message.w_frame; + if ($w_frame !== undefined) { + writeVarint32(bb, 26); + let nested = popByteBuffer(); + _encodeWFrame($w_frame, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional RGBFrame rgb_frame = 4; + let $rgb_frame = message.rgb_frame; + if ($rgb_frame !== undefined) { + writeVarint32(bb, 34); + let nested = popByteBuffer(); + _encodeRGBFrame($rgb_frame, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional AudioFrame audio_frame = 5; + let $audio_frame = message.audio_frame; + if ($audio_frame !== undefined) { + writeVarint32(bb, 42); + let nested = popByteBuffer(); + _encodeAudioFrame($audio_frame, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional InputEvent input_event = 6; + let $input_event = message.input_event; + if ($input_event !== undefined) { + writeVarint32(bb, 50); + let nested = popByteBuffer(); + _encodeInputEvent($input_event, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional FirmwareConfig firmware_config = 1; + let $firmware_config = message.firmware_config; + if ($firmware_config !== undefined) { + writeVarint32(bb, 10); + let nested = popByteBuffer(); + _encodeFirmwareConfig($firmware_config, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional RGBFrame rgb_frame_part1 = 7; + let $rgb_frame_part1 = message.rgb_frame_part1; + if ($rgb_frame_part1 !== undefined) { + writeVarint32(bb, 58); + let nested = popByteBuffer(); + _encodeRGBFrame($rgb_frame_part1, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional RGBFrame rgb_frame_part2 = 8; + let $rgb_frame_part2 = message.rgb_frame_part2; + if ($rgb_frame_part2 !== undefined) { + writeVarint32(bb, 66); + let nested = popByteBuffer(); + _encodeRGBFrame($rgb_frame_part2, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } +} + +export function decodePacket(binary) { + return _decodePacket(wrapByteBuffer(binary)); +} + +function _decodePacket(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional Frame frame = 2; + case 2: { + let limit = pushTemporaryLength(bb); + message.frame = _decodeFrame(bb); + bb.limit = limit; + break; + } + + // optional WFrame w_frame = 3; + case 3: { + let limit = pushTemporaryLength(bb); + message.w_frame = _decodeWFrame(bb); + bb.limit = limit; + break; + } + + // optional RGBFrame rgb_frame = 4; + case 4: { + let limit = pushTemporaryLength(bb); + message.rgb_frame = _decodeRGBFrame(bb); + bb.limit = limit; + break; + } + + // optional AudioFrame audio_frame = 5; + case 5: { + let limit = pushTemporaryLength(bb); + message.audio_frame = _decodeAudioFrame(bb); + bb.limit = limit; + break; + } + + // optional InputEvent input_event = 6; + case 6: { + let limit = pushTemporaryLength(bb); + message.input_event = _decodeInputEvent(bb); + bb.limit = limit; + break; + } + + // optional FirmwareConfig firmware_config = 1; + case 1: { + let limit = pushTemporaryLength(bb); + message.firmware_config = _decodeFirmwareConfig(bb); + bb.limit = limit; + break; + } + + // optional RGBFrame rgb_frame_part1 = 7; + case 7: { + let limit = pushTemporaryLength(bb); + message.rgb_frame_part1 = _decodeRGBFrame(bb); + bb.limit = limit; + break; + } + + // optional RGBFrame rgb_frame_part2 = 8; + case 8: { + let limit = pushTemporaryLength(bb); + message.rgb_frame_part2 = _decodeRGBFrame(bb); + bb.limit = limit; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeFrame(message) { + let bb = popByteBuffer(); + _encodeFrame(message, bb); + return toUint8Array(bb); +} + +function _encodeFrame(message, bb) { + // optional bytes data = 1; + let $data = message.data; + if ($data !== undefined) { + writeVarint32(bb, 10); + writeVarint32(bb, $data.length), writeBytes(bb, $data); + } + + // optional bytes palette = 2; + let $palette = message.palette; + if ($palette !== undefined) { + writeVarint32(bb, 18); + writeVarint32(bb, $palette.length), writeBytes(bb, $palette); + } + + // optional uint32 easing_interval = 3; + let $easing_interval = message.easing_interval; + if ($easing_interval !== undefined) { + writeVarint32(bb, 24); + writeVarint32(bb, $easing_interval); + } +} + +export function decodeFrame(binary) { + return _decodeFrame(wrapByteBuffer(binary)); +} + +function _decodeFrame(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional bytes data = 1; + case 1: { + message.data = readBytes(bb, readVarint32(bb)); + break; + } + + // optional bytes palette = 2; + case 2: { + message.palette = readBytes(bb, readVarint32(bb)); + break; + } + + // optional uint32 easing_interval = 3; + case 3: { + message.easing_interval = readVarint32(bb) >>> 0; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeWFrame(message) { + let bb = popByteBuffer(); + _encodeWFrame(message, bb); + return toUint8Array(bb); +} + +function _encodeWFrame(message, bb) { + // optional bytes data = 1; + let $data = message.data; + if ($data !== undefined) { + writeVarint32(bb, 10); + writeVarint32(bb, $data.length), writeBytes(bb, $data); + } + + // optional bytes palette = 2; + let $palette = message.palette; + if ($palette !== undefined) { + writeVarint32(bb, 18); + writeVarint32(bb, $palette.length), writeBytes(bb, $palette); + } + + // optional uint32 easing_interval = 3; + let $easing_interval = message.easing_interval; + if ($easing_interval !== undefined) { + writeVarint32(bb, 24); + writeVarint32(bb, $easing_interval); + } +} + +export function decodeWFrame(binary) { + return _decodeWFrame(wrapByteBuffer(binary)); +} + +function _decodeWFrame(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional bytes data = 1; + case 1: { + message.data = readBytes(bb, readVarint32(bb)); + break; + } + + // optional bytes palette = 2; + case 2: { + message.palette = readBytes(bb, readVarint32(bb)); + break; + } + + // optional uint32 easing_interval = 3; + case 3: { + message.easing_interval = readVarint32(bb) >>> 0; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeRGBFrame(message) { + let bb = popByteBuffer(); + _encodeRGBFrame(message, bb); + return toUint8Array(bb); +} + +function _encodeRGBFrame(message, bb) { + // optional bytes data = 1; + let $data = message.data; + if ($data !== undefined) { + writeVarint32(bb, 10); + writeVarint32(bb, $data.length), writeBytes(bb, $data); + } + + // optional uint32 easing_interval = 2; + let $easing_interval = message.easing_interval; + if ($easing_interval !== undefined) { + writeVarint32(bb, 16); + writeVarint32(bb, $easing_interval); + } +} + +export function decodeRGBFrame(binary) { + return _decodeRGBFrame(wrapByteBuffer(binary)); +} + +function _decodeRGBFrame(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional bytes data = 1; + case 1: { + message.data = readBytes(bb, readVarint32(bb)); + break; + } + + // optional uint32 easing_interval = 2; + case 2: { + message.easing_interval = readVarint32(bb) >>> 0; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeAudioFrame(message) { + let bb = popByteBuffer(); + _encodeAudioFrame(message, bb); + return toUint8Array(bb); +} + +function _encodeAudioFrame(message, bb) { + // optional string uri = 1; + let $uri = message.uri; + if ($uri !== undefined) { + writeVarint32(bb, 10); + writeString(bb, $uri); + } + + // optional uint32 channel = 2; + let $channel = message.channel; + if ($channel !== undefined) { + writeVarint32(bb, 16); + writeVarint32(bb, $channel); + } +} + +export function decodeAudioFrame(binary) { + return _decodeAudioFrame(wrapByteBuffer(binary)); +} + +function _decodeAudioFrame(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional string uri = 1; + case 1: { + message.uri = readString(bb, readVarint32(bb)); + break; + } + + // optional uint32 channel = 2; + case 2: { + message.channel = readVarint32(bb) >>> 0; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeInputEvent(message) { + let bb = popByteBuffer(); + _encodeInputEvent(message, bb); + return toUint8Array(bb); +} + +function _encodeInputEvent(message, bb) { + // optional InputType type = 1; + let $type = message.type; + if ($type !== undefined) { + writeVarint32(bb, 8); + writeVarint32(bb, encodeInputType[$type]); + } + + // optional int32 value = 3; + let $value = message.value; + if ($value !== undefined) { + writeVarint32(bb, 24); + writeVarint64(bb, intToLong($value)); + } +} + +export function decodeInputEvent(binary) { + return _decodeInputEvent(wrapByteBuffer(binary)); +} + +function _decodeInputEvent(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional InputType type = 1; + case 1: { + message.type = decodeInputType[readVarint32(bb)]; + break; + } + + // optional int32 value = 3; + case 3: { + message.value = readVarint32(bb); + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeFirmwareConfig(message) { + let bb = popByteBuffer(); + _encodeFirmwareConfig(message, bb); + return toUint8Array(bb); +} + +function _encodeFirmwareConfig(message, bb) { + // optional uint32 luminance = 1; + let $luminance = message.luminance; + if ($luminance !== undefined) { + writeVarint32(bb, 8); + writeVarint32(bb, $luminance); + } + + // optional EasingMode easing_mode = 2; + let $easing_mode = message.easing_mode; + if ($easing_mode !== undefined) { + writeVarint32(bb, 16); + writeVarint32(bb, encodeEasingMode[$easing_mode]); + } + + // optional bool show_test_frame = 3; + let $show_test_frame = message.show_test_frame; + if ($show_test_frame !== undefined) { + writeVarint32(bb, 24); + writeByte(bb, $show_test_frame ? 1 : 0); + } + + // optional uint32 config_phash = 4; + let $config_phash = message.config_phash; + if ($config_phash !== undefined) { + writeVarint32(bb, 32); + writeVarint32(bb, $config_phash); + } + + // optional bool enable_calibration = 5; + let $enable_calibration = message.enable_calibration; + if ($enable_calibration !== undefined) { + writeVarint32(bb, 40); + writeByte(bb, $enable_calibration ? 1 : 0); + } +} + +export function decodeFirmwareConfig(binary) { + return _decodeFirmwareConfig(wrapByteBuffer(binary)); +} + +function _decodeFirmwareConfig(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional uint32 luminance = 1; + case 1: { + message.luminance = readVarint32(bb) >>> 0; + break; + } + + // optional EasingMode easing_mode = 2; + case 2: { + message.easing_mode = decodeEasingMode[readVarint32(bb)]; + break; + } + + // optional bool show_test_frame = 3; + case 3: { + message.show_test_frame = !!readByte(bb); + break; + } + + // optional uint32 config_phash = 4; + case 4: { + message.config_phash = readVarint32(bb) >>> 0; + break; + } + + // optional bool enable_calibration = 5; + case 5: { + message.enable_calibration = !!readByte(bb); + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeFirmwarePacket(message) { + let bb = popByteBuffer(); + _encodeFirmwarePacket(message, bb); + return toUint8Array(bb); +} + +function _encodeFirmwarePacket(message, bb) { + // optional FirmwareInfo firmware_info = 1; + let $firmware_info = message.firmware_info; + if ($firmware_info !== undefined) { + writeVarint32(bb, 10); + let nested = popByteBuffer(); + _encodeFirmwareInfo($firmware_info, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } + + // optional RemoteLog remote_log = 2; + let $remote_log = message.remote_log; + if ($remote_log !== undefined) { + writeVarint32(bb, 18); + let nested = popByteBuffer(); + _encodeRemoteLog($remote_log, nested); + writeVarint32(bb, nested.limit); + writeByteBuffer(bb, nested); + pushByteBuffer(nested); + } +} + +export function decodeFirmwarePacket(binary) { + return _decodeFirmwarePacket(wrapByteBuffer(binary)); +} + +function _decodeFirmwarePacket(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional FirmwareInfo firmware_info = 1; + case 1: { + let limit = pushTemporaryLength(bb); + message.firmware_info = _decodeFirmwareInfo(bb); + bb.limit = limit; + break; + } + + // optional RemoteLog remote_log = 2; + case 2: { + let limit = pushTemporaryLength(bb); + message.remote_log = _decodeRemoteLog(bb); + bb.limit = limit; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeFirmwareInfo(message) { + let bb = popByteBuffer(); + _encodeFirmwareInfo(message, bb); + return toUint8Array(bb); +} + +function _encodeFirmwareInfo(message, bb) { + // optional string hostname = 1; + let $hostname = message.hostname; + if ($hostname !== undefined) { + writeVarint32(bb, 10); + writeString(bb, $hostname); + } + + // optional string build_time = 2; + let $build_time = message.build_time; + if ($build_time !== undefined) { + writeVarint32(bb, 18); + writeString(bb, $build_time); + } + + // optional uint32 panel_index = 3; + let $panel_index = message.panel_index; + if ($panel_index !== undefined) { + writeVarint32(bb, 24); + writeVarint32(bb, $panel_index); + } + + // optional uint32 fps = 4; + let $fps = message.fps; + if ($fps !== undefined) { + writeVarint32(bb, 32); + writeVarint32(bb, $fps); + } + + // optional uint32 config_phash = 5; + let $config_phash = message.config_phash; + if ($config_phash !== undefined) { + writeVarint32(bb, 40); + writeVarint32(bb, $config_phash); + } +} + +export function decodeFirmwareInfo(binary) { + return _decodeFirmwareInfo(wrapByteBuffer(binary)); +} + +function _decodeFirmwareInfo(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional string hostname = 1; + case 1: { + message.hostname = readString(bb, readVarint32(bb)); + break; + } + + // optional string build_time = 2; + case 2: { + message.build_time = readString(bb, readVarint32(bb)); + break; + } + + // optional uint32 panel_index = 3; + case 3: { + message.panel_index = readVarint32(bb) >>> 0; + break; + } + + // optional uint32 fps = 4; + case 4: { + message.fps = readVarint32(bb) >>> 0; + break; + } + + // optional uint32 config_phash = 5; + case 5: { + message.config_phash = readVarint32(bb) >>> 0; + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +export function encodeRemoteLog(message) { + let bb = popByteBuffer(); + _encodeRemoteLog(message, bb); + return toUint8Array(bb); +} + +function _encodeRemoteLog(message, bb) { + // optional string message = 1; + let $message = message.message; + if ($message !== undefined) { + writeVarint32(bb, 10); + writeString(bb, $message); + } +} + +export function decodeRemoteLog(binary) { + return _decodeRemoteLog(wrapByteBuffer(binary)); +} + +function _decodeRemoteLog(bb) { + let message = {}; + + end_of_message: while (!isAtEnd(bb)) { + let tag = readVarint32(bb); + + switch (tag >>> 3) { + case 0: + break end_of_message; + + // optional string message = 1; + case 1: { + message.message = readString(bb, readVarint32(bb)); + break; + } + + default: + skipUnknownField(bb, tag & 7); + } + } + + return message; +} + +function pushTemporaryLength(bb) { + let length = readVarint32(bb); + let limit = bb.limit; + bb.limit = bb.offset + length; + return limit; +} + +function skipUnknownField(bb, type) { + switch (type) { + case 0: while (readByte(bb) & 0x80) { } break; + case 2: skip(bb, readVarint32(bb)); break; + case 5: skip(bb, 4); break; + case 1: skip(bb, 8); break; + default: throw new Error("Unimplemented type: " + type); + } +} + +function stringToLong(value) { + return { + low: value.charCodeAt(0) | (value.charCodeAt(1) << 16), + high: value.charCodeAt(2) | (value.charCodeAt(3) << 16), + unsigned: false, + }; +} + +function longToString(value) { + let low = value.low; + let high = value.high; + return String.fromCharCode( + low & 0xFFFF, + low >>> 16, + high & 0xFFFF, + high >>> 16); +} + +// The code below was modified from https://github.com/protobufjs/bytebuffer.js +// which is under the Apache License 2.0. + +let f32 = new Float32Array(1); +let f32_u8 = new Uint8Array(f32.buffer); + +let f64 = new Float64Array(1); +let f64_u8 = new Uint8Array(f64.buffer); + +function intToLong(value) { + value |= 0; + return { + low: value, + high: value >> 31, + unsigned: value >= 0, + }; +} + +let bbStack = []; + +function popByteBuffer() { + const bb = bbStack.pop(); + if (!bb) return { bytes: new Uint8Array(64), offset: 0, limit: 0 }; + bb.offset = bb.limit = 0; + return bb; +} + +function pushByteBuffer(bb) { + bbStack.push(bb); +} + +function wrapByteBuffer(bytes) { + return { bytes, offset: 0, limit: bytes.length }; +} + +function toUint8Array(bb) { + let bytes = bb.bytes; + let limit = bb.limit; + return bytes.length === limit ? bytes : bytes.subarray(0, limit); +} + +function skip(bb, offset) { + if (bb.offset + offset > bb.limit) { + throw new Error('Skip past limit'); + } + bb.offset += offset; +} + +function isAtEnd(bb) { + return bb.offset >= bb.limit; +} + +function grow(bb, count) { + let bytes = bb.bytes; + let offset = bb.offset; + let limit = bb.limit; + let finalOffset = offset + count; + if (finalOffset > bytes.length) { + let newBytes = new Uint8Array(finalOffset * 2); + newBytes.set(bytes); + bb.bytes = newBytes; + } + bb.offset = finalOffset; + if (finalOffset > limit) { + bb.limit = finalOffset; + } + return offset; +} + +function advance(bb, count) { + let offset = bb.offset; + if (offset + count > bb.limit) { + throw new Error('Read past limit'); + } + bb.offset += count; + return offset; +} + +function readBytes(bb, count) { + let offset = advance(bb, count); + return bb.bytes.subarray(offset, offset + count); +} + +function writeBytes(bb, buffer) { + let offset = grow(bb, buffer.length); + bb.bytes.set(buffer, offset); +} + +function readString(bb, count) { + // Sadly a hand-coded UTF8 decoder is much faster than subarray+TextDecoder in V8 + let offset = advance(bb, count); + let fromCharCode = String.fromCharCode; + let bytes = bb.bytes; + let invalid = '\uFFFD'; + let text = ''; + + for (let i = 0; i < count; i++) { + let c1 = bytes[i + offset], c2, c3, c4, c; + + // 1 byte + if ((c1 & 0x80) === 0) { + text += fromCharCode(c1); + } + + // 2 bytes + else if ((c1 & 0xE0) === 0xC0) { + if (i + 1 >= count) text += invalid; + else { + c2 = bytes[i + offset + 1]; + if ((c2 & 0xC0) !== 0x80) text += invalid; + else { + c = ((c1 & 0x1F) << 6) | (c2 & 0x3F); + if (c < 0x80) text += invalid; + else { + text += fromCharCode(c); + i++; + } + } + } + } + + // 3 bytes + else if ((c1 & 0xF0) == 0xE0) { + if (i + 2 >= count) text += invalid; + else { + c2 = bytes[i + offset + 1]; + c3 = bytes[i + offset + 2]; + if (((c2 | (c3 << 8)) & 0xC0C0) !== 0x8080) text += invalid; + else { + c = ((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F); + if (c < 0x0800 || (c >= 0xD800 && c <= 0xDFFF)) text += invalid; + else { + text += fromCharCode(c); + i += 2; + } + } + } + } + + // 4 bytes + else if ((c1 & 0xF8) == 0xF0) { + if (i + 3 >= count) text += invalid; + else { + c2 = bytes[i + offset + 1]; + c3 = bytes[i + offset + 2]; + c4 = bytes[i + offset + 3]; + if (((c2 | (c3 << 8) | (c4 << 16)) & 0xC0C0C0) !== 0x808080) text += invalid; + else { + c = ((c1 & 0x07) << 0x12) | ((c2 & 0x3F) << 0x0C) | ((c3 & 0x3F) << 0x06) | (c4 & 0x3F); + if (c < 0x10000 || c > 0x10FFFF) text += invalid; + else { + c -= 0x10000; + text += fromCharCode((c >> 10) + 0xD800, (c & 0x3FF) + 0xDC00); + i += 3; + } + } + } + } + + else text += invalid; + } + + return text; +} + +function writeString(bb, text) { + // Sadly a hand-coded UTF8 encoder is much faster than TextEncoder+set in V8 + let n = text.length; + let byteCount = 0; + + // Write the byte count first + for (let i = 0; i < n; i++) { + let c = text.charCodeAt(i); + if (c >= 0xD800 && c <= 0xDBFF && i + 1 < n) { + c = (c << 10) + text.charCodeAt(++i) - 0x35FDC00; + } + byteCount += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } + writeVarint32(bb, byteCount); + + let offset = grow(bb, byteCount); + let bytes = bb.bytes; + + // Then write the bytes + for (let i = 0; i < n; i++) { + let c = text.charCodeAt(i); + if (c >= 0xD800 && c <= 0xDBFF && i + 1 < n) { + c = (c << 10) + text.charCodeAt(++i) - 0x35FDC00; + } + if (c < 0x80) { + bytes[offset++] = c; + } else { + if (c < 0x800) { + bytes[offset++] = ((c >> 6) & 0x1F) | 0xC0; + } else { + if (c < 0x10000) { + bytes[offset++] = ((c >> 12) & 0x0F) | 0xE0; + } else { + bytes[offset++] = ((c >> 18) & 0x07) | 0xF0; + bytes[offset++] = ((c >> 12) & 0x3F) | 0x80; + } + bytes[offset++] = ((c >> 6) & 0x3F) | 0x80; + } + bytes[offset++] = (c & 0x3F) | 0x80; + } + } +} + +function writeByteBuffer(bb, buffer) { + let offset = grow(bb, buffer.limit); + let from = bb.bytes; + let to = buffer.bytes; + + // This for loop is much faster than subarray+set on V8 + for (let i = 0, n = buffer.limit; i < n; i++) { + from[i + offset] = to[i]; + } +} + +function readByte(bb) { + return bb.bytes[advance(bb, 1)]; +} + +function writeByte(bb, value) { + let offset = grow(bb, 1); + bb.bytes[offset] = value; +} + +function readFloat(bb) { + let offset = advance(bb, 4); + let bytes = bb.bytes; + + // Manual copying is much faster than subarray+set in V8 + f32_u8[0] = bytes[offset++]; + f32_u8[1] = bytes[offset++]; + f32_u8[2] = bytes[offset++]; + f32_u8[3] = bytes[offset++]; + return f32[0]; +} + +function writeFloat(bb, value) { + let offset = grow(bb, 4); + let bytes = bb.bytes; + f32[0] = value; + + // Manual copying is much faster than subarray+set in V8 + bytes[offset++] = f32_u8[0]; + bytes[offset++] = f32_u8[1]; + bytes[offset++] = f32_u8[2]; + bytes[offset++] = f32_u8[3]; +} + +function readDouble(bb) { + let offset = advance(bb, 8); + let bytes = bb.bytes; + + // Manual copying is much faster than subarray+set in V8 + f64_u8[0] = bytes[offset++]; + f64_u8[1] = bytes[offset++]; + f64_u8[2] = bytes[offset++]; + f64_u8[3] = bytes[offset++]; + f64_u8[4] = bytes[offset++]; + f64_u8[5] = bytes[offset++]; + f64_u8[6] = bytes[offset++]; + f64_u8[7] = bytes[offset++]; + return f64[0]; +} + +function writeDouble(bb, value) { + let offset = grow(bb, 8); + let bytes = bb.bytes; + f64[0] = value; + + // Manual copying is much faster than subarray+set in V8 + bytes[offset++] = f64_u8[0]; + bytes[offset++] = f64_u8[1]; + bytes[offset++] = f64_u8[2]; + bytes[offset++] = f64_u8[3]; + bytes[offset++] = f64_u8[4]; + bytes[offset++] = f64_u8[5]; + bytes[offset++] = f64_u8[6]; + bytes[offset++] = f64_u8[7]; +} + +function readInt32(bb) { + let offset = advance(bb, 4); + let bytes = bb.bytes; + return ( + bytes[offset] | + (bytes[offset + 1] << 8) | + (bytes[offset + 2] << 16) | + (bytes[offset + 3] << 24) + ); +} + +function writeInt32(bb, value) { + let offset = grow(bb, 4); + let bytes = bb.bytes; + bytes[offset] = value; + bytes[offset + 1] = value >> 8; + bytes[offset + 2] = value >> 16; + bytes[offset + 3] = value >> 24; +} + +function readInt64(bb, unsigned) { + return { + low: readInt32(bb), + high: readInt32(bb), + unsigned, + }; +} + +function writeInt64(bb, value) { + writeInt32(bb, value.low); + writeInt32(bb, value.high); +} + +function readVarint32(bb) { + let c = 0; + let value = 0; + let b; + do { + b = readByte(bb); + if (c < 32) value |= (b & 0x7F) << c; + c += 7; + } while (b & 0x80); + return value; +} + +function writeVarint32(bb, value) { + value >>>= 0; + while (value >= 0x80) { + writeByte(bb, (value & 0x7f) | 0x80); + value >>>= 7; + } + writeByte(bb, value); +} + +function readVarint64(bb, unsigned) { + let part0 = 0; + let part1 = 0; + let part2 = 0; + let b; + + b = readByte(bb); part0 = (b & 0x7F); if (b & 0x80) { + b = readByte(bb); part0 |= (b & 0x7F) << 7; if (b & 0x80) { + b = readByte(bb); part0 |= (b & 0x7F) << 14; if (b & 0x80) { + b = readByte(bb); part0 |= (b & 0x7F) << 21; if (b & 0x80) { + + b = readByte(bb); part1 = (b & 0x7F); if (b & 0x80) { + b = readByte(bb); part1 |= (b & 0x7F) << 7; if (b & 0x80) { + b = readByte(bb); part1 |= (b & 0x7F) << 14; if (b & 0x80) { + b = readByte(bb); part1 |= (b & 0x7F) << 21; if (b & 0x80) { + + b = readByte(bb); part2 = (b & 0x7F); if (b & 0x80) { + b = readByte(bb); part2 |= (b & 0x7F) << 7; + } + } + } + } + } + } + } + } + } + + return { + low: part0 | (part1 << 28), + high: (part1 >>> 4) | (part2 << 24), + unsigned, + }; +} + +function writeVarint64(bb, value) { + let part0 = value.low >>> 0; + let part1 = ((value.low >>> 28) | (value.high << 4)) >>> 0; + let part2 = value.high >>> 24; + + // ref: src/google/protobuf/io/coded_stream.cc + let size = + part2 === 0 ? + part1 === 0 ? + part0 < 1 << 14 ? + part0 < 1 << 7 ? 1 : 2 : + part0 < 1 << 21 ? 3 : 4 : + part1 < 1 << 14 ? + part1 < 1 << 7 ? 5 : 6 : + part1 < 1 << 21 ? 7 : 8 : + part2 < 1 << 7 ? 9 : 10; + + let offset = grow(bb, size); + let bytes = bb.bytes; + + switch (size) { + case 10: bytes[offset + 9] = (part2 >>> 7) & 0x01; + case 9: bytes[offset + 8] = size !== 9 ? part2 | 0x80 : part2 & 0x7F; + case 8: bytes[offset + 7] = size !== 8 ? (part1 >>> 21) | 0x80 : (part1 >>> 21) & 0x7F; + case 7: bytes[offset + 6] = size !== 7 ? (part1 >>> 14) | 0x80 : (part1 >>> 14) & 0x7F; + case 6: bytes[offset + 5] = size !== 6 ? (part1 >>> 7) | 0x80 : (part1 >>> 7) & 0x7F; + case 5: bytes[offset + 4] = size !== 5 ? part1 | 0x80 : part1 & 0x7F; + case 4: bytes[offset + 3] = size !== 4 ? (part0 >>> 21) | 0x80 : (part0 >>> 21) & 0x7F; + case 3: bytes[offset + 2] = size !== 3 ? (part0 >>> 14) | 0x80 : (part0 >>> 14) & 0x7F; + case 2: bytes[offset + 1] = size !== 2 ? (part0 >>> 7) | 0x80 : (part0 >>> 7) & 0x7F; + case 1: bytes[offset] = size !== 1 ? part0 | 0x80 : part0 & 0x7F; + } +} + +function readVarint32ZigZag(bb) { + let value = readVarint32(bb); + + // ref: src/google/protobuf/wire_format_lite.h + return (value >>> 1) ^ -(value & 1); +} + +function writeVarint32ZigZag(bb, value) { + // ref: src/google/protobuf/wire_format_lite.h + writeVarint32(bb, (value << 1) ^ (value >> 31)); +} + +function readVarint64ZigZag(bb) { + let value = readVarint64(bb, /* unsigned */ false); + let low = value.low; + let high = value.high; + let flip = -(low & 1); + + // ref: src/google/protobuf/wire_format_lite.h + return { + low: ((low >>> 1) | (high << 31)) ^ flip, + high: (high >>> 1) ^ flip, + unsigned: false, + }; +} + +function writeVarint64ZigZag(bb, value) { + let low = value.low; + let high = value.high; + let flip = high >> 31; + + // ref: src/google/protobuf/wire_format_lite.h + writeVarint64(bb, { + low: (low << 1) ^ flip, + high: ((high << 1) | (low >>> 31)) ^ flip, + unsigned: false, + }); +} diff --git a/node-sources/palettes.js b/node-sources/palettes.js new file mode 100644 index 00000000..79b043b6 --- /dev/null +++ b/node-sources/palettes.js @@ -0,0 +1,9 @@ +export const blackWhite = Buffer.from([0,0,0,255,255,255]) +export const rainbow = Buffer.from([ + 228,3,3, // Red + 255,140,0, // Orange + 255,237,0, // Yellow + 0,128,38, // Green + 0,77,255, // Blue + 117,7,135 // Purple/Violet +]) diff --git a/node-sources/render.js b/node-sources/render.js new file mode 100644 index 00000000..14f26c8b --- /dev/null +++ b/node-sources/render.js @@ -0,0 +1,102 @@ +// USAGE +// node render.js [] + +// EXAMPLE +// node render.js localhost + +import { randomInt } from "node:crypto"; +import { canvas, ctx, canvasToRGBFrame, virtualScreenH, virtualScreenW } from './virtual-screen.js' +import { rgbFrame, send, demoServer, addListener } from './server.js' + +let windowCenters = Array(10).fill(0).map((v,i) => 4 + (18 + 8) * i) + +let currentWindow = 4 +let center = windowCenters[currentWindow] + +async function gen(tick) { + const x = tick % virtualScreenW + const y = tick % virtualScreenH + ctx.save() + + const x0 = randomInt(center-1, center+1) + const y0 = randomInt(virtualScreenH/2-1,virtualScreenH/2+1) + const x1 = randomInt(0,virtualScreenW) + const y1 = randomInt(0,virtualScreenH) + + ctx.beginPath() + + let sweep = ctx.createLinearGradient(x0, y0, x1, y1) + sweep.addColorStop(0, "red") + sweep.addColorStop(0.25, "orange") + sweep.addColorStop(0.5, "yellow") + sweep.addColorStop(0.75, "green") + sweep.addColorStop(1, "blue") + ctx.strokeStyle = sweep + ctx.lineWidth = 0.5 + ctx.lineCap = "square" + // console.log(x0, y0, x1, y1) + ctx.moveTo(x0, y0) + ctx.lineTo(x1, y1) + ctx.closePath() + ctx.stroke() + ctx.restore() + return await canvasToRGBFrame(canvas) +} + +// function mutateRandomPixel (d) { +// const i = randomInt(0, 640) +// d[i] = randomInt(0, 8) +// } + +function printUsage () { + console.log("USAGE") + console.log("node render.js []") + console.log("EXAMPLE") + console.log("node render.js localhost") +} + +// console.log(process.argv.length) +if (process.argv.length < 3 || process.argv.length > 3) { + printUsage() + process.exit(1) +} + +const server = process.argv[2] ? process.argv[2] : demoServer +console.log("sending data to", server) +console.log("stop server with ctrl+c") +await new Promise(res => setTimeout(async _ => res(true), 500)) // ~60 frames per second + +let t = 0 + +process.on('beforeExit', e => console.log("bye bye")) +addListener(msg => { + const type = msg.input_event.type + // console.log(msg.input_event) + switch(type) { + case 'BUTTON_2': + currentWindow = Math.min(currentWindow+1, 9); + break; + case 'BUTTON_3': break; + case 'BUTTON_4': break; + case 'BUTTON_5': break; + case 'BUTTON_6': break; + case 'BUTTON_7': break; + case 'BUTTON_8': break; + case 'BUTTON_9': break; + case 'BUTTON_10': + ctx.clearRect(0, 0, virtualScreenW, virtualScreenH) + break; + default: + currentWindow = Math.max(currentWindow-1, 0); + break; + } + + center = windowCenters[currentWindow] +}) + +while (true) { + t++; + // console.log(t) + await send(server, rgbFrame(await gen(t))) + await new Promise(res => setTimeout(async _ => res(true), 600)) // ~60 frames per second +} diff --git a/node-sources/scan-image.js b/node-sources/scan-image.js new file mode 100644 index 00000000..8ff8aed2 --- /dev/null +++ b/node-sources/scan-image.js @@ -0,0 +1,49 @@ +// USAGE +// node scan-image.js [] + +// EXAMPLE +// node scan-image.js test-pixels.png localhost + +import { resolve } from "node:path"; +import { loadImage } from 'canvas' +import { ratio, virtualScreenW, virtualScreenH, canvas, ctx, canvasToRGBFrame } from './virtual-screen.js' +import { rgbFrame, close, send, demoServer } from './server.js' + +async function scan (tick) { + const offset = tick % imageH + ctx.drawImage(image, 0, offset, imageW, imageW/ratio, 0, 0, virtualScreenW, virtualScreenH) + return await canvasToRGBFrame(canvas) +} + +function printUsage () { + console.log("USAGE") + console.log("node scan-image.js []") + console.log("EXAMPLE") + console.log("node scan-image.js test-pixels.png localhost") +} + +// console.log(process.argv.length) +if (process.argv.length < 3 || process.argv.length > 4) { + printUsage() + process.exit(1) +} + +const path = resolve(process.argv[2]) +const image = await loadImage(path) +const imageW = image.width +const imageH = image.height + +const server = process.argv[3] ? process.argv[3] : demoServer +console.log("sending data to", server) +console.log(imageH) + +await send(server, rgbFrame(await scan(0))) + +for (let t = 1; t < imageH - virtualScreenH; t++) { + console.log(t) + await send(server, rgbFrame(await scan(t))) + await new Promise(res => setTimeout(async _ => res(true), 16)) // ~60 frames per second +} + +console.log("bye bye") +close() diff --git a/node-sources/server.js b/node-sources/server.js new file mode 100644 index 00000000..b7f96896 --- /dev/null +++ b/node-sources/server.js @@ -0,0 +1,42 @@ +import dgram from 'node:dgram' +import { encodePacket, decodePacket } from './packet.js'; + +export const client = dgram.createSocket('udp4'); + +let listeners = [ + msg => console.log(msg) +] + +export function addListener (f) { + listeners.push(f) +} + +client.on('message', function (msg, info) { + const decoded = decodePacket(msg) + listeners.map(f => f(decoded)) +}); + + +export const demoServer = 'remote-octopus.fly.dev' +export const port = 2342 + +export function frame (data, palette) { + return encodePacket({ frame: { data, palette } }) +} + +export function rgbFrame (data) { + return encodePacket({ rgb_frame: { data } }) +} + +export async function send(server, packet) { + return new Promise((resolve, reject) => { + client.send(packet, port, server, function(err, bytes) { + if (err) reject(err) + resolve(bytes) + }) + }) +} + +export function close () { + client.close() +} diff --git a/node-sources/test-pixels.png b/node-sources/test-pixels.png new file mode 100644 index 00000000..0de1063d Binary files /dev/null and b/node-sources/test-pixels.png differ diff --git a/node-sources/test-stripes-letterbox.png b/node-sources/test-stripes-letterbox.png new file mode 100644 index 00000000..e4869545 Binary files /dev/null and b/node-sources/test-stripes-letterbox.png differ diff --git a/node-sources/virtual-screen.js b/node-sources/virtual-screen.js new file mode 100644 index 00000000..42381239 --- /dev/null +++ b/node-sources/virtual-screen.js @@ -0,0 +1,49 @@ +import { createCanvas } from 'canvas' + +export const pixels = 640 +export const windowMargin = 18 +export const virtualScreenW = 10 * 8 + 9 * windowMargin; +export const virtualScreenH = 8; +export const ratio = virtualScreenW / virtualScreenH + +// const attributes = { pixelFormat: 'RGB32' } +export const canvas = createCanvas(virtualScreenW, virtualScreenH) +export const ctx = canvas.getContext('2d'); +ctx.antialias = 'none' + +export async function canvasToRGBFrame (canvas) { + // const imageData = ctx.getImageData(0, 0, virtualScreenW, virtualScreenH); + // console.log(imageData.data) + + // debug + // const out = createWriteStream('./test.png') + // const stream = canvas.createPNGStream() + // stream.pipe(out) + + const targetBuffer = Buffer.from(Array(pixels*3)) // rgb_frame + const rawBGRA = canvas.toBuffer("raw") + + for (let window = 0; window < 10; window++) { + for (let y = 0; y < 8; y++) { + for (let x = 0; x < 8; x++) { + // map target to source pixel index + const targetBufferIndex = 3 * (window * 64 + y * 8 + x) + const sourceBufferIndex = 4 * (window * (8 + windowMargin) + y * virtualScreenW + x) + + // read r g b from source - source is BGRA + const b = rawBGRA[sourceBufferIndex] + const g = rawBGRA[sourceBufferIndex+1] + const r = rawBGRA[sourceBufferIndex+2] + + // console.log({sourceBufferIndex, targetBufferIndex, r,g,b}) + // write r g b to target + targetBuffer[targetBufferIndex] = r + targetBuffer[targetBufferIndex+1] = g + targetBuffer[targetBufferIndex+2] = b + } + } + } + + // console.log(targetBuffer) + return targetBuffer +}