Skip to content

Commit

Permalink
feat: run server init as promise (#3210)
Browse files Browse the repository at this point in the history
* feat: run server init as promise

* chore: format

* fix: format

* fix: format

* fix: restore files

* fix: restore files

* fix: disable steps

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli

* fix: init log on cli
  • Loading branch information
juanpicado committed Jun 2, 2022
1 parent 4f59bb8 commit 42194c7
Show file tree
Hide file tree
Showing 18 changed files with 319 additions and 44 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/e2e-gatsbyjs-cli-workflow.yml
Expand Up @@ -8,7 +8,7 @@ on:
name: 'E2E Gatsby.js CLI with verdaccio'
jobs:
npm6:
name: 'npm:gatsby example'
name: 'npm6:gatsby example'
runs-on: ubuntu-latest

steps:
Expand All @@ -32,7 +32,7 @@ jobs:
run: |
source scripts/e2e-setup-ci.sh
echo "registry=http://localhost:4873
loglevel="silent"
loglevel="warn"
fetch-retries=10
fetch-retry-factor=2
fetch-retry-mintimeout=10000
Expand Down
16 changes: 8 additions & 8 deletions .pnp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
6 changes: 6 additions & 0 deletions debug/bootstrap-runserver.js
@@ -0,0 +1,6 @@
// this file aims to help local debugging with hot transpilation
// it requires BABEL_ENV=registry set as env variable
require('@babel/register')({
extensions: ['.ts', '.js'],
});
require('./run-server');
9 changes: 9 additions & 0 deletions debug/run-server.ts
@@ -0,0 +1,9 @@
/* eslint-disable no-console */
const { runServer } = require('../src');

(async () => {
const app = await runServer(); // default configuration
app.listen(4000, () => {
console.log('listening on port 4000');
});
})();
4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -105,7 +105,7 @@
"@typescript-eslint/eslint-plugin": "4.33.0",
"@typescript-eslint/parser": "4.33.0",
"@verdaccio/eslint-config": "^8.5.0",
"@verdaccio/types": "10.3.0",
"@verdaccio/types": "10.4.2",
"all-contributors-cli": "6.20.0",
"babel-eslint": "10.1.0",
"babel-jest": "26.6.3",
Expand Down Expand Up @@ -172,7 +172,9 @@
"lint:ts": "eslint \"**/*.{js,jsx,ts,tsx}\" -c ./eslintrc.js",
"lint:lockfile": "lockfile-lint --path yarn.lock --type yarn --validate-https --allowed-hosts verdaccio npm yarn",
"start": "yarn babel-node --extensions \".ts,.tsx\" src/lib/cli --inspect",
"start:brk": "yarn babel-node --extensions \".ts,.tsx\" src/lib/cli --inspect-brk",
"start:debug": "yarn node debug/bootstrap.js",
"start:run-server": "yarn node debug/bootstrap-runserver.js",
"code:build": "yarn babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps inline",
"code:docker-build": "yarn babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\"",
"docker": "docker build -t verdaccio/verdaccio:local . --no-cache",
Expand Down
21 changes: 5 additions & 16 deletions scripts/e2e-config.yaml
Expand Up @@ -7,31 +7,21 @@ auth:
htpasswd:
file: ./htpasswd
uplinks:
verdaccio:
url: https://registry.verdaccio.org/
max_fails: 30
fail_timeout: 10m
timeout: 60s
cache: false
maxage: 30m
agent_options:
keepAlive: true
maxSockets: 40
maxFreeSockets: 10
npmjs:
url: https://registry.npmjs.org/

packages:
'@*/*':
# scoped packages
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: verdaccio
proxy: npmjs

'**':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: verdaccio
proxy: npmjs

server:
keepAliveTimeout: 60
Expand All @@ -40,5 +30,4 @@ middlewares:
audit:
enabled: true

logs:
- { type: stdout, format: json, level: warn }
logs: { type: stdout, format: json, level: warn }
9 changes: 5 additions & 4 deletions src/index.ts
@@ -1,4 +1,5 @@
// @flow
import { startVerdaccio } from './lib/bootstrap';

export default startVerdaccio;
export { parseConfigFile } from './lib/utils';
export { startVerdaccio as default, startVerdaccio } from './lib/bootstrap';
// Similar structure as v6 but with different functions
// this is a bridge for easy migration to v6
export { runServer } from './lib/bootstrap.v2';
16 changes: 14 additions & 2 deletions src/lib/bootstrap.ts
@@ -1,6 +1,6 @@
import constants from 'constants';
import express from 'express';
import { Application } from 'express';
import express from 'express';
import fs from 'fs';
import http from 'http';
import https from 'https';
Expand Down Expand Up @@ -32,6 +32,7 @@ function displayExperimentsInfoBox(experiments) {
* @param {String} configPath
* @param {String} pkgVersion
* @param {String} pkgName
* @deprecated use runServer instead
*/
function startVerdaccio(config: any, cliListen: string, configPath: string, pkgVersion: string, pkgName: string, callback: Callback): void {
if (isObject(config) === false) {
Expand All @@ -45,6 +46,10 @@ function startVerdaccio(config: any, cliListen: string, configPath: string, pkgV
endPointAPI(config).then((app): void => {
const addresses = getListListenAddresses(cliListen, config.listen);

if (addresses.length > 1) {
process.emitWarning('multiple listen addresses are deprecated, please use only one');
}

addresses.forEach(function (addr): void {
let webServer;
if (addr.proto === 'https') {
Expand Down Expand Up @@ -135,7 +140,14 @@ function handleHTTPS(app: express.Application, configPath: string, config: Confi
process.exit(2);
}
}

/**
*
* @param webServer
* @param addr
* @param pkgName
* @param pkgVersion
* @deprecated use initServer instead
*/
function listenDefaultCallback(webServer: Application, addr: any, pkgName: string, pkgVersion: string): void {
const server = webServer
.listen(addr.port || addr.path, addr.host, (): void => {
Expand Down
147 changes: 147 additions & 0 deletions src/lib/bootstrap.v2.ts
@@ -0,0 +1,147 @@
import constants from 'constants';
import buildDebug from 'debug';
import fs from 'fs';
import http from 'http';
import https from 'https';
import _, { assign } from 'lodash';
import path from 'path';

import { ConfigRuntime, HttpsConfKeyCert, HttpsConfPfx } from '@verdaccio/types';

import endPointAPI from '../api/index';
import { getListListenAddresses } from './cli/utils';
import findConfigFile from './config-path';
import { API_ERROR } from './constants';
import { parseConfigFile } from './utils';

const debug = buildDebug('verdaccio');

const logger = require('./logger');

export function displayExperimentsInfoBox(flags) {
if (!flags) {
return;
}

const experimentList = Object.keys(flags);
if (experimentList.length >= 1) {
logger.warn(
// eslint-disable-next-line max-len
`experiments are enabled, it is recommended do not use experiments in production comment out this section to disable it`
);
experimentList.forEach((experiment) => {
// eslint-disable-next-line max-len
logger.info(`support for experiment [${experiment}] ${flags[experiment] ? 'is enabled' : ' is disabled'}`);
});
}
}

/**
* Exposes a server factory to be instantiated programmatically.
*
const app = await runServer(); // default configuration
const app = await runServer('./config/config.yaml');
const app = await runServer({ configuration });
app.listen(4000, (event) => {
// do something
});
* @param config
*/
export async function runServer(config?: string): Promise<any> {
let configurationParsed: ConfigRuntime;
if (config === undefined || typeof config === 'string') {
const configPathLocation = findConfigFile(config);
configurationParsed = parseConfigFile(configPathLocation) as ConfigRuntime;
if (!configurationParsed.self_path) {
configurationParsed.self_path = path.resolve(configPathLocation);
}
} else if (_.isObject(config)) {
configurationParsed = config;
if (!configurationParsed.self_path) {
throw new Error('self_path is required, please provide a valid root path for storage');
}
} else {
throw new Error(API_ERROR.CONFIG_BAD_FORMAT);
}

const addresses = getListListenAddresses(undefined, configurationParsed.listen);
if (addresses.length > 1) {
process.emitWarning('You have specified multiple listen addresses, using this method only the first will be used');
}

const app = await endPointAPI(configurationParsed);
return createServerFactory(configurationParsed, addresses[0], app);
}

/**
* Return a native HTTP/HTTPS server instance
* @param config
* @param addr
* @param app
*/
export function createServerFactory(config: ConfigRuntime, addr, app) {
let serverFactory;
if (addr.proto === 'https') {
debug('https enabled');
try {
let httpsOptions = {
// disable insecure SSLv2 and SSLv3
secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3,
};

const keyCertConfig = config.https as HttpsConfKeyCert;
const pfxConfig = config.https as HttpsConfPfx;

// https must either have key and cert or a pfx and (optionally) a passphrase
if (!((keyCertConfig.key && keyCertConfig.cert) || pfxConfig.pfx)) {
throw Error('bad format https configuration');
}

if (pfxConfig.pfx) {
const { pfx, passphrase } = pfxConfig;
httpsOptions = assign(httpsOptions, {
pfx: fs.readFileSync(pfx),
passphrase: passphrase || '',
});
} else {
const { key, cert, ca } = keyCertConfig;
httpsOptions = assign(httpsOptions, {
key: fs.readFileSync(key),
cert: fs.readFileSync(cert),
...(ca && {
ca: fs.readFileSync(ca),
}),
});
}
// TODO: enable http2 as feature
// if (config.server.http2) <-- check if force http2
serverFactory = https.createServer(httpsOptions, app);
} catch (err) {
throw new Error(`cannot create https server: ${err.message}`);
}
} else {
// http
debug('http enabled');
serverFactory = http.createServer(app);
}

if (
config.server &&
typeof config.server.keepAliveTimeout !== 'undefined' &&
// @ts-ignore
config.server.keepAliveTimeout !== 'null'
) {
// library definition for node is not up to date (doesn't contain recent 8.0 changes)
serverFactory.keepAliveTimeout = config.server.keepAliveTimeout * 1000;
}
// FIXE: I could not find the reason of this code.
unlinkAddressPath(addr);

return serverFactory;
}

function unlinkAddressPath(addr) {
if (addr.path && fs.existsSync(addr.path)) {
fs.unlinkSync(addr.path);
}
}
2 changes: 1 addition & 1 deletion src/lib/cli/utils.ts
Expand Up @@ -27,7 +27,7 @@ export function isVersionValid(version) {
- localhost:5557
@return {Array}
*/
export function getListListenAddresses(argListen: string, configListen: any): any {
export function getListListenAddresses(argListen: string | void, configListen: any): any {
// command line || config file || default
let addresses;
if (argListen) {
Expand Down

0 comments on commit 42194c7

Please sign in to comment.