.github/000077500000000000000000000000001516075465100124305ustar00rootroot00000000000000.github/workflows/000077500000000000000000000000001516075465100144655ustar00rootroot00000000000000.github/workflows/build.yml000066400000000000000000000016761516075465100163210ustar00rootroot00000000000000# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: build on: schedule: - cron: '0 0 1 * *' push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: ['lts/*'] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm i -g grunt-cli - run: npm install - run: grunt .gitignore000066400000000000000000000003301516075465100130540ustar00rootroot00000000000000/build /node_modules /*.log .idea/workspace.xml .idea/tasks.xml .idea/profiles_settings.xml .idea/inspectionProfiles/Project_Default.xml .idea/inspectionProfiles/profiles_settings.xml node_modules/.yarn-integrity .npmignore000066400000000000000000000002421516075465100130650ustar00rootroot00000000000000/.idea /artifacts /build /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /*.lock *.log /corifeus-boot.json /.github /.vscodeGruntfile.js000066400000000000000000000004201516075465100133610ustar00rootroot00000000000000module.exports = (grunt) => { const builder = require(`corifeus-builder`); const loader = new builder.loader(grunt); loader.js({ replacer: { npmio: true } }); grunt.registerTask('default', builder.config.task.build.js); } LICENSE000066400000000000000000000022721516075465100121000ustar00rootroot00000000000000 @license corifeus-utils v2023.10.135 ❤️ Corifeus Utils https://corifeus.com/corifeus-utils Copyright (c) 2023 Patrik Laszlo / P3X / Corifeus and contributors. MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README.md000066400000000000000000000100671516075465100123530ustar00rootroot00000000000000[//]: #@corifeus-header [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://paypal.me/patrikx3) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Corifeus @ Facebook](https://img.shields.io/badge/Facebook-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [![Build Status](https://github.com/patrikx3/corifeus-utils/workflows/build/badge.svg)](https://github.com/patrikx3/corifeus-utils/actions?query=workflow%3Abuild) [![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m780749701-41bcade28c1ea8154eda7cca.svg)](https://stats.uptimerobot.com/9ggnzcWrw) [![NPM](https://nodei.co/npm/corifeus-utils.png?downloads=true&downloadRank=true)](https://www.npmjs.com/package/corifeus-utils/) --- # ❤️ Corifeus Utils v2023.10.135 **Bugs are evident™ - MATRIX️** ### NodeJS LTS is supported ### Built on NodeJs version ```txt v20.5.0 ``` # Description [//]: #@corifeus-header:end Misc utils (async array iterator, random characters, exit on silent ```unhandledRejection``` errors, etc...) ```js const utils = require('corifeus-utils'); ``` * Modules * Async Array Iterator ```forEachAsync``` * ```JSON.strintify``` for ```Error``` * Lodash Pascal * Lodash patch to work `_.isEmpty` with `Symbols` * Remove silent process ```unhandledRejection``` end ```process.exit()```, adds timestamp * Process ```uncaughtException``` that shows timestamp. * Random async Base62 string * Replace inject - finds a prefix and postfix in a string and replace the content, ```strings.inject``` * Convert a byte array or string to base62, ```utils.base.charset(string)``` * Async Hash (SHA-512, SHA-256) file using Base62, * Promise based HTTP Request * Time utilies * Additional file system utils * JSON based file database * HTTP/HTTPS based async/Promise request # Actual modules Everything is promise based. * time * verbose * span * regexp * escape * random * async (default is base62) * complexUuid * promise * deferred (simple extract the reject, resolve and promise function, instead of callback) * process * unhandledRejection * uncaughtException * writableCallbackExit * object * reduce * hash * async file * string * padStart * empty * inject * lodash * PascalCase * isEmpty * http * async request * db * file based json storage * child-process * async exec * array * forEachAsync, async/await for each * network * isPortReachable * makeRange * getPort * fs * ensureFile * ensureDir * find * ensureTempFile * tempFileName * readdirRecursive * createWriteStream * crypto * encrypt * decrypt * error * default `Error` has `toJSON` method * timer [//]: #@corifeus-footer --- 🙏 This is an open-source project. Star this repository, if you like it, or even donate to maintain the servers and the development. Thank you so much! Possible, this server, rarely, is down, please, hang on for 15-30 minutes and the server will be back up. All my domains ([patrikx3.com](https://patrikx3.com) and [corifeus.com](https://corifeus.com)) could have minor errors, since I am developing in my free time. However, it is usually stable. **Note about versioning:** Versions are cut in Major.Minor.Patch schema. Major is always the current year. Minor is either 4 (January - June) or 10 (July - December). Patch is incremental by every build. If there is a breaking change, it should be noted in the readme. --- [**CORIFEUS-UTILS**](https://corifeus.com/corifeus-utils) Build v2023.10.135 [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZVM4V6HVZJW6) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Like Corifeus @ Facebook](https://img.shields.io/badge/LIKE-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [//]: #@corifeus-footer:end package.json000066400000000000000000000025621516075465100133630ustar00rootroot00000000000000{ "name": "corifeus-utils", "version": "2023.10.135", "corifeus": { "icon": "far fa-lightbulb", "code": "Memory", "publish": true, "nodejs": "v20.5.0", "reponame": "corifeus-utils", "opencollective": false, "build": true }, "description": "❤️ Corifeus Utils", "main": "src/index.js", "directories": { "test": "test" }, "scripts": { "test": "grunt", "coverage": "istanbul cover node_modules/mocha/bin/_mocha --report clover -- -R spec test/mocha/**/*.js" }, "repository": { "type": "git", "url": "git+https://github.com/patrikx3/corifeus-utils.git" }, "keywords": [ "corifeus", "nodejs", "node", "utils" ], "author": "Patrik Laszlo ", "license": "MIT", "bugs": { "url": "https://github.com/patrikx3/corifeus-utils/issues" }, "homepage": "https://corifeus.com/corifeus-utils", "devDependencies": { "corifeus-builder": "^2023.10.135", "istanbul": "^0.4.5" }, "peerDependencies": { "lodash": "^4.17.21" }, "dependencies": { "fs-extra": "^11.1.1", "ms": "^2.1.3", "mz": "^2.7.0", "timestring": "^7.0.0", "uuid": "^9.0.0" }, "engines": { "node": ">=12.13.0" } }src/000077500000000000000000000000001516075465100116575ustar00rootroot00000000000000src/array/000077500000000000000000000000001516075465100127755ustar00rootroot00000000000000src/array/for-each-async.js000066400000000000000000000013331516075465100161320ustar00rootroot00000000000000const forEachAsync = (array, cb, serial = false) => { const promises = []; let lastCb; for (let index = 0; index < array.length; index++) { const item = array[index]; const call = () => { cb(item, index) } if (serial) { if (lastCb === undefined) { lastCb = cb(item, index) } else { lastCb = lastCb.then(() => cb(item, index)); } } else { promises.push(cb(item, index)) } } if (serial) { return lastCb; } else { const result = Promise.all(promises); result.promises = promises; return result; } } module.exports = forEachAsync; src/array/index.js000066400000000000000000000007751516075465100144530ustar00rootroot00000000000000module.exports.forEachAsync = require('./for-each-async'); module.exports.isfy = (input) => { const args = Array.prototype.slice.call(input); return args.sort(); } if (!Array.prototype.forEachAsync) { const forEachAsync = module.exports.forEachAsync; Object.defineProperty(Array.prototype, 'forEachAsync', { enumerable: false, writable: true, value: function (callback, serial = false) { return forEachAsync(this, callback, serial); } }); } src/base.js000066400000000000000000000011721516075465100131300ustar00rootroot00000000000000const base62Charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const base36Charset = 'abcdefghijklmnopqrstuvwxyz0123456789'; module.exports.base36Charset = base36Charset; module.exports.base62Charset = base62Charset; module.exports.charset = (bytes, charset = base62Charset) => { let string = '' for (let index = 0; index < bytes.length; index++) { const byte = bytes[index]; const percent = (100 / 256 * byte) / 100; const charIndex = Math.floor(charset.length * percent); const char = charset.charAt(charIndex) string += char; } return string; } src/child-process/000077500000000000000000000000001516075465100144165ustar00rootroot00000000000000src/child-process/index.js000066400000000000000000000015571516075465100160730ustar00rootroot00000000000000const childProcess = require('child_process'); const promiseUtil = require('../promise'); module.exports.exec = (command, options) => { if (options === true) { options = { display: true } } options = options || {}; options.stdio = options.stdio || 'inherit'; options.stdin = options.stdin || 'inherit'; options.display = options.display || false; const {resolve, reject, promise} = promiseUtil.deferred(); const run = childProcess.exec(command, options, (err, stdout, stderr) => { if (err) { reject(err); return; } resolve({ stdout: stdout, stderr: stderr, }) }) if (options.display === true) { run.stdout.pipe(process.stdout) run.stderr.pipe(process.stderr) } promise.exec = run; return promise } src/crypto.js000066400000000000000000000027541516075465100135450ustar00rootroot00000000000000const crypto = require('crypto'); const defaultAlgorithm = 'aes256'; const encrypt = (options) => { return new Promise((resolve, reject) => { const {data, pass} = options; let {algorithm} = options; if (algorithm === undefined) { algorithm = defaultAlgorithm; } const cipher = crypto.createCipheriv(algorithm, pass) let encrypted = ''; cipher.on('readable', () => { const ondata = cipher.read(); if (ondata) { encrypted += ondata.toString('hex'); } }); cipher.on('end', () => { resolve(encrypted); }); cipher.write(data); cipher.end(); }) } const decrypt = (options) => { return new Promise((resolve, reject) => { const {data, pass} = options; let {algorithm} = options; if (algorithm === undefined) { algorithm = defaultAlgorithm; } const iv = Buffer.alloc(16, 0); const decipher = crypto.createDecipheriv(algorithm, pass, iv) let decrypted = ''; decipher.on('readable', () => { const ondata = decipher.read(); if (ondata) { decrypted += ondata.toString('utf8'); } }); decipher.on('end', () => { resolve(decrypted); }); decipher.write(data, 'hex'); decipher.end(); }) } module.exports.encrypt = encrypt; module.exports.decrypt = decrypt; src/db/000077500000000000000000000000001516075465100122445ustar00rootroot00000000000000src/db/index.js000066400000000000000000000027651516075465100137230ustar00rootroot00000000000000const coryFs = require('../fs'); const mz = require('mz'); const load = async (dbFile, data = {}) => { const exists = await coryFs.ensureFile(dbFile, data) if (exists) { data = await mz.fs.readFile(dbFile); } data = JSON.parse(data.toString()); return new db(dbFile, data); } const db = function (dbFile, data) { const getTime = () => { return Date.now(); } if (!data.hasOwnProperty('_createdAt')) { data._createdAt = getTime(); data._updatedAt = getTime(); } Object.defineProperty(this, 'raw', { get: () => { return data; } }) this.exists = function (entity, key) { if (!data.hasOwnProperty(entity)) { return false; } if (!data[entity].hasOwnProperty(key)) { return false; } return true; } this.save = function (entity, key, saveData) { if (!data.hasOwnProperty(entity)) { data[entity] = {}; } if (data[entity].hasOwnProperty(key)) { saveData._updatedAt = getTime(); data[entity][key] = Object.assign(data[entity][key], saveData); } else { saveData._createdAt = getTime(); saveData._updatedAt = getTime(); data[entity][key] = saveData; } } this.write = async function () { data._updatedAt = getTime(); await mz.fs.writeFile(dbFile, JSON.stringify(data, null, 4)); } } module.exports.load = load; src/error.js000066400000000000000000000005701516075465100133500ustar00rootroot00000000000000if (!('toJSON' in Error.prototype)) { Object.defineProperty(Error.prototype, 'toJSON', { value: function () { const alt = {}; Object.getOwnPropertyNames(this).forEach(function (key) { alt[key] = this[key]; }, this); return alt; }, configurable: true, writable: true }); }src/fs/000077500000000000000000000000001516075465100122675ustar00rootroot00000000000000src/fs/find.js000066400000000000000000000053771516075465100135610ustar00rootroot00000000000000const path = require('path'); const mz = require('mz'); const multi = async (options) => { await options.find.forEachAsync(async (findable) => { const resolved = path.resolve(options.root, findable); const finds = await mz.fs.exists(resolved); if (finds) { const stat = await mz.fs.stat(resolved); if ( (options.type.hasOwnProperty('d') && stat.isDirectory()) || (options.type.hasOwnProperty('f') && stat.isFile()) ) { options.results.push({ path: resolved, dir: stat.isFile() ? path.dirname(resolved) : resolved, // stat: stat }); } } const foundHit = await mz.fs.readdir(options.root) const foundHitPromises = []; await foundHit.forEachAsync(async (foundDir) => { const resolvedFoundDir = path.resolve(options.root, foundDir); const stat = await mz.fs.stat(resolvedFoundDir); if (!stat.isDirectory()) { return; } if (options.find.includes(foundDir) || options.exclude.includes(foundDir)) { return; } const newOptions = Object.assign({}, options) newOptions.root = resolvedFoundDir; foundHitPromises.push(multi(newOptions)) }) await Promise.all(foundHitPromises); }) return options.results; } module.exports = async (options) => { if (typeof options === 'string') { options = { find: options } } options.root = options.root || process.cwd(); options.results = options.results || []; options.type = options.type || { d: true, f: true, }; if (!Array.isArray(options.find)) { options.find = [options.find]; } options.find = options.find.map(findable => { findable = findable.trim(); if (findable.startsWith('./')) { findable = findable.substr(2); } if (findable.endsWith('/')) { findable = findable.substr(0, findable.length - 1); } return findable; }) if (!options.exclude) { options.exclude = []; const excluder = (path) => { if (!options.find.includes(path)) { options.exclude.push(path); } } excluder('node_modules') excluder('bower_components') excluder('vendor') excluder('dist') excluder('build') excluder('build-modules') excluder('release') } if (options.dry || options.debug) { console.log(`Options: ${JSON.stringify(options, null, 4)}`) } return await multi(options); }; src/fs/index.js000066400000000000000000000036741516075465100137460ustar00rootroot00000000000000const fs = require('fs'); const mz = require('mz'); const path = require('path'); const fsExtra = require('fs-extra'); const os = require('os'); const tmp = os.tmpdir(); const random = require('../random'); const ensureDir = async (dir) => { const exists = await mz.fs.exists(dir); if (exists) { return; } await fsExtra.ensureDir(dir); } const ensureFile = async (file, defaultData = '', alwaysWrite = false) => { const exists = await mz.fs.exists(file); if (exists && !alwaysWrite) { return true; } if (typeof (defaultData) === 'object') { defaultData = JSON.stringify(defaultData); } await fsExtra.ensureDir(path.dirname(file)); await mz.fs.writeFile(file, defaultData) return false; } const createWriteStream = (filename) => { const stream = fs.createWriteStream(filename); const promise = new Promise((resolve, reject) => { stream.on('finish', async () => { resolve(); }); stream.on('error', (error) => { reject(error); }); }) promise.stream = stream; return promise; } const tempFileName = async (extension = 'tmp') => { const randomFile = 'tmp-' + Date.now() + '-' + await random.lower(); const randomFileFinal = `${tmp}/${randomFile}.${extension}` if (await mz.fs.exists(randomFileFinal)) { return await tempFileName(extension); } return randomFileFinal; } const ensureTempFile = async (data, extension = 'tmp') => { const randomFileFinal = await tempFileName(extension); await mz.fs.writeFile(randomFileFinal, data); return randomFileFinal; } module.exports.ensureFile = ensureFile; module.exports.ensureDir = ensureDir; module.exports.find = require('./find'); module.exports.ensureTempFile = ensureTempFile; module.exports.tempFileName = tempFileName; module.exports.readdirRecursive = require('./readdir-recursive') module.exports.createWriteStream = createWriteStream; src/fs/readdir-recursive.js000066400000000000000000000041451516075465100162500ustar00rootroot00000000000000const fs = require('fs'); const path = require('path'); function readdirRecursive(startDir) { let readDirQueue = [], fileList = []; function readDir(dir) { function getItemList(readDir) { return new Promise((resolve, reject) => { fs.readdir(readDir, (err, itemList) => { if (err) { return reject(); } // resolve with parent path added to each item resolve(itemList.map((item) => path.resolve(readDir, item))); }); }); } function getItemListStat(itemList) { function getStat(itemPath) { return new Promise((resolve, reject) => { fs.stat(itemPath, (err, stat) => { if (err) { return reject(); } // resolve with item path and if directory resolve({itemPath, isDirectory: stat.isDirectory()}); }); }); } // stat all items in list return Promise.all(itemList.map(getStat)); } function processItemList(itemList) { for (let {itemPath, isDirectory} of itemList) { // if directory add to queue if (isDirectory) { readDirQueue.push(itemPath); continue; } // add file to list fileList.push(itemPath); } // if queue, process next item recursive if (readDirQueue.length > 0) { return readDir(readDirQueue.shift()); } // finished - return file list return fileList; } // read item list from directory, stat each item then walk result return getItemList(dir) .then(getItemListStat) .then(processItemList); } // commence reading at the top return readDir(startDir); } module.exports = readdirRecursive src/hash.js000066400000000000000000000013531516075465100131420ustar00rootroot00000000000000const fs = require('fs'); const crypto = require('crypto'); const fileHash = async (file, cryptoName = 'sha256') => { return new Promise((resolve, reject) => { const fstream = fs.createReadStream(file); const hash = crypto.createHash(cryptoName); fstream.on('error', reject); fstream.on('end', function () { hash.end(); const bytes = hash.read(); const string = require('./base').charset(bytes) resolve(string); }); fstream.pipe(hash); }) } const stringHash = (string, cryptoName = 'sha256') => { return crypto.createHash(cryptoName).update(string).digest("hex"); } module.exports.string = stringHash; module.exports.file = fileHash; src/http/000077500000000000000000000000001516075465100126365ustar00rootroot00000000000000src/http/index.js000066400000000000000000000000571516075465100143050ustar00rootroot00000000000000module.exports.request = require('./request'); src/http/request.js000066400000000000000000000102771516075465100146730ustar00rootroot00000000000000const url = require('url'); const coryRequest = (options) => { if (typeof (options) === 'string') { options = { url: options, } } const originalOptions = Object.assign({}, options) /* https://nodejs.org/api/http.html#http_http_request_options_callback */ const parsedUrl = url.parse(options.url); let request; if (parsedUrl.protocol === 'https:') { request = require('https').request; if (parsedUrl.port === null) { parsedUrl.port = 443; } } else if (parsedUrl.protocol === 'http:') { request = require('http').request; if (parsedUrl.port === null) { parsedUrl.port = 80; } } else { throw new Error(`Unknown protocol ${parsedUrl.protocol}`); } options.protocol = parsedUrl.protocol; options.port = parsedUrl.port; options.host = parsedUrl.host; options.hostname = parsedUrl.hostname; options.path = parsedUrl.path; let body; options.headers = options.headers || {}; if (options.body !== undefined) { if (typeof (options.body) === 'object') { body = JSON.stringify(options.body); if (!options.headers.hasOwnProperty('Content-Type')) { options.headers['Content-Type'] = 'application/json; charset=utf-8' options.headers['Content-Length'] = Buffer.byteLength(body) } } } if (!options.headers.hasOwnProperty('User-Agent')) { options.headers['User-Agent'] = 'Corifeus-Utils-Request BOT'; } if (!options.hasOwnProperty('method')) { options.method = 'GET'; } const urlParsed = new url.URL(options.url) /* console.log(!options.headers.hasOwnProperty('Authorization')) console.log(!options.headers.hasOwnProperty('authorization')) console.log(urlParsed.username ) console.log(urlParsed.password) */ if ((!options.headers.hasOwnProperty('Authorization') || !options.headers.hasOwnProperty('authorization')) && (urlParsed.username !== '' || urlParsed.password !== '')) { const auth = `Basic ${Buffer.from((urlParsed.username || '') + ':' + (urlParsed.password || '')).toString('base64')}`; options.headers['Authorization'] = auth; } /* console.log(urlParsed) console.log(options) */ const promise = new Promise((resolve, reject) => { try { const req = request(options, (response) => { if (response.headers.hasOwnProperty('location')) { req.end(); originalOptions.url = response.headers.location; return resolve(coryRequest(originalOptions)); } if (options.hasOwnProperty('pipe') && options.pipe === true) { resolve(response); return; } response.setEncoding('utf8'); let rawData = ''; response.on('data', (chunk) => { rawData += chunk; }); response.on('end', () => { try { if (response.headers.hasOwnProperty('content-type') && response.headers['content-type'].startsWith('application/json') && options.raw !== true) { if (typeof rawData !== 'undefined' && rawData !== '') { const parsedData = JSON.parse(rawData); response.body = parsedData; } else { response.body = {}; } } else { response.body = rawData; } resolve(response); } catch (e) { e.requestRawText = rawData reject(e); } }); }) req.on('error', reject); if (body !== undefined) { req.write(body); } req.end(); } catch (e) { console.error(e); reject(e); } }) return promise; } module.exports = coryRequest; src/index.js000066400000000000000000000024161516075465100133270ustar00rootroot00000000000000//const os = require('os'); //const process = require('process'); //const cores = os.cpus().length < 4 ? 4 : os.cpus().length; //process.env.UV_THREADPOOL_SIZE = cores; //console.debug(`Corifeus Utils sets UV_THREADPOOL_SIZE to ${cores} thread pool`) module.exports = { lodash: require('./lodash'), error: require('./error'), process: require('./process'), base: require('./base'), random: require('./random'), array: require('./array'), string: require('./string'), time: require('./time'), object: require('./object'), hash: require('./hash'), http: require('./http'), childProcess: require('./child-process'), promise: require('./promise'), fs: require('./fs'), db: require('./db'), regexp: require('./regexp'), json: require('./json'), require: require('./require'), timer: require('./timer'), input: require('./input'), network: require('./network'), redis: require('./redis'), crypto: require('./crypto'), snap: require('./snap'), } const repeat = (count, callback) => { return [...Array(count).keys()].forEach(callback); } repeat.async = async (count, callback, serial) => { return await [...Array(count).keys()].forEachAsync(callback, serial); } module.exports.repeat = repeat; src/input.js000066400000000000000000000006131516075465100133540ustar00rootroot00000000000000const readline = require('readline'); module.exports.key = async (msg = "Press for enter...") => { return new Promise((resolve, reject) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); rl.question(msg, function (answer) { resolve(answer); rl.close(); }) }) }src/json.js000066400000000000000000000005251516075465100131700ustar00rootroot00000000000000module.exports.clone = (obj) => { let cloneDeep try { cloneDeep = require('lodash/cloneDeep') } catch (e) { console.warn('corifeus-utils warn: looks like lodash is not in your dependencies') throw e } if (obj === null || obj === undefined) { return obj } return cloneDeep(obj); } src/lodash.js000066400000000000000000000012021516075465100134620ustar00rootroot00000000000000try { const _ = require('lodash'); _.mixin({'pascalCase': _.flow(_.camelCase, _.upperFirst)}); _.dotCase = (name) => { return _.snakeCase(name).replace(/_/g, '.'); } const originalIsEmpty = _.isEmpty _.isEmpty = (value) => { const originalResult = originalIsEmpty(value) if (originalResult && value) { const objectSymbols = Object.getOwnPropertySymbols(value); return objectSymbols.length === 0 } return originalResult } module.exports = _; } catch (e) { console.warn('corifeus-utils warn: looks like lodash is not in you dependecies') } src/network.js000066400000000000000000000137651516075465100137220ustar00rootroot00000000000000const utilsPromise = require('./promise'); module.exports.waitPort = async (options) => { let { port, host, retry, wait } = options if (port === undefined) { throw new Error(`${port} is undefined, please select a port like 25, 80 etc...`) } retry = retry || 8 wait = wait || 3000 host = host || '127.0.0.1'; let actualRetry = 0; const {reject, resolve, promise} = utilsPromise.deferred(); const checkPort = () => { actualRetry++; const net = require('net'); const server = net.createServer(); server.once('error', function (err) { if (err.code === 'EADDRINUSE') { // port is currently in use console.info(`Port ${port} in ${host} is opened`); server.close(); clearInterval(interval); resolve(); } }); server.once('listening', function () { // close the server if listening doesn't fail console.info(`Retry ${actualRetry}, Port ${port} in ${host} is not opened`); server.close(); if (actualRetry > retry) { reject(); } }); server.listen({ host: 'localhost', port: port, }); } const interval = setInterval(checkPort, wait) checkPort(); return promise; } module.exports.isPortReachable = async (port, {timeout = 1000, host} = {}) => { const net = require('net'); const promise = new Promise(((resolve, reject) => { const socket = new net.Socket(); const onError = () => { socket.destroy(); reject(); }; socket.setTimeout(timeout); socket.once('error', onError); socket.once('timeout', onError); socket.connect(port, host, () => { socket.end(); resolve(); }); })); try { await promise; return true; } catch (_) { return false; } }; 'use strict'; const net = require('net'); const os = require('os'); class Locked extends Error { constructor(port) { super(`${port} is locked`); } } const lockedPorts = { old: new Set(), young: new Set() }; // On this interval, the old locked ports are discarded, // the young locked ports are moved to old locked ports, // and a new young set for locked ports are created. const releaseOldLockedPortsIntervalMs = 1000 * 15; // Lazily create interval on first use let interval; const getLocalHosts = () => { const interfaces = os.networkInterfaces(); // Add undefined value for createServer function to use default host, // and default IPv4 host in case createServer defaults to IPv6. const results = new Set([undefined, '0.0.0.0']); for (const _interface of Object.values(interfaces)) { for (const config of _interface) { results.add(config.address); } } return results; }; const checkAvailablePort = options => new Promise((resolve, reject) => { const server = net.createServer(); server.unref(); server.on('error', reject); server.listen(options, () => { const {port} = server.address(); server.close(() => { resolve(port); }); }); }); const getAvailablePort = async (options, hosts) => { if (options.host || options.port === 0) { return checkAvailablePort(options); } for (const host of hosts) { try { await checkAvailablePort({port: options.port, host}); // eslint-disable-line no-await-in-loop } catch (error) { if (!['EADDRNOTAVAIL', 'EINVAL'].includes(error.code)) { throw error; } } } return options.port; }; const portCheckSequence = function * (ports) { if (ports) { yield * ports; } yield 0; // Fall back to 0 if anything else failed }; module.exports.getPort = async options => { let ports; if (options) { ports = typeof options.port === 'number' ? [options.port] : options.port; } if (interval === undefined) { interval = setInterval(() => { lockedPorts.old = lockedPorts.young; lockedPorts.young = new Set(); }, releaseOldLockedPortsIntervalMs); // Does not exist in some environments (Electron, Jest jsdom env, browser, etc). if (interval.unref) { interval.unref(); } } const hosts = getLocalHosts(); for (const port of portCheckSequence(ports)) { try { let availablePort = await getAvailablePort({...options, port}, hosts); // eslint-disable-line no-await-in-loop while (lockedPorts.old.has(availablePort) || lockedPorts.young.has(availablePort)) { if (port !== 0) { throw new Locked(port); } availablePort = await getAvailablePort({...options, port}, hosts); // eslint-disable-line no-await-in-loop } lockedPorts.young.add(availablePort); return availablePort; } catch (error) { if (!['EADDRINUSE', 'EACCES'].includes(error.code) && !(error instanceof Locked)) { throw error; } } } throw new Error('No available ports found'); }; module.exports.makeRange = (from, to) => { if (!Number.isInteger(from) || !Number.isInteger(to)) { throw new TypeError('`from` and `to` must be integer numbers'); } if (from < 1024 || from > 65535) { throw new RangeError('`from` must be between 1024 and 65535'); } if (to < 1024 || to > 65536) { throw new RangeError('`to` must be between 1024 and 65536'); } if (to < from) { throw new RangeError('`to` must be greater than or equal to `from`'); } const generator = function * (from, to) { for (let port = from; port <= to; port++) { yield port; } }; return generator(from, to); }; src/object.js000066400000000000000000000004511516075465100134630ustar00rootroot00000000000000module.exports.reduce = (obj, props = ['content'], length = 100) => { const reduced = Object.assign({}, obj); if (Array.isArray(props)) { props = [props]; } props.forEach((prop) => { reduced[prop] = reduced[prop].substring(0, length); }) return reduced; } src/process.js000066400000000000000000000012361516075465100136750ustar00rootroot00000000000000process.on("unhandledRejection", (err, promise) => { if (process.listeners('unhandledRejection').length > 1) { return; } console.error(new Date().toLocaleString(), 'unhandledRejection', err, promise); process.exit(1); }); process.on('uncaughtException', function (err) { if (process.listeners('uncaughtException').length > 1) { return; } console.error(new Date().toLocaleString(), 'uncaughtException', err); process.exit(1); }); module.exports.writableCallbackExit = (callback) => { process.on('exit', function () { if (!this.stdin._writableState.ended) { callback(this.stdin) } }); }src/promise.js000066400000000000000000000004161516075465100136740ustar00rootroot00000000000000module.exports.deferred = () => { let resolver, rejecter; const promise = new Promise((resolve, reject) => { resolver = resolve, rejecter = reject }) return { resolve: resolver, reject: rejecter, promise: promise, } } src/random.js000066400000000000000000000014421516075465100134760ustar00rootroot00000000000000const crypto = require('mz/crypto'); const uuid = require('uuid'); module.exports = async (length = 128) => { const random = await crypto.randomBytes(length); const string = require('./base').charset(random) return string; } module.exports.timeBase = async (length = 128) => { let random = await module.exports(length) return `${Date.now()}${random}`; } module.exports.integer = (min = 0, max = Int.MAX_INTEGER) => { return Math.floor(Math.random() * (max - min + 1)) + min; } module.exports.lower = async (length = 16) => { const random = await crypto.randomBytes(length); const base = require('./base'); const string = base.charset(random, base.base36Charset) return string; } module.exports.complexUuid = () => { return `${uuid.v4()}-${uuid.v1()}` } src/redis.js000066400000000000000000000006031516075465100133220ustar00rootroot00000000000000module.exports.parseUrl = (redisUrlInput) => { const url = require('url'); const redisUrl = new url.URL(redisUrlInput); const redisObject = { "password": redisUrl.password, "port": redisUrl.port || 6379, "host": redisUrl.hostname, "db": redisUrl.pathname.length > 1 ? parseInt(redisUrl.pathname.substr(1)) : 0, }; return redisObject; }src/regexp.js000066400000000000000000000010621516075465100135060ustar00rootroot00000000000000const escape = string => { if (typeof string !== 'string') { throw new TypeError('Expected a string'); } // Escape characters with special meaning either inside or outside character sets. // Use a simple backslash escape when it’s always valid, and a \unnnn escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar. return string .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&') .replace(/-/g, '\\x2d'); } if (!RegExp.escape) { RegExp.escape = escape; } module.exports.escape = escape; src/require.js000066400000000000000000000057371516075465100137050ustar00rootroot00000000000000const resolveDependencies = (options) => { if (Array.isArray(options)) { options = { modules: options } } let { modules, recursive, debug } = options; recursive = recursive || []; if (debug) { dconsole = console; } else { dconsole = { info: () => { }, } } let resovledModules = []; let lastWrongModule; let iteration = 0; dconsole.info(`Modules: ${modules.length}`); const ensureWants = () => { iteration++; dconsole.info(); dconsole.info(`Iteration: ${iteration}`) let totalOk = true; for (let index = 0; index < modules.length; index++) { const loadedModule = modules[index]; dconsole.info(); dconsole.info(`Module: ${loadedModule.name}`); if (recursive.includes(loadedModule.name)) { if (!resovledModules.includes(loadedModule)) { dconsole.info(`Adding to the recursived list`); resovledModules.push(loadedModule); } } if (resovledModules.includes(loadedModule)) { dconsole.info(`Already got it`); continue; } let ok = true loadedModule.wants.forEach((want) => { let found = false; resovledModules.forEach((resultModule) => { if (resultModule.name === want) { found = true; } }) if (!found) { ok = false; totalOk = false; } }) if (ok) { dconsole.info(`Found!`); resovledModules.push(loadedModule); } else { lastWrongModule = { name: loadedModule.name, wants: loadedModule.wants } } } return totalOk; } let checkCircular; while (!ensureWants()) { if (checkCircular === undefined) { checkCircular = resovledModules.length; continue; } if (checkCircular === resovledModules.length) { const print = (datas) => { return JSON.stringify(datas.map((data) => { return { name: data.name, wants: data.wants } }), null, 2) } dconsole.info(` Loaded factories `, print(modules)) dconsole.info(` Wanted factories in order `, print(resovledModules)); dconsole.info(` Last wrong factory `, lastWrongModule); dconsole.info(` `) throw Error('circular loading factory'); } checkCircular = resovledModules.length; } return resovledModules; } module.exports.resolveDependencies = resolveDependencies; src/snap.js000066400000000000000000000004361516075465100131610ustar00rootroot00000000000000module.exports.getVersion = async ({ pkg }) => { const result = await require('./child-process').exec(`snapcraft status ${pkg.name}`) let snapVersion = result.stdout.split('\n')[3].trim().split(' ') snapVersion = snapVersion[snapVersion.length - 1] return snapVersion } src/string/000077500000000000000000000000001516075465100131655ustar00rootroot00000000000000src/string/index.js000066400000000000000000000030471516075465100146360ustar00rootroot00000000000000if (!String.prototype.padStart) { String.prototype.padStart = function padStart(targetLength, padString) { targetLength = targetLength >> 0; //floor if number or convert non-number to 0; padString = String(padString || ' '); if (this.length > targetLength) { return String(this); } else { targetLength = targetLength - this.length; if (targetLength > padString.length) { padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed } return padString.slice(0, targetLength) + String(this); } }; } module.exports.empty = (spec) => { spec = String(spec).trim(); return spec === undefined || spec === '' || spec === 'undefined' } module.exports.inject = (str, options) => { const findPrefix = str.indexOf(options.prefix); const postixIndex = str.indexOf(options.postfix); if (findPrefix === -1 && postixIndex === -1 && !options.header && !options.footer) { return; } if (findPrefix === -1 && postixIndex === -1) { let replaceText = options.prefix + '\n' + options.replace + '\n' + options.postfix; if (options.header) { str = replaceText + '\n' + str; } else { str += '\n' + replaceText; } } else { const prefixIndex = findPrefix + options.prefix.length; str = str.substring(0, prefixIndex) + '\n' + options.replace + '\n' + str.substring(postixIndex); } return str; } src/time.js000066400000000000000000000021001516075465100131440ustar00rootroot00000000000000const ms = require('ms'); const timestring = require('timestring'); module.exports.span = (spec) => { let result = timestring(spec); if (typeof (result) === 'number') { result = result * 1000; } return result; } module.exports.msParse = (ms) => { if (typeof ms !== 'number') { throw new TypeError('Expected a number'); } var roundTowardZero = ms > 0 ? Math.floor : Math.ceil; return { days: roundTowardZero(ms / 86400000), hours: roundTowardZero(ms / 3600000) % 24, minutes: roundTowardZero(ms / 60000) % 60, seconds: roundTowardZero(ms / 1000) % 60, milliseconds: roundTowardZero(ms) % 1000 }; }; module.exports.verbose = (timestamp, started) => { if (timestamp === undefined) { return undefined; } const leftMs = timestamp - Date.now(); return { left: ms(leftMs), leftMs: leftMs, end: new Date(timestamp).toLocaleString(), start: new Date(started).toLocaleString(), startstamp: started, timestamp: timestamp, } } src/timer.js000066400000000000000000000034521516075465100133410ustar00rootroot00000000000000const promiseUtils = require('./promise'); const os = require('os'); const fs = require('fs').promises; const hash = require('./hash'); const path = require('path'); const wait = async (timeout) => { return await corySetTimeout(timeout); } const waitFile = async (timeout = 20000, file) => { const fsExtra = require('fs-extra'); if (file === undefined) { file = `${os.tmpdir()}/p3x-wait-file-${path.parse(process.argv[1]).name}-${hash.string(process.argv.join())}.boot` } const exists = await fsExtra.pathExists(file); if (exists) { console.info(`${file} exists, no delay required`); } else { console.info(`${file} doesn't exist, waiting ${timeout}ms, then generate ${file}`); await wait(timeout); console.info(`${file} now exists`); } await fs.writeFile(file, String(Date.now())); return { timeout: timeout, file: file, exists: exists, } } const corySetTimeout = async (cb, timeout) => { if (timeout === undefined) { timeout = cb; cb = () => { }; } const {resolve, reject, promise} = promiseUtils.deferred(); promise.timer = setTimeout(async () => { try { await cb(); resolve(); } catch (e) { reject(e); } }, timeout) return promise; } const corySetInterval = async (cb, timeout) => { const {resolve, reject, promise} = promiseUtils.deferred(); promise.timer = setInterval(async () => { try { await cb(); resolve(); } catch (e) { reject(e); } }, timeout) return promise; } module.exports.wait = wait; module.exports.waitFile = waitFile; module.exports.setTimeout = corySetTimeout; module.exports.setInterval = corySetInterval; test/000077500000000000000000000000001516075465100120475ustar00rootroot00000000000000test/script/000077500000000000000000000000001516075465100133535ustar00rootroot00000000000000test/script/complex-uuid.js000066400000000000000000000003051516075465100163220ustar00rootroot00000000000000const utils = require('../../src'); const uuid = require('uuid'); console.log('corifeus-utils complex uuid', utils.random.complexUuid()) console.log('v1', uuid.v1()) console.log('v4', uuid.v4()) test/script/decrypt.js000077500000000000000000000006751516075465100153760ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const start = async () => { const pass = process.argv[2] const data = process.argv[3] console.log(`Dencrypt ${data} with pass ${pass}`) try { const decrypted = await utils.crypto.decrypt({ data: data, pass: pass, }) console.log(`Decrypted: ${decrypted}`) } catch (e) { console.error(e); } } start(); test/script/encrypt-decrypt.js000077500000000000000000000011441516075465100170500ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const start = async () => { const pass = process.argv[2] const data = process.argv[3] console.log(`Encrypt ${data} with pass ${pass}`) try { const encrypted = await utils.crypto.encrypt({ data: data, pass: pass, }) console.log(`Encrypted: ${encrypted}`) const decrypted = await utils.crypto.decrypt({ data: encrypted, pass: pass, }) console.log(`Decrypted: ${decrypted}`) } catch (e) { console.error(e); } } start(); test/script/error.js000077500000000000000000000000661516075465100150470ustar00rootroot00000000000000#!/usr/bin/env node require('../../src'); throw 400;test/script/hash-string.js000077500000000000000000000004321516075465100161420ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const start = async () => { const hash = await utils.hash.string(process.argv[2]); console.log(hash); if (process.argv[3] === 'delay') { await utils.timer.waitFile(); return; } } start(); test/script/hash.js000077500000000000000000000002641516075465100146410ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const start = async () => { const hash = await utils.hash.file('./package.json'); console.log(hash); } start(); test/script/json-clone.js000077500000000000000000000002401516075465100157570ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const obj = { a: 1, b: 2, } const obj2 = utils.json.clone(obj); obj.a = 2; console.log(obj2)test/script/last-day.js000077500000000000000000000007611516075465100154360ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); console.log(new Date(utils.time.lastDay(0)).toLocaleString()); console.log(new Date(utils.time.lastDay(1)).toLocaleString()); console.log(new Date(utils.time.lastDay(2)).toLocaleString()); console.log(new Date(utils.time.lastDay(3)).toLocaleString()); console.log(new Date(utils.time.lastDay(4)).toLocaleString()); console.log(new Date(utils.time.lastDay(5)).toLocaleString()); console.log(new Date(utils.time.lastDay(6)).toLocaleString()); test/script/port-open.js000077500000000000000000000002741516075465100156420ustar00rootroot00000000000000#!/usr/bin/env node const utls = require('../../src'); const start = async () => { await utls.network.waitPort({ port: 6379, hostname: '127.0.0.1', }) } start();test/script/random.js000077500000000000000000000002501516075465100151710ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const start = async () => { const random = await utils.random(128); console.log(random); } start(); test/script/request.js000077500000000000000000000007301516075465100154040ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const init = async () => { try { const request = await utils.http.request({ // https://installer:titkos-kod@storage.ngivr.sygnus.hu/installer/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz url: 'https://server.patrikx3.com/api/core/util/random/32', raw: true, }); console.debug(request.body) } catch (e) { console.error(e); } } init(); test/script/wait-file.js000077500000000000000000000003071516075465100155750ustar00rootroot00000000000000#!/usr/bin/env node const utils = require('../../src'); const start = async () => { if (process.argv[2] === 'delay') { await utils.timer.waitFile(); return; } } start();