fix: modernize docker publishing
This commit is contained in:
@@ -1 +1,6 @@
|
|||||||
|
.git/
|
||||||
|
.nogit/
|
||||||
|
dist/
|
||||||
|
dist_*/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
rust/target/
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
name: Default (not tags)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags-ignore:
|
|
||||||
- '**'
|
|
||||||
|
|
||||||
env:
|
|
||||||
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
|
||||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
|
||||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
|
||||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
|
||||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
|
||||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
security:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
continue-on-error: true
|
|
||||||
container:
|
|
||||||
image: ${{ env.IMAGE }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Install pnpm and npmci
|
|
||||||
run: |
|
|
||||||
pnpm install -g pnpm
|
|
||||||
pnpm install -g @shipzone/npmci
|
|
||||||
|
|
||||||
- name: Run npm prepare
|
|
||||||
run: npmci npm prepare
|
|
||||||
|
|
||||||
- name: Audit production dependencies
|
|
||||||
run: |
|
|
||||||
npmci command npm config set registry https://registry.npmjs.org
|
|
||||||
npmci command pnpm audit --audit-level=high --prod
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Audit development dependencies
|
|
||||||
run: |
|
|
||||||
npmci command npm config set registry https://registry.npmjs.org
|
|
||||||
npmci command pnpm audit --audit-level=high --dev
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
test:
|
|
||||||
if: ${{ always() }}
|
|
||||||
needs: security
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ${{ env.IMAGE }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Test stable
|
|
||||||
run: |
|
|
||||||
npmci node install stable
|
|
||||||
npmci npm install
|
|
||||||
npmci npm test
|
|
||||||
|
|
||||||
- name: Test build
|
|
||||||
run: |
|
|
||||||
npmci node install stable
|
|
||||||
npmci npm install
|
|
||||||
npmci npm build
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
name: Default (tags)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
|
|
||||||
env:
|
|
||||||
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
|
||||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
|
||||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
|
||||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
|
||||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
|
||||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
security:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
continue-on-error: true
|
|
||||||
container:
|
|
||||||
image: ${{ env.IMAGE }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Prepare
|
|
||||||
run: |
|
|
||||||
pnpm install -g pnpm
|
|
||||||
pnpm install -g @shipzone/npmci
|
|
||||||
npmci npm prepare
|
|
||||||
|
|
||||||
- name: Audit production dependencies
|
|
||||||
run: |
|
|
||||||
npmci command npm config set registry https://registry.npmjs.org
|
|
||||||
npmci command pnpm audit --audit-level=high --prod
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Audit development dependencies
|
|
||||||
run: |
|
|
||||||
npmci command npm config set registry https://registry.npmjs.org
|
|
||||||
npmci command pnpm audit --audit-level=high --dev
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
test:
|
|
||||||
if: ${{ always() }}
|
|
||||||
needs: security
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ${{ env.IMAGE }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Prepare
|
|
||||||
run: |
|
|
||||||
pnpm install -g pnpm
|
|
||||||
pnpm install -g @shipzone/npmci
|
|
||||||
npmci npm prepare
|
|
||||||
|
|
||||||
- name: Test stable
|
|
||||||
run: |
|
|
||||||
npmci node install stable
|
|
||||||
npmci npm install
|
|
||||||
npmci npm test
|
|
||||||
|
|
||||||
- name: Test build
|
|
||||||
run: |
|
|
||||||
npmci node install stable
|
|
||||||
npmci npm install
|
|
||||||
npmci npm build
|
|
||||||
|
|
||||||
release:
|
|
||||||
needs: test
|
|
||||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ${{ env.IMAGE }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Prepare
|
|
||||||
run: |
|
|
||||||
pnpm install -g pnpm
|
|
||||||
pnpm install -g @shipzone/npmci
|
|
||||||
npmci npm prepare
|
|
||||||
|
|
||||||
- name: Release
|
|
||||||
run: |
|
|
||||||
npmci node install stable
|
|
||||||
npmci npm publish
|
|
||||||
|
|
||||||
metadata:
|
|
||||||
needs: test
|
|
||||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ${{ env.IMAGE }}
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Prepare
|
|
||||||
run: |
|
|
||||||
pnpm install -g pnpm
|
|
||||||
pnpm install -g @shipzone/npmci
|
|
||||||
npmci npm prepare
|
|
||||||
|
|
||||||
- name: Code quality
|
|
||||||
run: |
|
|
||||||
npmci command npm install -g typescript
|
|
||||||
npmci npm install
|
|
||||||
|
|
||||||
- name: Trigger
|
|
||||||
run: npmci trigger
|
|
||||||
|
|
||||||
- name: Build docs and upload artifacts
|
|
||||||
run: |
|
|
||||||
npmci node install stable
|
|
||||||
npmci npm install
|
|
||||||
pnpm install -g @git.zone/tsdoc
|
|
||||||
npmci command tsdoc
|
|
||||||
continue-on-error: true
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
name: Docker (non-tag pushes)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: code.foss.global/host.today/ht-docker-node:szci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @git.zone/tsdocker@latest
|
||||||
|
pnpm config set registry https://verdaccio.lossless.digital
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: pnpm test
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
run: tsdocker build
|
||||||
|
|
||||||
|
- name: Test image
|
||||||
|
run: tsdocker test
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
name: Docker (tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: code.foss.global/host.today/ht-docker-node:szci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: code.foss.global/host.today/ht-docker-dbase:szci
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @git.zone/tsdocker@latest
|
||||||
|
pnpm config set registry https://verdaccio.lossless.digital
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
- name: Login to registries
|
||||||
|
run: tsdocker login
|
||||||
|
|
||||||
|
- name: List images
|
||||||
|
run: tsdocker list
|
||||||
|
|
||||||
|
- name: Build images
|
||||||
|
run: tsdocker build
|
||||||
|
|
||||||
|
- name: Test images
|
||||||
|
run: tsdocker test
|
||||||
|
|
||||||
|
- name: Push to code.foss.global
|
||||||
|
run: tsdocker push code.foss.global
|
||||||
+8
-1
@@ -5,6 +5,13 @@
|
|||||||
"linux_arm64"
|
"linux_arm64"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"@git.zone/tsdocker": {
|
||||||
|
"registries": ["code.foss.global"],
|
||||||
|
"registryRepoMap": {
|
||||||
|
"code.foss.global": "serve.zone/remoteingress"
|
||||||
|
},
|
||||||
|
"platforms": ["linux/amd64", "linux/arm64"]
|
||||||
|
},
|
||||||
"@git.zone/cli": {
|
"@git.zone/cli": {
|
||||||
"projectType": "npm",
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
@@ -47,4 +54,4 @@
|
|||||||
"@ship.zone/szci": {
|
"@ship.zone/szci": {
|
||||||
"npmGlobalTools": []
|
"npmGlobalTools": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-35
@@ -1,46 +1,38 @@
|
|||||||
# gitzone dockerfile_service
|
# gitzone dockerfile_service
|
||||||
## STAGE 1 // BUILD
|
## STAGE 1 // BUILD
|
||||||
FROM registry.gitlab.com/hosttoday/ht-docker-node:npmci as node1
|
FROM code.foss.global/host.today/ht-docker-node:lts AS build
|
||||||
COPY ./ /app
|
|
||||||
WORKDIR /app
|
|
||||||
ARG NPMCI_TOKEN_NPM2
|
|
||||||
ENV NPMCI_TOKEN_NPM2 $NPMCI_TOKEN_NPM2
|
|
||||||
RUN npmci npm prepare
|
|
||||||
RUN pnpm config set store-dir .pnpm-store
|
|
||||||
RUN rm -rf node_modules && pnpm install
|
|
||||||
RUN pnpm run build
|
|
||||||
|
|
||||||
# gitzone dockerfile_service
|
|
||||||
## STAGE 2 // install production
|
|
||||||
FROM registry.gitlab.com/hosttoday/ht-docker-node:npmci as node2
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=node1 /app /app
|
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
RUN pnpm config set store-dir .pnpm-store
|
||||||
|
RUN pnpm config set registry https://verdaccio.lossless.digital
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
COPY . ./
|
||||||
|
# The npm package builds both Rust targets; each OCI image only needs its native binary.
|
||||||
|
RUN node -e "const fs=require('node:fs');const p='.smartconfig.json';const c=JSON.parse(fs.readFileSync(p,'utf8'));c['@git.zone/tsrust']={...(c['@git.zone/tsrust']||{}),targets:[]};fs.writeFileSync(p,JSON.stringify(c));" \
|
||||||
|
&& pnpm exec tsbuild tsfolders --allowimplicitany \
|
||||||
|
&& pnpm exec tsrust
|
||||||
RUN rm -rf .pnpm-store
|
RUN rm -rf .pnpm-store
|
||||||
ARG NPMCI_TOKEN_NPM2
|
RUN pnpm prune --prod
|
||||||
ENV NPMCI_TOKEN_NPM2 $NPMCI_TOKEN_NPM2
|
|
||||||
RUN npmci npm prepare
|
|
||||||
RUN pnpm config set store-dir .pnpm-store
|
|
||||||
RUN rm -rf node_modules/ && pnpm install --prod
|
|
||||||
|
|
||||||
|
## STAGE 2 // PRODUCTION
|
||||||
|
FROM code.foss.global/host.today/ht-docker-node:alpine-node AS production
|
||||||
|
|
||||||
## STAGE 3 // rebuild dependencies for alpine
|
|
||||||
FROM registry.gitlab.com/hosttoday/ht-docker-node:alpinenpmci as node3
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=node2 /app /app
|
|
||||||
ARG NPMCI_TOKEN_NPM2
|
|
||||||
ENV NPMCI_TOKEN_NPM2 $NPMCI_TOKEN_NPM2
|
|
||||||
RUN npmci npm prepare
|
|
||||||
RUN pnpm config set store-dir .pnpm-store
|
|
||||||
RUN pnpm rebuild -r
|
|
||||||
|
|
||||||
## STAGE 4 // the final production image with all dependencies in place
|
ENV NODE_ENV=production
|
||||||
FROM registry.gitlab.com/hosttoday/ht-docker-node:alpine as node4
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=node3 /app /app
|
|
||||||
|
|
||||||
### Healthchecks
|
COPY --from=build /app/package.json ./package.json
|
||||||
RUN pnpm install -g @servezone/healthy
|
COPY --from=build /app/node_modules ./node_modules
|
||||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=30s --retries=3 CMD [ "healthy" ]
|
COPY --from=build /app/cli.js ./cli.js
|
||||||
|
COPY --from=build /app/dist_ts ./dist_ts
|
||||||
|
COPY --from=build /app/dist_rust ./dist_rust
|
||||||
|
|
||||||
EXPOSE 80
|
LABEL org.opencontainers.image.title="remoteingress" \
|
||||||
CMD ["npm", "start"]
|
org.opencontainers.image.description="serve.zone edge ingress tunnel" \
|
||||||
|
org.opencontainers.image.source="https://code.foss.global/serve.zone/remoteingress"
|
||||||
|
|
||||||
|
EXPOSE 80 443 8443 53/udp
|
||||||
|
CMD ["node", "cli.js"]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"author": "Task Venture Capital GmbH",
|
"author": "Task Venture Capital GmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"start": "(node ./cli.js)",
|
||||||
"test": "(pnpm run build && tstest test/ --verbose --logfile --timeout 60)",
|
"test": "(pnpm run build && tstest test/ --verbose --logfile --timeout 60)",
|
||||||
"build": "(tsbuild tsfolders --allowimplicitany && tsrust)",
|
"build": "(tsbuild tsfolders --allowimplicitany && tsrust)",
|
||||||
"buildDocs": "(tsdoc)"
|
"buildDocs": "(tsdoc)"
|
||||||
|
|||||||
Executable
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
node --input-type=module <<'NODE'
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const readJson = (path) => JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||||
|
const arch = process.arch === 'x64' ? 'amd64' : process.arch;
|
||||||
|
|
||||||
|
const checks = {
|
||||||
|
packageVersion: readJson('/app/package.json').version,
|
||||||
|
hasCli: fs.existsSync('/app/cli.js'),
|
||||||
|
hasRustBinary: fs.existsSync(`/app/dist_rust/remoteingress-bin_linux_${arch}`) || fs.existsSync('/app/dist_rust/remoteingress-bin'),
|
||||||
|
};
|
||||||
|
|
||||||
|
await import('/app/dist_ts/index.js');
|
||||||
|
execFileSync('node', ['/app/cli.js', '--help'], { stdio: 'pipe' });
|
||||||
|
|
||||||
|
if (checks.packageVersion !== '4.17.1') {
|
||||||
|
throw new Error(`Unexpected remoteingress package version ${checks.packageVersion}`);
|
||||||
|
}
|
||||||
|
if (!checks.hasCli) {
|
||||||
|
throw new Error('Missing cli.js');
|
||||||
|
}
|
||||||
|
if (!checks.hasRustBinary) {
|
||||||
|
throw new Error(`Missing Rust binary for ${arch}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(checks));
|
||||||
|
NODE
|
||||||
@@ -135,7 +135,7 @@ export interface IUdpStatus {
|
|||||||
droppedDatagrams: number;
|
droppedDatagrams: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TAllowedEdge = { id: string; secret: string; listenPorts?: number[]; listenPortsUdp?: number[]; stunIntervalSecs?: number; firewallConfig?: IFirewallConfig; performance?: IPerformanceConfig };
|
export type TAllowedEdge = { id: string; secret: string; listenPorts?: number[]; listenPortsUdp?: number[]; stunIntervalSecs?: number; firewallConfig?: IFirewallConfig; performance?: IPerformanceConfig };
|
||||||
|
|
||||||
const MAX_RESTART_ATTEMPTS = 10;
|
const MAX_RESTART_ATTEMPTS = 10;
|
||||||
const MAX_RESTART_BACKOFF_MS = 30_000;
|
const MAX_RESTART_BACKOFF_MS = 30_000;
|
||||||
|
|||||||
+144
@@ -1,3 +1,147 @@
|
|||||||
|
import { RemoteIngressEdge } from './classes.remoteingressedge.js';
|
||||||
|
import { RemoteIngressHub, type IHubConfig, type TAllowedEdge } from './classes.remoteingresshub.js';
|
||||||
|
|
||||||
export * from './classes.remoteingresshub.js';
|
export * from './classes.remoteingresshub.js';
|
||||||
export * from './classes.remoteingressedge.js';
|
export * from './classes.remoteingressedge.js';
|
||||||
export * from './classes.token.js';
|
export * from './classes.token.js';
|
||||||
|
|
||||||
|
const usage = `remoteingress
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
remoteingress hub [--tunnel-port 8443] [--target-host 127.0.0.1]
|
||||||
|
remoteingress edge --token <connection-token>
|
||||||
|
remoteingress edge --hub-host <host> --edge-id <id> --secret <secret> [--hub-port 8443]
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
REMOTEINGRESS_MODE=hub|edge
|
||||||
|
REMOTEINGRESS_TOKEN=<connection-token>
|
||||||
|
REMOTEINGRESS_HUB_HOST=<host>
|
||||||
|
REMOTEINGRESS_HUB_PORT=8443
|
||||||
|
REMOTEINGRESS_EDGE_ID=<id>
|
||||||
|
REMOTEINGRESS_SECRET=<secret>
|
||||||
|
REMOTEINGRESS_TARGET_HOST=127.0.0.1
|
||||||
|
REMOTEINGRESS_ALLOWED_EDGES_JSON='[{"id":"edge-1","secret":"secret","listenPorts":[80,443]}]'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const readArg = (args: string[], name: string): string | undefined => {
|
||||||
|
const prefix = `--${name}=`;
|
||||||
|
const inlineValue = args.find((arg) => arg.startsWith(prefix));
|
||||||
|
if (inlineValue) {
|
||||||
|
return inlineValue.slice(prefix.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = args.indexOf(`--${name}`);
|
||||||
|
if (index >= 0) {
|
||||||
|
return args[index + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const readNumber = (value: string | undefined, fallback: number): number => {
|
||||||
|
if (!value) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {
|
||||||
|
throw new Error(`Invalid port: ${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const readJson = <T>(value: string | undefined, fallback: T): T => {
|
||||||
|
if (!value) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(value) as T;
|
||||||
|
};
|
||||||
|
|
||||||
|
const waitForever = async (stop: () => Promise<void>) => {
|
||||||
|
let stopping = false;
|
||||||
|
const handleStop = async () => {
|
||||||
|
if (stopping) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stopping = true;
|
||||||
|
await stop();
|
||||||
|
process.exit(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.once('SIGINT', () => void handleStop());
|
||||||
|
process.once('SIGTERM', () => void handleStop());
|
||||||
|
|
||||||
|
await new Promise(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const runCli = async () => {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
if (args.includes('--help') || args.includes('-h')) {
|
||||||
|
console.log(usage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionalMode = args[0]?.startsWith('--') ? undefined : args[0];
|
||||||
|
const mode = readArg(args, 'mode') ?? positionalMode ?? process.env.REMOTEINGRESS_MODE;
|
||||||
|
|
||||||
|
if (mode === 'hub') {
|
||||||
|
const hub = new RemoteIngressHub();
|
||||||
|
const config: IHubConfig = {
|
||||||
|
tunnelPort: readNumber(readArg(args, 'tunnel-port') ?? process.env.REMOTEINGRESS_TUNNEL_PORT, 8443),
|
||||||
|
targetHost: readArg(args, 'target-host') ?? process.env.REMOTEINGRESS_TARGET_HOST ?? '127.0.0.1',
|
||||||
|
tls: {
|
||||||
|
certPem: readArg(args, 'tls-cert-pem') ?? process.env.REMOTEINGRESS_TLS_CERT_PEM,
|
||||||
|
keyPem: readArg(args, 'tls-key-pem') ?? process.env.REMOTEINGRESS_TLS_KEY_PEM,
|
||||||
|
},
|
||||||
|
performance: readJson(readArg(args, 'performance-json') ?? process.env.REMOTEINGRESS_PERFORMANCE_JSON, undefined),
|
||||||
|
};
|
||||||
|
|
||||||
|
await hub.start(config);
|
||||||
|
|
||||||
|
const allowedEdges = readJson<TAllowedEdge[]>(
|
||||||
|
readArg(args, 'allowed-edges-json') ?? process.env.REMOTEINGRESS_ALLOWED_EDGES_JSON,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
if (allowedEdges.length > 0) {
|
||||||
|
await hub.updateAllowedEdges(allowedEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`RemoteIngress hub listening on ${config.tunnelPort}`);
|
||||||
|
await waitForever(() => hub.stop());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === 'edge') {
|
||||||
|
const edge = new RemoteIngressEdge();
|
||||||
|
const token = readArg(args, 'token') ?? process.env.REMOTEINGRESS_TOKEN;
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
await edge.start({ token });
|
||||||
|
} else {
|
||||||
|
const hubHost = readArg(args, 'hub-host') ?? process.env.REMOTEINGRESS_HUB_HOST;
|
||||||
|
const edgeId = readArg(args, 'edge-id') ?? process.env.REMOTEINGRESS_EDGE_ID;
|
||||||
|
const secret = readArg(args, 'secret') ?? process.env.REMOTEINGRESS_SECRET;
|
||||||
|
|
||||||
|
if (!hubHost || !edgeId || !secret) {
|
||||||
|
throw new Error('Edge mode requires --token or --hub-host, --edge-id, and --secret');
|
||||||
|
}
|
||||||
|
|
||||||
|
await edge.start({
|
||||||
|
hubHost,
|
||||||
|
hubPort: readNumber(readArg(args, 'hub-port') ?? process.env.REMOTEINGRESS_HUB_PORT, 8443),
|
||||||
|
edgeId,
|
||||||
|
secret,
|
||||||
|
bindAddress: readArg(args, 'bind-address') ?? process.env.REMOTEINGRESS_BIND_ADDRESS,
|
||||||
|
transportMode: readArg(args, 'transport-mode') as any,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('RemoteIngress edge started');
|
||||||
|
await waitForever(() => edge.stop());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(usage);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user