diff --git a/lib/auth.js b/lib/auth.js index 013f8d774..7a87e5446 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -157,7 +157,7 @@ class Auth { allow_access(package_name, user, callback) { let plugins = this.plugins.slice(0); let pkg = Object.assign({name: package_name}, - this.config.get_package_spec(package_name)) + this.config.getMatchedPackagesSpec(package_name)) ;(function next() { let p = plugins.shift(); @@ -183,7 +183,7 @@ class Auth { allow_publish(package_name, user, callback) { let plugins = this.plugins.slice(0); let pkg = Object.assign({name: package_name}, - this.config.get_package_spec(package_name)) + this.config.getMatchedPackagesSpec(package_name)) ;(function next() { let p = plugins.shift(); diff --git a/lib/config.js b/lib/config.js index dd981f3a3..51ccd1313 100644 --- a/lib/config.js +++ b/lib/config.js @@ -8,6 +8,7 @@ const _ = require('lodash'); const Error = require('http-errors'); const Crypto = require('crypto'); const minimatch = require('minimatch'); + const Utils = require('./utils'); const pkginfo = require('pkginfo')(module); // eslint-disable-line no-unused-vars const pkgVersion = module.exports.version; @@ -30,50 +31,12 @@ function flatten(array) { return result; } -const parse_interval_table = { - '': 1000, - 'ms': 1, - 's': 1000, - 'm': 60*1000, - 'h': 60*60*1000, - 'd': 86400000, - 'w': 7*86400000, - 'M': 30*86400000, - 'y': 365*86400000, -}; - -/** - * Parse an internal string to number - * @param {*} interval - * @return {Number} - */ -function parse_interval(interval) { - if (typeof(interval) === 'number') { - return interval * 1000; - } - let result = 0; - let last_suffix = Infinity; - interval.split(/\s+/).forEach(function(x) { - if (!x) return; - let m = x.match(/^((0|[1-9][0-9]*)(\.[0-9]+)?)(ms|s|m|h|d|w|M|y|)$/); - if (!m - || parse_interval_table[m[4]] >= last_suffix - || (m[4] === '' && last_suffix !== Infinity)) { - throw Error('invalid interval: ' + interval); - } - last_suffix = parse_interval_table[m[4]]; - result += Number(m[1]) * parse_interval_table[m[4]]; - }); - return result; -} - /** * Coordinates the application configuration */ class Config { /** - * Constructor * @param {*} config config the content */ constructor(config) { @@ -214,23 +177,25 @@ class Config { /** * Check whether an uplink can proxy - * @param {*} pkg - * @param {*} uplink + * @param {String} pkg package anem + * @param {*} upLink * @return {Boolean} */ - can_proxy_to(pkg, uplink) { - return (this.get_package_spec(pkg).proxy || []).reduce(function(prev, curr) { - if (uplink === curr) return true; + hasProxyTo(pkg, upLink) { + return (this.getMatchedPackagesSpec(pkg).proxy || []).reduce(function(prev, curr) { + if (upLink === curr) { + return true; + } return prev; }, false); } /** * Check for package spec - * @param {*} pkg + * @param {String} pkg package name * @return {Object} */ - get_package_spec(pkg) { + getMatchedPackagesSpec(pkg) { for (let i in this.packages) { if (minimatch.makeRe(i).exec(pkg)) { return this.packages[i]; @@ -257,4 +222,3 @@ class Config { } module.exports = Config; -module.exports.parse_interval = parse_interval; diff --git a/lib/storage.js b/lib/storage.js index 6b82e32ae..6c73260ed 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -8,10 +8,10 @@ const semver = require('semver'); const Stream = require('stream'); const Search = require('./search'); -const LocalStorage = require('./local-storage'); +const LocalStorage = require('./storage/local/local-storage'); const Logger = require('./logger'); -const MyStreams = require('./streams'); -const Proxy = require('./up-storage'); +const MyStreams = require('./storage/streams'); +const Proxy = require('./storage/up-storage'); const Utils = require('./utils'); /** @@ -67,7 +67,7 @@ class Storage { * Check whether a package exist in any of the uplinks. * @return {Promise} */ - const check_package_remote = () => { + const checkPackageRemote = () => { return new Promise((resolve, reject) => { self._sync_package_with_uplinks(name, null, {}, (err, results, err_results) => { // something weird @@ -97,7 +97,7 @@ class Storage { * Add a package to the local database * @return {Promise} */ - const publish_package = () => { + const publishPackage = () => { return new Promise((resolve, reject) => { self.localStorage.addPackage(name, metadata, (err, latest) => { if (!_.isNull(err)) { @@ -116,8 +116,8 @@ class Storage { // so all requests are necessary checkPackageLocal() .then(() => { - return check_package_remote().then(() => { - return publish_package().then(() => { + return checkPackageRemote().then(() => { + return publishPackage().then(() => { callback(); }, (err) => callback(err)); }, (err) => callback(err)); @@ -499,7 +499,7 @@ class Storage { let uplinks = []; for (let i in self.uplinks) { - if (self.config.can_proxy_to(name, i)) { + if (self.config.hasProxyTo(name, i)) { uplinks.push(self.uplinks[i]); } } diff --git a/lib/local-data.js b/lib/storage/local/local-data.js similarity index 100% rename from lib/local-data.js rename to lib/storage/local/local-data.js diff --git a/lib/local-fs.js b/lib/storage/local/local-fs.js similarity index 98% rename from lib/local-fs.js rename to lib/storage/local/local-fs.js index 3301e3772..0cff425b0 100644 --- a/lib/local-fs.js +++ b/lib/storage/local/local-fs.js @@ -6,8 +6,8 @@ const fs = require('fs'); const path = require('path'); const createError = require('http-errors'); const mkdirp = require('mkdirp'); -const MyStream = require('./streams'); -const locker = require('./file-locking'); +const MyStream = require('../streams'); +const locker = require('../../file-locking'); const fileExist = 'EEXISTS'; const noSuchFile = 'ENOENT'; diff --git a/lib/local-storage.js b/lib/storage/local/local-storage.js similarity index 96% rename from lib/local-storage.js rename to lib/storage/local/local-storage.js index eef9207a1..3c56555de 100644 --- a/lib/local-storage.js +++ b/lib/storage/local/local-storage.js @@ -1,29 +1,29 @@ /* eslint prefer-rest-params: "off" */ /* eslint prefer-spread: "off" */ 'use strict'; + const assert = require('assert'); const Crypto = require('crypto'); const fs = require('fs'); const Path = require('path'); const Stream = require('stream'); const url = require('url'); - const async = require('async'); const createError = require('http-errors'); const _ = require('lodash'); const fsStorage = require('./local-fs'); const LocalData = require('./local-data'); -const Logger = require('./logger'); -const customStream = require('./streams'); -const Utils = require('./utils'); +const Logger = require('../../logger'); +const customStream = require('../streams'); +const Utils = require('../../utils'); + const pkgFileName = 'package.json'; const fileExist = 'EEXISTS'; const noSuchFile = 'ENOENT'; const resourceNotAvailable = 'EAGAIN'; -// returns the minimal package file -const get_boilerplate = function(name) { +const generatePackageTemplate = function(name) { return { // standard things 'name': name, @@ -47,15 +47,24 @@ class LocalStorage { */ constructor(config) { this.config = config; - // local data handler is linked with the configuration handler - this.localList = new LocalData(Path.join(Path.resolve(Path.dirname(config.self_path || ''), config.storage), - // FUTURE: the database might be parameterizable from config.yaml - '.sinopia-db.json' - ) - ); + this.localList = new LocalData(this._buildStoragePath(this.config)); this.logger = Logger.logger.child({sub: 'fs'}); } + /** + * Build the local database path. + * @param {Object} config + * @return {string|String|*} + * @private + */ + _buildStoragePath(config) { + // FUTURE: the database might be parameterizable from config.yaml + return Path.join(Path.resolve(Path.dirname(config.self_path || ''), + config.storage, + '.sinopia-db.json' + )); + } + /** * Add a package. @@ -66,11 +75,12 @@ class LocalStorage { */ addPackage(name, info, callback) { const storage = this.storage(name); + if (!storage) { return callback( createError(404, 'this package cannot be added')); } - storage.createJSON(pkgFileName, get_boilerplate(name), function(err) { + storage.createJSON(pkgFileName, generatePackageTemplate(name), function(err) { if (err && err.code === fileExist) { return callback( createError(409, 'this package is already present')); } @@ -607,7 +617,7 @@ class LocalStorage { * @return {Object} */ storage(pkg) { - let path = this.config.get_package_spec(pkg).storage; + let path = this.config.getMatchedPackagesSpec(pkg).storage; if (_.isNil(path)) { path = this.config.storage; } @@ -709,7 +719,7 @@ class LocalStorage { _readCreatePackage(name, callback) { const storage = this.storage(name); if (!storage) { - const data = get_boilerplate(name); + const data = generatePackageTemplate(name); this._normalizePackage(data); return callback(null, data); } @@ -718,7 +728,7 @@ class LocalStorage { if (err) { if (err.code === noSuchFile) { // if package doesn't exist, we create it here - data = get_boilerplate(name); + data = generatePackageTemplate(name); } else { return callback(this._internalError(err, pkgFileName, 'error reading')); } diff --git a/lib/streams.js b/lib/storage/streams.js similarity index 100% rename from lib/streams.js rename to lib/storage/streams.js diff --git a/lib/up-storage.js b/lib/storage/up-storage.js similarity index 97% rename from lib/up-storage.js rename to lib/storage/up-storage.js index 0dc397d30..aa77e3615 100644 --- a/lib/up-storage.js +++ b/lib/storage/up-storage.js @@ -6,10 +6,9 @@ const _ = require('lodash'); const request = require('request'); const Stream = require('stream'); const URL = require('url'); -const parseInterval = require('./config').parse_interval; -const Logger = require('./logger'); +const Logger = require('../logger'); const MyStreams = require('./streams'); -const Utils = require('./utils'); +const Utils = require('../utils'); const zlib = require('zlib'); const encode = function(thing) { return encodeURIComponent(thing).replace(/^%40/, '@'); @@ -58,10 +57,10 @@ class ProxyStorage { } // a bunch of different configurable timers - this.maxage = parseInterval(setConfig(this.config, 'maxage', '2m' )); - this.timeout = parseInterval(setConfig(this.config, 'timeout', '30s')); + this.maxage = Utils.parseInterval(setConfig(this.config, 'maxage', '2m' )); + this.timeout = Utils.parseInterval(setConfig(this.config, 'timeout', '30s')); this.max_fails = Number(setConfig(this.config, 'max_fails', 2 )); - this.fail_timeout = parseInterval(setConfig(this.config, 'fail_timeout', '5m' )); + this.fail_timeout = Utils.parseInterval(setConfig(this.config, 'fail_timeout', '5m' )); } /** diff --git a/lib/utils.js b/lib/utils.js index e3211ff1f..8565f7c67 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -277,6 +277,44 @@ function normalize_dist_tags(data) { } } +const parseIntervalTable = { + '': 1000, + 'ms': 1, + 's': 1000, + 'm': 60*1000, + 'h': 60*60*1000, + 'd': 86400000, + 'w': 7*86400000, + 'M': 30*86400000, + 'y': 365*86400000, +}; + +/** + * Parse an internal string to number + * @param {*} interval + * @return {Number} + */ +function parseInterval(interval) { + if (typeof(interval) === 'number') { + return interval * 1000; + } + let result = 0; + let last_suffix = Infinity; + interval.split(/\s+/).forEach(function(x) { + if (!x) return; + let m = x.match(/^((0|[1-9][0-9]*)(\.[0-9]+)?)(ms|s|m|h|d|w|M|y|)$/); + if (!m + || parseIntervalTable[m[4]] >= last_suffix + || (m[4] === '' && last_suffix !== Infinity)) { + throw Error('invalid interval: ' + interval); + } + last_suffix = parseIntervalTable[m[4]]; + result += Number(m[1]) * parseIntervalTable[m[4]]; + }); + return result; +} + +module.exports.parseInterval = parseInterval; module.exports.semver_sort = semverSort; module.exports.parse_address = parse_address; module.exports.get_version = get_version; diff --git a/test/unit/mystreams.js b/test/unit/mystreams.js index 40f51e5dd..68dc7c923 100644 --- a/test/unit/mystreams.js +++ b/test/unit/mystreams.js @@ -1,6 +1,6 @@ 'use strict'; -let ReadTarball = require('../../lib/streams').ReadTarball; +let ReadTarball = require('../../lib/storage/streams').ReadTarball; describe('mystreams', function() { it('should delay events', function(cb) { diff --git a/test/unit/no_proxy.js b/test/unit/no_proxy.js index d86ccfb65..38cb972d9 100644 --- a/test/unit/no_proxy.js +++ b/test/unit/no_proxy.js @@ -1,7 +1,7 @@ 'use strict'; let assert = require('assert'); -let Storage = require('../../lib/up-storage'); +let Storage = require('../../lib/storage/up-storage'); require('../../lib/logger').setup([]); diff --git a/test/unit/parse_interval.js b/test/unit/parse_interval.js index c0567be4a..61ecf45c1 100644 --- a/test/unit/parse_interval.js +++ b/test/unit/parse_interval.js @@ -1,17 +1,17 @@ 'use strict'; let assert = require('assert'); -let parse_interval = require('../../lib/config').parse_interval; +let parseInterval = require('../../lib/utils').parseInterval; describe('Parse interval', function() { function add_test(str, res) { it('parse ' + str, function() { if (res === null) { assert.throws(function() { - console.log(parse_interval(str)); + console.log(parseInterval(str)); }); } else { - assert.strictEqual(parse_interval(str), res); + assert.strictEqual(parseInterval(str), res); } }); }