0
Fork 0
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:
Juan Picado @jotadeveloper 2018-04-21 18:36:06 +02:00
parent df418a8ecb
commit e5caa71d35
No known key found for this signature in database
GPG key ID: 18AC54485952D158
15 changed files with 84 additions and 76 deletions

View file

@ -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",

View file

@ -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
View file

@ -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) {

View file

@ -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,

View file

@ -208,7 +208,7 @@ class Config {
* @return {String}
*/
checkSecretKey(secret) {
if (_.isNil(secret) === false && secret !== '') {
if (_.isString(secret) && secret !== '') {
this.secret = secret;
return secret;
}

View file

@ -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) {

View file

@ -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);
}
/**

View file

@ -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();
});
});

View file

@ -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();
});
});

View file

@ -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;

View file

@ -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');
}
});
});

View file

@ -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);

View file

@ -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) => {

View file

@ -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}

View file

@ -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"