Skip to content

Commit a9fe4ee

Browse files
authored
Merge pull request #1 from deep-foundation/main
Merge
2 parents 219d1aa + 4684205 commit a9fe4ee

File tree

14 files changed

+77075
-5992
lines changed

14 files changed

+77075
-5992
lines changed

.github/workflows/dockerize.yaml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ name: Deploy deepRunnerJs
22
on:
33
push:
44
branches: [ main ]
5-
pull_request:
6-
branches: [ main ]
75
workflow_dispatch:
86
defaults:
97
run:
@@ -16,19 +14,24 @@ jobs:
1614
- uses: actions/checkout@v2
1715
- uses: actions/setup-node@v1
1816
with:
19-
node-version: '14.15'
17+
node-version: 18
18+
- name: Install latest npm
19+
run: npm install -g npm@latest
2020
- name: build
2121
run: npm ci && npm run package:build
22+
- name: Display npm log
23+
if: ${{ failure() }}
24+
run: cat /home/runner/.npm/_logs/*-debug.log
2225
- name: Log in to Docker Hub
2326
uses: docker/login-action@v1
2427
with:
25-
username: ${{ secrets.DOCKER_TEST_USERNAME }}
26-
password: ${{ secrets.DOCKER_TEST_PASSWORD }}
28+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
29+
password: ${{ secrets.DOCKERHUB_TOKEN }}
2730
- name: Extract metadata (tags, labels) for Docker
2831
id: meta
2932
uses: docker/metadata-action@v3
3033
with:
31-
images: konard/deep-runner-js
34+
images: deepf/js-docker-isolation-provider
3235
- name: build docker image and push
3336
id: docker_build
3437
uses: docker/build-push-action@v2

.github/workflows/npm-build.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: Npm Build
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, edited, synchronize]
6+
workflow_dispatch:
7+
8+
jobs:
9+
main:
10+
uses: deep-foundation/workflows/.github/workflows/npm-build.yml@main

.gitpod.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
tasks:
2+
- init: npm ci

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
18

Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:14.15-stretch
1+
FROM node:18
22

33
COPY package.json .
44
COPY index.js .
@@ -7,4 +7,7 @@ COPY index.ts .
77
COPY node_modules ./node_modules
88
COPY imports ./imports
99

10+
RUN apt-get update
11+
RUN apt-get install ffmpeg -y
12+
1013
ENTRYPOINT ["node", "index.js"]

LICENSE

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <https://unlicense.org>

README.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,59 @@
1-
# deepRunnerJs
1+
[![Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/deep-foundation/js-docker-isolation-provider)
2+
3+
# js-docker-isolation-provider
4+
5+
## HTTP routes
6+
7+
- `/healthz` - GET - 200 - Health check endpoint
8+
- Response:
9+
- `{}`
10+
- `/init` - GET - 200 - Initialization endpoint
11+
- Response:
12+
- `{}`
13+
- `/call` - GET - 200 - Call executable code of handler in this isolation provider (it used in HandleInsert, HandleUpdate, HandleDelete and so on)
14+
- Request:
15+
- body:
16+
- params:
17+
- jwt: STRING - Deeplinks send this token, for create gql and deep client
18+
- secret: STRING - Secret to access Hasura in unsafe mode (if package/user are allowed to use it by permissions)
19+
- code: STRING - Code of handler
20+
- data: {} - Data for handler execution from deeplinks
21+
> If this is type handler
22+
- oldLink - from deeplinks, link before transaction
23+
- newLink - from deeplinks, link after transaction
24+
- promiseId - from deeplinks, promise id
25+
- Response:
26+
- `{ resolved?: any; rejected?: any; }` - If resolved or rejected is not null, then it's result of execution
27+
- `/http-call` - GET - 200 - Call executable code of handler in this isolation provider to produce the http responce (it is used in HandleRoute)
28+
- Request:
29+
- Headers:
30+
- `deep-call-options`
31+
- jwt: STRING - Deeplinks send this token, for create gql and deep client
32+
- secret: STRING - Secret to access Hasura in unsafe mode (if package/user are allowed to use it by permissions)
33+
- code: STRING - Code of handler
34+
- data: {} - Data for handler execution from deeplinks
35+
> If this is type handler
36+
- oldLink - from deeplinks, link before transaction
37+
- newLink - from deeplinks, link after transaction
38+
- promiseId - from deeplinks, promise id
39+
- Responce:
40+
- Http responce generated by code if execution is successful
41+
- `{ rejected: any; }` - on error
42+
43+
## Diagnostics
44+
45+
### Logs
46+
47+
#### Get container logs to console:
48+
49+
```bash
50+
docker logs $(docker ps -a -q --filter "ancestor=deepf/js-docker-isolation-provider:main")
51+
```
52+
53+
#### Get container logs to file:
54+
55+
Sometimes console cannot output the full logs so it might be helpful to store the entire container's logs as file. It can be done like this:
56+
57+
```bash
58+
docker logs $(docker ps -a -q --filter "ancestor=deepf/js-docker-isolation-provider:main") > log.txt
59+
```

index.ts

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,118 @@
11
import express from 'express';
2-
import { generateApolloClient } from "@deep-foundation/hasura/client";
3-
import { DeepClient } from "@deep-foundation/deeplinks/imports/client";
4-
import memoize from 'lodash/memoize'
2+
import { generateApolloClient } from "@deep-foundation/hasura/client.js";
3+
import { HasuraApi } from '@deep-foundation/hasura/api.js';
4+
import { DeepClient, parseJwt } from "@deep-foundation/deeplinks/imports/client.js";
5+
import { gql } from '@apollo/client/index.js';
6+
import { serializeError } from 'serialize-error';
7+
import memoize from 'lodash/memoize.js';
8+
import http from 'http';
9+
// import { parseStream, parseFile } from 'music-metadata';
10+
import { createRequire } from 'node:module';
11+
import bodyParser from 'body-parser';
12+
const require = createRequire(import.meta.url);
513

614
const memoEval = memoize(eval);
715

816
const app = express();
9-
let initiated;
1017

11-
const GQL_URN = process.env.GQL_URN || 'localhost:3006/gql';
18+
const GQL_URN = process.env.GQL_URN || 'host.docker.internal:3006/gql';
1219
const GQL_SSL = process.env.GQL_SSL || 0;
1320

14-
const toJSON = (data) => JSON.stringify(data, Object.getOwnPropertyNames(data), 2);
21+
const DEEPLINKS_HASURA_PATH = process.env.DEEPLINKS_HASURA_PATH || 'host.docker.internal:8080';
22+
const DEEPLINKS_HASURA_SSL = !!(+process.env.DEEPLINKS_HASURA_SSL || 0);
23+
24+
const requireWrapper = (id: string) => {
25+
// if (id === 'music-metadata') {
26+
// return { parseStream, parseFile };
27+
// }
28+
return require(id);
29+
}
30+
31+
DeepClient.resolveDependency = requireWrapper;
32+
33+
const makeFunction = (code: string) => {
34+
const fn = memoEval(code);
35+
if (typeof fn !== 'function')
36+
{
37+
throw new Error("Executed handler's code didn't return a function.");
38+
}
39+
return fn;
40+
}
41+
42+
const makeDeepClient = (token: string, path?: string, ssl?: boolean, secret?: string) => {
43+
if (!token) throw new Error('No token provided');
44+
const decoded = parseJwt(token);
45+
const linkId = decoded?.userId;
46+
const apolloClient = generateApolloClient({
47+
path: GQL_URN,
48+
ssl: !!+GQL_SSL,
49+
token,
50+
});
51+
52+
const unsafe: any = {};
53+
if (secret) {
54+
unsafe.hasura = new HasuraApi({
55+
path,
56+
ssl,
57+
secret,
58+
});
59+
}
60+
61+
const deepClient = new DeepClient({ apolloClient, linkId, token, unsafe }) as any;
62+
return deepClient;
63+
}
64+
65+
const execute = async (args, options) => {
66+
const { jwt, secret, code, data, path, ssl } = options;
67+
const fn = makeFunction(code);
68+
const deep = makeDeepClient(jwt, path, ssl, secret);
69+
// await supports both sync and async functions the same way
70+
const result = await fn(...args, { data, deep, gql, require: requireWrapper });
71+
return result;
72+
}
73+
74+
app.use(bodyParser.json({limit: '50mb'}));
75+
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
1576

16-
app.use(express.json());
1777
app.get('/healthz', (req, res) => {
1878
res.json({});
1979
});
80+
2081
app.post('/init', (req, res) => {
2182
res.json({});
2283
});
23-
app.post('/call', async (req, res) => {
24-
try
25-
{
26-
console.log({ body: req?.body });
27-
const token = req?.body?.params?.jwt;
28-
if (!token) throw new Error('No token provided');
29-
initiated = memoEval(req?.body?.params?.code);
30-
if (typeof initiated !== 'function')
31-
{
32-
throw new Error("Executed handler's code didn't return a function.");
33-
}
34-
35-
const apolloClient = generateApolloClient({
36-
path: GQL_URN,
37-
ssl: !!+GQL_SSL,
38-
token,
39-
});
4084

41-
const deepClient = new DeepClient({ apolloClient });
42-
const result = await initiated({ deep: deepClient }); // Supports both sync and async functions the same way
85+
app.post('/call', async (req, res) => {
86+
try {
87+
const options = req?.body?.params || {};
88+
console.log('call options', options);
89+
const result = await execute([], options);
4390
console.log('call result', result);
4491
res.json({ resolved: result });
4592
}
4693
catch(rejected)
4794
{
48-
const processedRejection = JSON.parse(toJSON(rejected));
49-
console.log('rejected: ', processedRejection);
95+
const processedRejection = serializeError(rejected);
96+
console.log('rejected', processedRejection);
5097
res.json({ rejected: processedRejection });
5198
}
5299
});
53100

54-
app.listen(process.env.PORT, () => {
55-
console.log(`Listening ${process.env.PORT} port`);
56-
});
101+
app.use('/http-call', async (req, res, next) => {
102+
try {
103+
const options = JSON.parse(decodeURI(`${req.headers['deep-call-options']}`) || '{}');
104+
console.log('http call options', options);
105+
const result = await execute([req, res, next], options);
106+
console.log('http call result', result);
107+
return result;
108+
}
109+
catch(rejected)
110+
{
111+
const processedRejection = serializeError(rejected);
112+
console.log('rejected', processedRejection);
113+
res.json({ rejected: processedRejection }); // TODO: Do we need to send json to client? HTTP respone may not expect json output.
114+
}
115+
});
116+
117+
http.createServer({ maxHeaderSize: 10*1024*1024*1024 }, app).listen(process.env.PORT);
118+
console.log(`Listening ${process.env.PORT} port`);

key.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"type": "service_account",
3+
"project_id": "deep-sound-handler",
4+
"private_key_id": "c03fd7ed391b0e82a666f6b88089e3b145c33879",
5+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCljHCNaHpGK/AS\n4iE9+h+eAL93H3HKLchrz3hADZjHwNetquySoh71g3zcXhKqmQWbD6o3pw4+tAsJ\nHfecgjAlxvmZ8wNbycgfnT6u2iM2fCUhwuxy2WYURHAGTqupAkkZIGksLDSBYQqH\nrqx7l142JnaJdqeYm4YjRdNO8X3ROcQcSlJflK4yBozFq2QyNJLHZMpL+1bCY88Q\nhIKEqXWbVT2iWTAtJPwZqdbRyIr/vjnk63fNuEmNy1VFW1Q6hR2wA3WyY2Re5nKG\nxMQuBpJSfrZn5mJlodPkKpPUP4Jtkn9kfT0O5Fk5nxVA5XIa8kjVHEXzVmrQYbrv\n5VEsKF71AgMBAAECggEAGxYueESm9QJNZpmPPNfHApA2w6Pmd2EkUNeCYmCXJd/c\nqjK0QI28KQmZjWjq/vTIoQVgIXj48LN+tsArenUmsZer0U+cthD+6IVO80cHyeto\nG+0LyQLfG+PSvIV0utN/6FeQPcUB1kVtdqPS3un2ZT/H11gNtf+EZBMRrvH+VxQs\nGyNDQeO9tMhrOxeOyYrZg8KBa+1K9yucBKgQUvjOFTL7jSLXq7ODCs1joUNy17ZD\nOK2H40dp+ul5b9BeA58zwDygHhh1DKgfXef0KjhfzuKQG6wXs0DUXvdG/S6QTnX/\nmZ5qP06/FFlaIVppYJIOrdG5eCtyRfitSWhSgcmPJQKBgQDYC03dSS8gS26GWGgV\nlWnyh7XXVtMx2M/i9cx6/zkXp0p1y+aZoU20CumlTXPbGbIGy5JbRSGmeGCszrZo\nTWA75Yj4lkDR0NjkcfpdvdIe3zjsWuo9N6gNJV5zCSjib9O+YZ5BbcHUoChlaLYz\nG7Uzpszp1jB3xg9AyMfpf+1IcwKBgQDEKmcwLwjcjYRsnmyiveOxNWSsR9CsN/1q\np1WS5XTs9Tv3gtTt6WweGoi/dKTOMNeVRR1pxSxYHJ2e2/hFAAwLUjFUoFvj6htO\nShfqxGtQA+RWCrAxg59mD5I8JFDdm/NGbYP0czOaOhnUbSUVDQ0dNJpjflEsqXeF\n9+bOr6So9wKBgDf2NaUsX9itsWN7Yvq0SU1ZefDdvLccwjy4Ds+NbOyDmPYKayFA\ndzA742m+NlR6w3KfKLobnivQ4rngkb9Sy6q4OlKqGQBAaO5D1+aQVO1KRSR0KFjT\nIeTF2UFTDhQZg2+9OZEZLSw2kEA0b32tn7JRcqLfqI5d73WIjMAfMwehAoGAImv+\nZ2oZd/otPpIeJgCEL9harhB8AXxhr5FlZr104w+1Uh1XF9hZ7H5jeJUTRkszyTGz\nk5fRzDRZREL9Mb5sXqAxn9Pzy+6MlBRUVhHZctT8AE0n1chu9A3Pb1ZACmMPMVCO\nUxrT90AywB/W3fbIUlOks8i6nceu/YcerS4NCskCgYBCusqLkGStC9Tw7R1xX+ey\nDkA5sGNfHIV18PQH1l0R1MNf1cXjxkBvt4aVTO5iqcLfr/LCGwYQJn/CXuBkS2Tv\njKOAdmkFVGe1DdMLXDbhHKwduHnqgAkEyWu0Jw+lPHvziTmcJy2t3m9Lcm9srgEu\nKE9c9B+zjkFrG8NTrLAhbQ==\n-----END PRIVATE KEY-----\n",
6+
"client_email": "deep-sound-handler@deep-sound-handler.iam.gserviceaccount.com",
7+
"client_id": "100687498969961716359",
8+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
9+
"token_uri": "https://oauth2.googleapis.com/token",
10+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/deep-sound-handler%40deep-sound-handler.iam.gserviceaccount.com"
12+
}

local/docker-compose.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
version: '3.6'
1+
version: '3.7'
22
services:
3-
deep-runner-js:
4-
image: konard/deep-runner-js:main
3+
js-docker-isolation-provider:
4+
image: deepf/js-docker-isolation-provider:main
55
networks:
66
- deep
77
ports:

0 commit comments

Comments
 (0)