mirror of
https://github.com/HeyPuter/puter.git
synced 2025-02-02 23:28:39 +08:00
refactor: flatten the monorepo
This commit is contained in:
parent
f88c4a5c9c
commit
fa7bec3854
30
package-lock.json
generated
30
package-lock.json
generated
@ -7,12 +7,12 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "puter.com",
|
"name": "puter.com",
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@xterm/xterm": "^5.5.0",
|
||||||
"json-colorizer": "^3.0.1",
|
"json-colorizer": "^3.0.1",
|
||||||
"uuid": "^9.0.1"
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
@ -5456,6 +5456,10 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/contextlink": {
|
||||||
|
"resolved": "packages/contextlink",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/convert-source-map": {
|
"node_modules/convert-source-map": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||||
@ -5789,6 +5793,10 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dev-pty": {
|
||||||
|
"resolved": "packages/pty",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/diff": {
|
"node_modules/diff": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
||||||
@ -10712,6 +10720,10 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strataparse": {
|
||||||
|
"resolved": "packages/strataparse",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/streamsearch": {
|
"node_modules/streamsearch": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||||
@ -12061,6 +12073,13 @@
|
|||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"packages/contextlink": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "^10.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packages/git": {
|
"packages/git": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
@ -12312,6 +12331,11 @@
|
|||||||
"extraneous": true,
|
"extraneous": true,
|
||||||
"license": "AGPL-3.0-only"
|
"license": "AGPL-3.0-only"
|
||||||
},
|
},
|
||||||
|
"packages/pty": {
|
||||||
|
"name": "dev-pty",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "AGPL-3.0-only"
|
||||||
|
},
|
||||||
"packages/puter-js": {
|
"packages/puter-js": {
|
||||||
"name": "@heyputer/puterjs",
|
"name": "@heyputer/puterjs",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@ -12326,6 +12350,10 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "UNLICENSED"
|
"license": "UNLICENSED"
|
||||||
},
|
},
|
||||||
|
"packages/strataparse": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "AGPL-3.0-only"
|
||||||
|
},
|
||||||
"packages/terminal": {
|
"packages/terminal": {
|
||||||
"name": "@heyputer/terminal",
|
"name": "@heyputer/terminal",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
|
@ -29,8 +29,7 @@
|
|||||||
"start=gui": "nodemon --exec \"node dev-server.js\" ",
|
"start=gui": "nodemon --exec \"node dev-server.js\" ",
|
||||||
"start": "node run-selfhosted.js",
|
"start": "node run-selfhosted.js",
|
||||||
"build": "node ./build.js",
|
"build": "node ./build.js",
|
||||||
"check-translations": "node tools/check-translations.js",
|
"check-translations": "node tools/check-translations.js"
|
||||||
"postinstall": "cd packages/phoenix && cd packages/contextlink && npm install && cd - && cd packages/strataparse && npm install && cd - && cd packages/pty && npm install"
|
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
const { AdvancedBase } = require('./src/AdvancedBase');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
AdvancedBase,
|
|
||||||
};
|
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@heyputer/puter-js-common",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "Puter Technologies Inc.",
|
|
||||||
"license": "UNLICENSED"
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
// This doesn't go in ./bases because it logically depends on
|
|
||||||
// both ./bases and ./traits, and ./traits depends on ./bases.
|
|
||||||
|
|
||||||
const { TraitBase } = require("./bases/TraitBase");
|
|
||||||
|
|
||||||
class AdvancedBase extends TraitBase {
|
|
||||||
static TRAITS = [
|
|
||||||
require('./traits/NodeModuleDITrait'),
|
|
||||||
require('./traits/PropertiesTrait'),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
AdvancedBase,
|
|
||||||
};
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
class BasicBase {
|
|
||||||
_get_inheritance_chain () {
|
|
||||||
const chain = [];
|
|
||||||
let cls = this.constructor;
|
|
||||||
while ( cls && cls !== BasicBase ) {
|
|
||||||
chain.push(cls);
|
|
||||||
cls = cls.__proto__;
|
|
||||||
}
|
|
||||||
return chain.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_merged_static_array (key) {
|
|
||||||
const chain = this._get_inheritance_chain();
|
|
||||||
const values = [];
|
|
||||||
for ( const cls of chain ) {
|
|
||||||
if ( cls[key] ) {
|
|
||||||
values.push(...cls[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_merged_static_object (key) {
|
|
||||||
const chain = this._get_inheritance_chain();
|
|
||||||
const values = {};
|
|
||||||
for ( const cls of chain ) {
|
|
||||||
if ( cls[key] ) {
|
|
||||||
Object.assign(values, cls[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
BasicBase,
|
|
||||||
};
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
const { BasicBase } = require("./BasicBase");
|
|
||||||
|
|
||||||
class TraitBase extends BasicBase {
|
|
||||||
constructor (parameters, ...a) {
|
|
||||||
super(parameters, ...a);
|
|
||||||
for ( const trait of this.traits ) {
|
|
||||||
trait.install_in_instance(
|
|
||||||
this,
|
|
||||||
{
|
|
||||||
parameters: parameters || {},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get traits () {
|
|
||||||
return this._get_merged_static_array('TRAITS');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
TraitBase,
|
|
||||||
};
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* This trait allows dependency injection of node modules.
|
|
||||||
* This is incredibly useful for passing mock implementations
|
|
||||||
* of modules for unit testing.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* class MyClass extends AdvancedBase {
|
|
||||||
* static MODULES = {
|
|
||||||
* axios,
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* const my_class = new MyClass({
|
|
||||||
* modules: {
|
|
||||||
* axios: MY_AXIOS_MOCK,
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
module.exports = {
|
|
||||||
install_in_instance: (instance, { parameters }) => {
|
|
||||||
const modules = instance._get_merged_static_object('MODULES');
|
|
||||||
|
|
||||||
if ( parameters.modules ) {
|
|
||||||
for ( const k in parameters.modules ) {
|
|
||||||
modules[k] = parameters.modules[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instance.modules = modules;
|
|
||||||
|
|
||||||
// This "require" function can shadow the real one so
|
|
||||||
// that editor tools are aware of the modules that
|
|
||||||
// are being used.
|
|
||||||
instance.require = (name) => {
|
|
||||||
if ( modules[name] ) {
|
|
||||||
return modules[name];
|
|
||||||
}
|
|
||||||
return require(name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
module.exports = {
|
|
||||||
install_in_instance: (instance) => {
|
|
||||||
const properties = instance._get_merged_static_object('PROPERTIES');
|
|
||||||
|
|
||||||
for ( const k in properties ) {
|
|
||||||
if ( typeof properties[k] === 'function' ) {
|
|
||||||
instance[k] = properties[k]();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( typeof properties[k] === 'object' ) {
|
|
||||||
// This will be supported in the future.
|
|
||||||
throw new Error(`Property ${k} in ${instance.constructor.name} ` +
|
|
||||||
`is not a supported property specification.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
instance[k] = properties[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Puter Technologies Inc.
|
|
||||||
*
|
|
||||||
* This file is part of Puter.
|
|
||||||
*
|
|
||||||
* Puter is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
const { expect } = require('chai');
|
|
||||||
const { BasicBase } = require('../src/bases/BasicBase');
|
|
||||||
const { AdvancedBase } = require('../src/AdvancedBase');
|
|
||||||
|
|
||||||
class ClassA extends BasicBase {
|
|
||||||
static STATIC_OBJ = {
|
|
||||||
a: 1,
|
|
||||||
b: 2,
|
|
||||||
};
|
|
||||||
static STATIC_ARR = ['a', 'b'];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClassB extends ClassA {
|
|
||||||
static STATIC_OBJ = {
|
|
||||||
c: 3,
|
|
||||||
d: 4,
|
|
||||||
};
|
|
||||||
static STATIC_ARR = ['c', 'd'];
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('testing', () => {
|
|
||||||
it('does a thing', () => {
|
|
||||||
const b = new ClassB();
|
|
||||||
|
|
||||||
console.log(b._get_inheritance_chain());
|
|
||||||
console.log([ClassA, ClassB]);
|
|
||||||
expect(b._get_inheritance_chain()).deep.equal([ClassA, ClassB]);
|
|
||||||
expect(b._get_merged_static_array('STATIC_ARR'))
|
|
||||||
.deep.equal(['a', 'b', 'c', 'd']);
|
|
||||||
expect(b._get_merged_static_object('STATIC_OBJ'))
|
|
||||||
.deep.equal({ a: 1, b: 2, c: 3, d: 4 });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
class ClassWithModule extends AdvancedBase {
|
|
||||||
static MODULES = {
|
|
||||||
axios: 'axios',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('AdvancedBase', () => {
|
|
||||||
it('passes DI modules to instance', () => {
|
|
||||||
const c1 = new ClassWithModule();
|
|
||||||
expect(c1.modules.axios).to.equal('axios');
|
|
||||||
|
|
||||||
const c2 = new ClassWithModule({
|
|
||||||
modules: {
|
|
||||||
axios: 'my-axios',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(c2.modules.axios).to.equal('my-axios');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -20,6 +20,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
|
|||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
import copy from 'rollup-plugin-copy';
|
import copy from 'rollup-plugin-copy';
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
|
const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
|
||||||
await import(`./${configFile}`);
|
await import(`./${configFile}`);
|
||||||
@ -34,6 +35,7 @@ export default {
|
|||||||
nodeResolve({
|
nodeResolve({
|
||||||
browser: true,
|
browser: true,
|
||||||
preferBuiltins: false,
|
preferBuiltins: false,
|
||||||
|
rootDir: path.join(process.cwd(), '..'),
|
||||||
}),
|
}),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
copy({
|
copy({
|
||||||
|
@ -20,6 +20,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
|
|||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
import copy from 'rollup-plugin-copy';
|
import copy from 'rollup-plugin-copy';
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
|
const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
|
||||||
await import(`./${configFile}`);
|
await import(`./${configFile}`);
|
||||||
@ -31,7 +32,9 @@ export default {
|
|||||||
format: "iife"
|
format: "iife"
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
nodeResolve(),
|
nodeResolve({
|
||||||
|
rootDir: path.join(process.cwd(), '..'),
|
||||||
|
}),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
copy({
|
copy({
|
||||||
targets: [
|
targets: [
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import { TeePromise, raceCase } from '../../src/promise.js';
|
import { libs } from '@heyputer/puter-js-common';
|
||||||
|
const { TeePromise, raceCase } = libs.promise;
|
||||||
|
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
|
|
@ -2,4 +2,7 @@ const { AdvancedBase } = require('./src/AdvancedBase');
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
AdvancedBase,
|
AdvancedBase,
|
||||||
|
libs: {
|
||||||
|
promise: require('./src/libs/promise'),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
171
packages/puter-js-common/src/libs/promise.js
Normal file
171
packages/puter-js-common/src/libs/promise.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Puter Technologies Inc.
|
||||||
|
*
|
||||||
|
* This file is part of Puter.
|
||||||
|
*
|
||||||
|
* Puter is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
class TeePromise {
|
||||||
|
static STATUS_PENDING = Symbol('pending');
|
||||||
|
static STATUS_RUNNING = {};
|
||||||
|
static STATUS_DONE = Symbol('done');
|
||||||
|
constructor () {
|
||||||
|
this.status_ = this.constructor.STATUS_PENDING;
|
||||||
|
this.donePromise = new Promise((resolve, reject) => {
|
||||||
|
this.doneResolve = resolve;
|
||||||
|
this.doneReject = reject;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
get status () {
|
||||||
|
return this.status_;
|
||||||
|
}
|
||||||
|
set status (status) {
|
||||||
|
this.status_ = status;
|
||||||
|
if ( status === this.constructor.STATUS_DONE ) {
|
||||||
|
this.doneResolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve (value) {
|
||||||
|
this.status_ = this.constructor.STATUS_DONE;
|
||||||
|
this.doneResolve(value);
|
||||||
|
}
|
||||||
|
awaitDone () {
|
||||||
|
return this.donePromise;
|
||||||
|
}
|
||||||
|
then (fn, ...a) {
|
||||||
|
return this.donePromise.then(fn, ...a);
|
||||||
|
}
|
||||||
|
|
||||||
|
reject (err) {
|
||||||
|
this.status_ = this.constructor.STATUS_DONE;
|
||||||
|
this.doneReject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use then() instead
|
||||||
|
*/
|
||||||
|
onComplete(fn) {
|
||||||
|
return this.then(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Lock {
|
||||||
|
constructor() {
|
||||||
|
this._locked = false;
|
||||||
|
this._waiting = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async acquire(callback) {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
if ( ! this._locked ) {
|
||||||
|
this._locked = true;
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
this._waiting.push({
|
||||||
|
resolve,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if ( callback ) {
|
||||||
|
let retval;
|
||||||
|
try {
|
||||||
|
retval = await callback();
|
||||||
|
} finally {
|
||||||
|
this.release();
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release() {
|
||||||
|
if (this._waiting.length > 0) {
|
||||||
|
const { resolve } = this._waiting.shift();
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
this._locked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback behindScheduleCallback
|
||||||
|
* @param {number} drift - The number of milliseconds that the callback was
|
||||||
|
* called behind schedule.
|
||||||
|
* @returns {boolean} - If the callback returns true, the timer will be
|
||||||
|
* cancelled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When passing an async callback to setInterval, it's possible for the
|
||||||
|
* callback to be called again before the previous invocation has finished.
|
||||||
|
*
|
||||||
|
* This function wraps setInterval and ensures that the callback is not
|
||||||
|
* called again until the previous invocation has finished.
|
||||||
|
*
|
||||||
|
* @param {Function} callback - The function to call when the timer elapses.
|
||||||
|
* @param {number} delay - The minimum number of milliseconds between invocations.
|
||||||
|
* @param {?Array<any>} args - Additional arguments to pass to setInterval.
|
||||||
|
* @param {?Object} options - Additional options.
|
||||||
|
* @param {behindScheduleCallback} options.onBehindSchedule - A callback to call when the callback is called behind schedule.
|
||||||
|
*/
|
||||||
|
const asyncSafeSetInterval = async (callback, delay, args, options) => {
|
||||||
|
args = args ?? [];
|
||||||
|
options = options ?? {};
|
||||||
|
const { onBehindSchedule } = options;
|
||||||
|
|
||||||
|
const sleep = (ms) => new Promise(rslv => setTimeout(rslv, ms));
|
||||||
|
|
||||||
|
for ( ;; ) {
|
||||||
|
await sleep(delay);
|
||||||
|
|
||||||
|
const ts_start = Date.now();
|
||||||
|
await callback(...args);
|
||||||
|
const ts_end = Date.now();
|
||||||
|
|
||||||
|
const runtime = ts_end - ts_start;
|
||||||
|
const sleep_time = delay - runtime;
|
||||||
|
|
||||||
|
if ( sleep_time < 0 ) {
|
||||||
|
if ( onBehindSchedule ) {
|
||||||
|
const cancel = await onBehindSchedule(-sleep_time);
|
||||||
|
if ( cancel ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await sleep(sleep_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* raceCase is like Promise.race except it takes an object instead of
|
||||||
|
* an array, and returns the key of the promise that resolves first
|
||||||
|
* as well as the value that it resolved to.
|
||||||
|
*
|
||||||
|
* @param {Object.<string, Promise>} promise_map
|
||||||
|
*
|
||||||
|
* @returns {Promise.<[string, any]>}
|
||||||
|
*/
|
||||||
|
const raceCase = async (promise_map) => {
|
||||||
|
return Promise.race(Object.entries(promise_map).map(
|
||||||
|
([key, promise]) => promise.then(value => [key, value])));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
TeePromise,
|
||||||
|
Lock,
|
||||||
|
asyncSafeSetInterval,
|
||||||
|
raceCase,
|
||||||
|
};
|
@ -20,6 +20,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
|
|||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
import copy from 'rollup-plugin-copy';
|
import copy from 'rollup-plugin-copy';
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
|
const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
|
||||||
await import(`./${configFile}`);
|
await import(`./${configFile}`);
|
||||||
@ -31,7 +32,9 @@ export default {
|
|||||||
format: "iife"
|
format: "iife"
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
nodeResolve(),
|
nodeResolve({
|
||||||
|
rootDir: path.join(process.cwd(), '..'),
|
||||||
|
}),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
copy({
|
copy({
|
||||||
targets: [
|
targets: [
|
||||||
|
Loading…
Reference in New Issue
Block a user