mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-04-01 02:42:23 -05:00
refactor: storage is async
allows storage to initalize whether a async call is required on start up.
This commit is contained in:
parent
df418a8ecb
commit
e5caa71d35
15 changed files with 84 additions and 76 deletions
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/file-locking": "0.0.5",
|
||||
"@verdaccio/local-storage": "1.0.1",
|
||||
"@verdaccio/local-storage": "1.0.2",
|
||||
"@verdaccio/streams": "1.0.0",
|
||||
"JSONStream": "1.3.2",
|
||||
"async": "2.6.0",
|
||||
|
@ -51,7 +51,7 @@
|
|||
"@commitlint/cli": "6.1.3",
|
||||
"@commitlint/config-conventional": "6.1.3",
|
||||
"@commitlint/travis-cli": "6.1.3",
|
||||
"@verdaccio/types": "2.1.0",
|
||||
"@verdaccio/types": "2.2.0",
|
||||
"babel-cli": "6.26.0",
|
||||
"babel-core": "6.26.0",
|
||||
"babel-eslint": "8.2.2",
|
||||
|
|
|
@ -20,11 +20,7 @@ const Config = require('../lib/config');
|
|||
const Middleware = require('./middleware');
|
||||
const Cats = require('../lib/status-cats');
|
||||
|
||||
export default function(configHash: any) {
|
||||
// Config
|
||||
LoggerApp.setup(configHash.logs);
|
||||
const config: IConfig = new Config(configHash);
|
||||
const storage: IStorageHandler = new Storage(config);
|
||||
const defineAPI = function(config: Config, storage: IStorageHandler) {
|
||||
const auth: IAuth = new Auth(config);
|
||||
const app: $Application = express();
|
||||
// run in production mode by default, just in case
|
||||
|
@ -102,4 +98,13 @@ export default function(configHash: any) {
|
|||
app.use(Middleware.final);
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
export default async function(configHash: any) {
|
||||
LoggerApp.setup(configHash.logs);
|
||||
const config: IConfig = new Config(configHash);
|
||||
const storage: IStorageHandler = new Storage(config);
|
||||
// waits until init calls have been intialized
|
||||
await storage.init(config);
|
||||
return defineAPI(config, storage);
|
||||
}
|
||||
|
|
38
src/lib/bootstrap.js
vendored
38
src/lib/bootstrap.js
vendored
|
@ -8,7 +8,7 @@ import http from'http';
|
|||
import https from 'https';
|
||||
// $FlowFixMe
|
||||
import constants from 'constants';
|
||||
import server from '../api/index';
|
||||
import endPointAPI from '../api/index';
|
||||
import {parse_address} from './utils';
|
||||
|
||||
import type {Callback} from '@verdaccio/types';
|
||||
|
@ -63,31 +63,35 @@ export function getListListenAddresses(argListen: string, configListen: mixed) {
|
|||
* @param {String} pkgVersion
|
||||
* @param {String} pkgName
|
||||
*/
|
||||
function startVerdaccio(config: any, cliListen: string, configPath: string, pkgVersion: string, pkgName: string, callback: Callback) {
|
||||
function startVerdaccio(config: any, cliListen: string,
|
||||
configPath: string, pkgVersion: string,
|
||||
pkgName: string, callback: Callback) {
|
||||
if (isObject(config) === false) {
|
||||
throw new Error('config file must be an object');
|
||||
}
|
||||
|
||||
const app = server(config);
|
||||
const addresses = getListListenAddresses(cliListen, config.listen);
|
||||
endPointAPI(config).then((app)=> {
|
||||
const addresses = getListListenAddresses(cliListen, config.listen);
|
||||
|
||||
addresses.forEach(function(addr) {
|
||||
let webServer;
|
||||
if (addr.proto === 'https') {
|
||||
// https must either have key cert and ca or a pfx and (optionally) a passphrase
|
||||
if (!config.https || !config.https.key || !config.https.cert || !config.https.ca) {
|
||||
displayHTTPSWarning(configPath);
|
||||
addresses.forEach(function(addr) {
|
||||
let webServer;
|
||||
if (addr.proto === 'https') {
|
||||
// https must either have key cert and ca or a pfx and (optionally) a passphrase
|
||||
if (!config.https || !config.https.key || !config.https.cert || !config.https.ca) {
|
||||
displayHTTPSWarning(configPath);
|
||||
}
|
||||
|
||||
webServer = handleHTTPS(app, configPath, config);
|
||||
} else { // http
|
||||
webServer = http.createServer(app);
|
||||
}
|
||||
|
||||
webServer = handleHTTPS(app, configPath, config);
|
||||
} else { // http
|
||||
webServer = http.createServer(app);
|
||||
}
|
||||
unlinkAddressPath(addr);
|
||||
|
||||
unlinkAddressPath(addr);
|
||||
|
||||
callback(webServer, addr, pkgName, pkgVersion);
|
||||
callback(webServer, addr, pkgName, pkgVersion);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function unlinkAddressPath(addr) {
|
||||
|
|
|
@ -59,13 +59,13 @@ try {
|
|||
}
|
||||
|
||||
logger.logger.warn({file: configPathLocation}, 'config file - @{file}');
|
||||
|
||||
startVerdaccio(verdaccioConfiguration, cliListner, configPathLocation, pkgVersion, pkgName, listenDefaultCallback);
|
||||
} catch (err) {
|
||||
logger.logger.fatal({file: configPathLocation, err: err}, 'cannot open config file @{file}: @{!err.message}');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
startVerdaccio(verdaccioConfiguration, cliListner, configPathLocation, pkgVersion, pkgName, listenDefaultCallback);
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
logger.logger.fatal( {
|
||||
err: err,
|
||||
|
|
|
@ -208,7 +208,7 @@ class Config {
|
|||
* @return {String}
|
||||
*/
|
||||
checkSecretKey(secret) {
|
||||
if (_.isNil(secret) === false && secret !== '') {
|
||||
if (_.isString(secret) && secret !== '') {
|
||||
this.secret = secret;
|
||||
return secret;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ class LocalStorage implements IStorage {
|
|||
this.logger = logger.child({sub: 'fs'});
|
||||
this.config = config;
|
||||
this.localData = this._loadStorage(config, logger);
|
||||
this._setSecret(config);
|
||||
}
|
||||
|
||||
addPackage(name: string, pkg: Package, callback: Callback) {
|
||||
|
@ -839,8 +838,10 @@ class LocalStorage implements IStorage {
|
|||
}
|
||||
}
|
||||
|
||||
_setSecret(config: Config) {
|
||||
this.localData.setSecret(config.checkSecretKey(this.localData.getSecret()));
|
||||
async getSecret(config: Config) {
|
||||
const secretKey = await this.localData.getSecret();
|
||||
|
||||
return this.localData.setSecret(config.checkSecretKey(secretKey));
|
||||
}
|
||||
|
||||
_loadStorage(config: Config, logger: Logger) {
|
||||
|
|
|
@ -41,10 +41,6 @@ const getDefaultMetadata = function(name): Package {
|
|||
return pkgMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements Storage interface
|
||||
* (same for storage.js, local-storage.js, up-storage.js).
|
||||
*/
|
||||
class Storage implements IStorageHandler {
|
||||
localStorage: IStorage;
|
||||
config: Config;
|
||||
|
@ -59,7 +55,12 @@ class Storage implements IStorageHandler {
|
|||
this.uplinks = {};
|
||||
this._setupUpLinks(this.config);
|
||||
this.logger = LoggerApi.logger.child();
|
||||
}
|
||||
|
||||
init(config: Config) {
|
||||
this.localStorage = new LocalStorage(this.config, LoggerApi.logger);
|
||||
|
||||
return this.localStorage.getSecret(config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,21 +5,17 @@ import rimraf from 'rimraf';
|
|||
|
||||
import configDefault from './partials/config/access';
|
||||
import Config from '../../src/lib/config';
|
||||
import Storage from '../../src/lib/storage';
|
||||
import Auth from '../../src/lib/auth';
|
||||
import indexAPI from '../../src/api/index';
|
||||
import endPointAPI from '../../src/api/index';
|
||||
|
||||
require('../../src/lib/logger').setup([]);
|
||||
|
||||
describe('api with no limited access configuration', () => {
|
||||
let config;
|
||||
let storage;
|
||||
let auth;
|
||||
let app;
|
||||
|
||||
beforeAll(function(done) {
|
||||
const store = path.join(__dirname, './partials/store/access-storage');
|
||||
rimraf(store, () => {
|
||||
rimraf(store, async () => {
|
||||
const configForTest = _.clone(configDefault);
|
||||
configForTest.auth = {
|
||||
htpasswd: {
|
||||
|
@ -28,9 +24,7 @@ describe('api with no limited access configuration', () => {
|
|||
};
|
||||
configForTest.self_path = store;
|
||||
config = new Config(configForTest);
|
||||
storage = new Storage(config);
|
||||
auth = new Auth(config);
|
||||
app = indexAPI(config, auth, storage);
|
||||
app = await endPointAPI(config);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,23 +7,19 @@ import configDefault from './partials/config';
|
|||
import publishMetadata from './partials/publish-api';
|
||||
import forbiddenPlace from './partials/forbidden-place';
|
||||
import Config from '../../src/lib/config';
|
||||
import Storage from '../../src/lib/storage';
|
||||
import Auth from '../../src/lib/auth';
|
||||
import indexAPI from '../../src/api/index';
|
||||
import endPointAPI from '../../src/api/index';
|
||||
|
||||
require('../../src/lib/logger').setup([]);
|
||||
const credentials = { name: 'Jota', password: 'secretPass' };
|
||||
|
||||
describe('endpoint unit test', () => {
|
||||
let config;
|
||||
let storage;
|
||||
let auth;
|
||||
let app;
|
||||
jest.setTimeout(10000);
|
||||
|
||||
beforeAll(function(done) {
|
||||
const store = path.join(__dirname, './partials/store/test-storage');
|
||||
rimraf(store, () => {
|
||||
rimraf(store, async () => {
|
||||
const configForTest = _.clone(configDefault);
|
||||
configForTest.auth = {
|
||||
htpasswd: {
|
||||
|
@ -32,9 +28,7 @@ describe('endpoint unit test', () => {
|
|||
};
|
||||
configForTest.self_path = store;
|
||||
config = new Config(configForTest);
|
||||
storage = new Storage(config);
|
||||
auth = new Auth(config);
|
||||
app = indexAPI(config, auth, storage);
|
||||
app = await endPointAPI(config);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import verdaccio from '../../src/api/index';
|
||||
import endPointAPI from '../../src/api/index';
|
||||
|
||||
const assert = require('assert');
|
||||
const express = require('express');
|
||||
|
@ -17,9 +17,9 @@ describe('basic system test', () => {
|
|||
rimraf(__dirname + '/store/test-storage', done);
|
||||
});
|
||||
|
||||
beforeAll(function(done) {
|
||||
beforeAll(async function(done) {
|
||||
|
||||
app.use(verdaccio(config));
|
||||
app.use(await endPointAPI(config));
|
||||
|
||||
server.listen(0, function() {
|
||||
port = server.address().port;
|
||||
|
|
|
@ -9,10 +9,10 @@ require('../../src/lib/logger').setup([]);
|
|||
describe('startServer via API', () => {
|
||||
|
||||
describe('startServer launcher', () => {
|
||||
test('should provide all server data', (done) => {
|
||||
test('should provide all server data await/async', async (done) => {
|
||||
const store = path.join(__dirname, 'partials/store');
|
||||
|
||||
startServer(config, 6000, store, '1.0.0', 'verdaccio-test',
|
||||
await startServer(config, 6000, store, '1.0.0', 'verdaccio-test',
|
||||
(webServer, addrs, pkgName, pkgVersion) => {
|
||||
expect(webServer).toBeDefined();
|
||||
expect(addrs).toBeDefined();
|
||||
|
@ -27,8 +27,12 @@ describe('startServer via API', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should fails if config is missing', () => {
|
||||
expect(() => { return startServer() }).toThrow('config file must be an object');
|
||||
test('should fails if config is missing', async () => {
|
||||
try {
|
||||
await startServer();
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual('config file must be an object');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -33,9 +33,10 @@ let packages = [
|
|||
];
|
||||
|
||||
describe('search', () => {
|
||||
beforeAll(function() {
|
||||
beforeAll(async function() {
|
||||
let config = new Config(config_hash);
|
||||
this.storage = new Storage(config);
|
||||
await this.storage.init(config);
|
||||
Search.configureStorage(this.storage);
|
||||
packages.map(function(item) {
|
||||
Search.add(item);
|
||||
|
|
|
@ -13,22 +13,24 @@ import type {IStorageHandler} from '../../types';
|
|||
|
||||
setup(configExample.logs);
|
||||
|
||||
const generateStorage = function(): IStorageHandler {
|
||||
const generateStorage = async function() {
|
||||
const storageConfig = _.clone(configExample);
|
||||
const storage = `./unit/partials/store/test-storage-store.spec`;
|
||||
storageConfig.self_path = __dirname;
|
||||
storageConfig.storage = storage;
|
||||
const config: Config = new AppConfig(storageConfig);
|
||||
const store: IStorageHandler = new Storage(config);
|
||||
await store.init(config);
|
||||
|
||||
return new Storage(config);
|
||||
return store;
|
||||
}
|
||||
|
||||
describe('StorageTest', () => {
|
||||
|
||||
jest.setTimeout(10000);
|
||||
|
||||
beforeAll((done)=> {
|
||||
const storage: IStorageHandler = generateStorage();
|
||||
beforeAll(async (done)=> {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
var request = httpMocks.createRequest({
|
||||
method: 'GET',
|
||||
url: '/react',
|
||||
|
@ -50,14 +52,14 @@ describe('StorageTest', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should be defined', () => {
|
||||
const storage: IStorageHandler = generateStorage();
|
||||
test('should be defined', async () => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
expect(storage).toBeDefined();
|
||||
});
|
||||
|
||||
test('should fetch from uplink react metadata from nmpjs', (done) => {
|
||||
const storage: IStorageHandler = generateStorage();
|
||||
test('should fetch from uplink react metadata from nmpjs', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('react', null, {}, (err, metadata, errors) => {
|
||||
|
@ -66,8 +68,8 @@ describe('StorageTest', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should fails on fetch from uplink metadata from nmpjs', (done) => {
|
||||
const storage: IStorageHandler = generateStorage();
|
||||
test('should fails on fetch from uplink metadata from nmpjs', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('@verdaccio/404', null, {}, (err, metadata, errors) => {
|
||||
|
|
|
@ -79,6 +79,7 @@ export interface IStorageHandler {
|
|||
logger: Logger;
|
||||
uplinks: ProxyList;
|
||||
addPackage(name: string, metadata: any, callback: Function): void;
|
||||
init(config: Config): Promise<any>;
|
||||
addVersion(name: string, version: string, metadata: Version, tag: StringValue, callback: Callback): void;
|
||||
mergeTags(name: string, tagHash: MergeTags, callback: Callback): void;
|
||||
replaceTags(name: string, tagHash: MergeTags, callback: Callback): void;
|
||||
|
@ -110,6 +111,7 @@ export interface IStorage {
|
|||
getTarball(name: string, filename: string): IReadTarball;
|
||||
getPackageMetadata(name: string, callback: Callback): void;
|
||||
search(startKey: string, options: any): IUploadTarball;
|
||||
getSecret(config: Config): Promise<any>;
|
||||
}
|
||||
|
||||
export type $RequestExtend = $Request & {remote_user?: any}
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -227,9 +227,9 @@
|
|||
lockfile "1.0.3"
|
||||
lodash "4.17.4"
|
||||
|
||||
"@verdaccio/local-storage@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/local-storage/-/local-storage-1.0.1.tgz#eb5d3a5e035d302ecf756b68eee7f3c48f32ca88"
|
||||
"@verdaccio/local-storage@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/local-storage/-/local-storage-1.0.2.tgz#3cdc2b27ce0496787f0ca36560b8a34b4959164e"
|
||||
dependencies:
|
||||
"@verdaccio/file-locking" "0.0.5"
|
||||
"@verdaccio/streams" "1.0.0"
|
||||
|
@ -242,9 +242,9 @@
|
|||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/streams/-/streams-1.0.0.tgz#d5d24c6747208728b9fd16b908e3932c3fb1f864"
|
||||
|
||||
"@verdaccio/types@2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/types/-/types-2.1.0.tgz#1a0b330f96bc63fbc87391c2b5c625fd3be5da84"
|
||||
"@verdaccio/types@2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/types/-/types-2.2.0.tgz#4d931867b0f02e2e939beedcb8a44a60d02e62ce"
|
||||
|
||||
JSONStream@1.3.2, JSONStream@^1.0.4:
|
||||
version "1.3.2"
|
||||
|
|
Loading…
Add table
Reference in a new issue