diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index d28ffe88..d98565d5 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -225,6 +225,9 @@ const install = async ({ services, app }) => { const { DevTODService } = require('./services/DevTODService'); services.registerService('__dev-tod', DevTODService); + + const { DriverService } = require("./services/drivers/DriverService"); + services.registerService('driver', DriverService); } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/SelfHostedModule.js b/packages/backend/src/SelfHostedModule.js index 268ed094..9eec5a88 100644 --- a/packages/backend/src/SelfHostedModule.js +++ b/packages/backend/src/SelfHostedModule.js @@ -5,6 +5,9 @@ class SelfHostedModule extends AdvancedBase { async install (context) { const services = context.get('services'); + const { SelfhostedService } = require('./services/SelfhostedService'); + services.registerService('__selfhosted', SelfhostedService); + const DefaultUserService = require('./services/DefaultUserService'); services.registerService('__default-user', DefaultUserService); diff --git a/packages/backend/src/services/drivers/implementations/BaseImplementation.js b/packages/backend/src/definitions/Driver.js similarity index 94% rename from packages/backend/src/services/drivers/implementations/BaseImplementation.js rename to packages/backend/src/definitions/Driver.js index 7c6b4c56..ded51255 100644 --- a/packages/backend/src/services/drivers/implementations/BaseImplementation.js +++ b/packages/backend/src/definitions/Driver.js @@ -17,16 +17,16 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { Context } = require("../../../util/context"); -const APIError = require("../../../api/APIError"); -const { AppUnderUserActorType, Actor, UserActorType } = require("../../auth/Actor"); -const { BaseOperation } = require("../../OperationTraceService"); -const { CodeUtil } = require("../../../codex/CodeUtil"); +const { Context } = require('../util/context') +const APIError = require("../api/APIError"); +const { AppUnderUserActorType, UserActorType } = require("../services/auth/Actor"); +const { BaseOperation } = require("../services/OperationTraceService"); +const { CodeUtil } = require("../codex/CodeUtil"); /** * Base class for all driver implementations. */ -class BaseImplementation extends AdvancedBase { +class Driver extends AdvancedBase { constructor (...a) { super(...a); const methods = this._get_merged_static_object('METHODS'); @@ -184,5 +184,5 @@ class BaseImplementation extends AdvancedBase { } module.exports = { - BaseImplementation, + Driver, }; diff --git a/packages/backend/src/services/drivers/implementations/DBKVStore.js b/packages/backend/src/drivers/DBKVStore.js similarity index 87% rename from packages/backend/src/services/drivers/implementations/DBKVStore.js rename to packages/backend/src/drivers/DBKVStore.js index 8f6badfd..d86928ec 100644 --- a/packages/backend/src/services/drivers/implementations/DBKVStore.js +++ b/packages/backend/src/drivers/DBKVStore.js @@ -16,14 +16,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AppUnderUserActorType } = require("../../auth/Actor"); -const { BaseImplementation } = require("./BaseImplementation"); +const config = require("../config"); +const APIError = require("../api/APIError"); +const { DB_READ, DB_WRITE } = require("../services/database/consts"); +const { Driver } = require("../definitions/Driver"); -const config = require("../../../config"); -const APIError = require("../../../api/APIError"); -const { DB_READ, DB_WRITE } = require("../../database/consts"); - -class DBKVStore extends BaseImplementation { +class DBKVStore extends Driver { static ID = 'public-db-kvstore'; static VERSION = '0.0.0'; static INTERFACE = 'puter-kvstore'; @@ -32,6 +30,7 @@ class DBKVStore extends BaseImplementation { } static METHODS = { get: async function ({ key }) { + console.log('THIS WAS CALLED', { key }); const actor = this.context.get('actor'); // If the actor is an app then it gets its own KV store. @@ -58,6 +57,7 @@ class DBKVStore extends BaseImplementation { return kv[0]?.value ?? null; }, set: async function ({ key, value }) { + console.log('THIS WAS CALLED (SET)', { key, value }) const actor = this.context.get('actor'); // Validate the key @@ -98,12 +98,15 @@ class DBKVStore extends BaseImplementation { ] ); } catch (e) { - // if ( e.code !== 'SQLITE_ERROR' && e.code !== 'SQLITE_CONSTRAINT_PRIMARYKEY' ) throw e; - // The "ON CONFLICT" clause isn't currently working. - await db.write( - `UPDATE kv SET value = ? WHERE user_id=? AND app=? AND kkey_hash=?`, - [ value, user.id, app?.uid ?? 'global', key_hash ] - ); + // I discovered that my .sqlite file was corrupted and the update + // above didn't work. The current database initialization does not + // cause this issue so I'm adding this log as a safeguard. + // - KernelDeimos / ED + const svc_error = this.services.get('error-service'); + svc_error.report('kvstore:sqlite_error', { + message: 'Broken database version - please contact maintainers', + source: e, + }); } return true; diff --git a/packages/backend/src/services/drivers/implementations/EntityStoreImplementation.js b/packages/backend/src/drivers/EntityStoreImplementation.js similarity index 94% rename from packages/backend/src/services/drivers/implementations/EntityStoreImplementation.js rename to packages/backend/src/drivers/EntityStoreImplementation.js index 6e98f9b9..8aed529b 100644 --- a/packages/backend/src/services/drivers/implementations/EntityStoreImplementation.js +++ b/packages/backend/src/drivers/EntityStoreImplementation.js @@ -16,10 +16,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const APIError = require("../../../api/APIError"); -const { Entity } = require("../../../om/entitystorage/Entity"); -const { Or, And, Eq } = require("../../../om/query/query"); -const { BaseImplementation } = require("./BaseImplementation"); +const APIError = require("../api/APIError"); +const { Driver } = require("../definitions/Driver"); +const { Entity } = require("../om/entitystorage/Entity"); +const { Or, And, Eq } = require("../om/query/query"); const _fetch_based_on_complex_id = async (self, id) => { // Ensure `id` is an object and get its keys @@ -87,7 +87,7 @@ const _fetch_based_on_either_id = async (self, uid, id) => { return await _fetch_based_on_complex_id(self, id); } -class EntityStoreImplementation extends BaseImplementation { +class EntityStoreImplementation extends Driver { constructor ({ service }) { super(); this.service = service; diff --git a/packages/backend/src/services/drivers/implementations/HelloWorld.js b/packages/backend/src/drivers/HelloWorld.js similarity index 88% rename from packages/backend/src/services/drivers/implementations/HelloWorld.js rename to packages/backend/src/drivers/HelloWorld.js index 7513e691..058e5d12 100644 --- a/packages/backend/src/services/drivers/implementations/HelloWorld.js +++ b/packages/backend/src/drivers/HelloWorld.js @@ -16,10 +16,9 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { Context } = require("../../../util/context"); -const { BaseImplementation } = require("./BaseImplementation"); +const { Driver } = require("../definitions/Driver"); -class HelloWorld extends BaseImplementation { +class HelloWorld extends Driver { static ID = 'public-helloworld'; static VERSION = '0.0.0'; static INTERFACE = 'helloworld'; diff --git a/packages/backend/src/om/definitions/PropType.js b/packages/backend/src/om/definitions/PropType.js index e72d7cdf..40e9fa09 100644 --- a/packages/backend/src/om/definitions/PropType.js +++ b/packages/backend/src/om/definitions/PropType.js @@ -128,8 +128,6 @@ class PropType extends AdvancedBase { async is_set (value) { const is_setters = this.chains.is_set || []; - console.log('IS SETTERS', is_setters) - for ( const is_setter of is_setters ) { const result = await is_setter(value); if ( ! result ) { diff --git a/packages/backend/src/services/SelfhostedService.js b/packages/backend/src/services/SelfhostedService.js new file mode 100644 index 00000000..3c3f4a74 --- /dev/null +++ b/packages/backend/src/services/SelfhostedService.js @@ -0,0 +1,21 @@ +const { DBKVStore } = require("../drivers/DBKVStore"); +const { EntityStoreImplementation } = require("../drivers/EntityStoreImplementation"); +const { HelloWorld } = require("../drivers/HelloWorld"); +const BaseService = require("./BaseService"); + +class SelfhostedService extends BaseService { + static description = ` + Registers drivers for self-hosted Puter instances. + ` + + async _init () { + const svc_driver = this.services.get('driver'); + + svc_driver.register_driver('helloworld', new HelloWorld()); + svc_driver.register_driver('puter-kvstore', new DBKVStore()); + svc_driver.register_driver('puter-apps', new EntityStoreImplementation({ service: 'es:app' })); + svc_driver.register_driver('puter-subdomains', new EntityStoreImplementation({ service: 'es:subdomain' })); + } +} + +module.exports = { SelfhostedService }; diff --git a/packages/backend/src/services/database/SqliteDatabaseAccessService.js b/packages/backend/src/services/database/SqliteDatabaseAccessService.js index b1e76eb3..200f670c 100644 --- a/packages/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/packages/backend/src/services/database/SqliteDatabaseAccessService.js @@ -168,22 +168,13 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { query = this.sqlite_transform_query_(query); params = this.sqlite_transform_params_(params); - try { - const stmt = this.db.prepare(query); - const info = stmt.run(...params); + const stmt = this.db.prepare(query); + const info = stmt.run(...params); - return { - insertId: info.lastInsertRowid, - anyRowsAffected: info.changes > 0, - }; - } catch ( e ) { - console.error(e); - console.log('everything', { - query, params, - }) - console.log(params.map(p => typeof p)); - // throw e; - } + return { + insertId: info.lastInsertRowid, + anyRowsAffected: info.changes > 0, + }; } async _batch_write (entries) { diff --git a/packages/backend/src/services/drivers/DriverService.js b/packages/backend/src/services/drivers/DriverService.js index 361c92e9..70b60deb 100644 --- a/packages/backend/src/services/drivers/DriverService.js +++ b/packages/backend/src/services/drivers/DriverService.js @@ -16,37 +16,27 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); const { Context } = require("../../util/context"); const APIError = require("../../api/APIError"); const { DriverError } = require("./DriverError"); -const { Value, TypedValue } = require("./meta/Runtime"); -const { ServiceImplementation, EntityStoreImplementation } = require("./implementations/EntityStoreImplementation"); +const { TypedValue } = require("./meta/Runtime"); +const BaseService = require("../BaseService"); /** * DriverService provides the functionality of Puter drivers. */ -class DriverService extends AdvancedBase { +class DriverService extends BaseService { static MODULES = { types: require('./types'), } - constructor ({ services }) { - super(); - this.services = services; - - // TODO: move this to an init method - this.log = services.get('log-service').create(this.constructor.name); - this.errors = services.get('error-service').create(this.log); - + _construct () { this.interfaces = require('./interfaces'); + this.interface_to_implementation = {}; + } - this.interface_to_implementation = { - 'helloworld': new (require('./implementations/HelloWorld').HelloWorld)(), - 'puter-kvstore': new (require('./implementations/DBKVStore').DBKVStore)(), - 'puter-apps': new EntityStoreImplementation({ service: 'es:app' }), - 'puter-subdomains': new EntityStoreImplementation({ service: 'es:subdomain' }), - }; + register_driver (interface_name, implementation) { + this.interface_to_implementation[interface_name] = implementation; } get_interface (interface_name) { diff --git a/packages/backend/src/services/drivers/implementations/PuterDriverProxy.js b/packages/backend/src/services/drivers/implementations/PuterDriverProxy.js deleted file mode 100644 index 422bdc9d..00000000 --- a/packages/backend/src/services/drivers/implementations/PuterDriverProxy.js +++ /dev/null @@ -1,56 +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 . - */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); - -const ENDPOINT = 'https://api.puter.com/drivers/call'; - -/* - -Fetch example: - -await fetch("https://api.puter.local/drivers/call", { - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer ", - }, - "body": JSON.stringify({ interface: '...', method: '...', args: { ... } }), - "method": "POST", -}); - -*/ - -class PuterDriverProxy extends AdvancedBase { - static MODULES = { - axios: require('axios'), - } - - constructor ({ target }) { - super(); - this.target = target; - } - - async call (method, args) { - const require = this.require; - const axios = require('axios'); - - // TODO: We need the BYOK feature before we can implement this - } -} - -module.exports = PuterDriverProxy; diff --git a/run-selfhosted.js b/run-selfhosted.js index 94db315b..12893622 100644 --- a/run-selfhosted.js +++ b/run-selfhosted.js @@ -57,7 +57,6 @@ const main = async () => { Kernel, CoreModule, DatabaseModule, - PuterDriversModule, LocalDiskStorageModule, SelfHostedModule } = (await import('@heyputer/backend')).default; @@ -66,7 +65,6 @@ const main = async () => { const k = new Kernel(); k.add_module(new CoreModule()); k.add_module(new DatabaseModule()); - k.add_module(new PuterDriversModule()); k.add_module(new LocalDiskStorageModule()); k.add_module(new SelfHostedModule()); k.boot();