ソースを参照

refactor(backend): de-couple driver registration from DriverService

KernelDeimos 11 ヶ月 前
コミット
665b2d4e4e

+ 3 - 0
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 }) => {

+ 3 - 0
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);
 

+ 7 - 7
packages/backend/src/services/drivers/implementations/BaseImplementation.js → packages/backend/src/definitions/Driver.js

@@ -17,16 +17,16 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 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,
 };

+ 16 - 13
packages/backend/src/services/drivers/implementations/DBKVStore.js → 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 <https://www.gnu.org/licenses/>.
  */
-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;

+ 5 - 5
packages/backend/src/services/drivers/implementations/EntityStoreImplementation.js → 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 <https://www.gnu.org/licenses/>.
  */
-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;

+ 2 - 3
packages/backend/src/services/drivers/implementations/HelloWorld.js → 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 <https://www.gnu.org/licenses/>.
  */
-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';

+ 0 - 2
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 ) {

+ 21 - 0
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 };

+ 6 - 15
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) {

+ 8 - 18
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 <https://www.gnu.org/licenses/>.
  */
-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) {

+ 0 - 56
packages/backend/src/services/drivers/implementations/PuterDriverProxy.js

@@ -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 <https://www.gnu.org/licenses/>.
- */
-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 <actor token>",
-  },
-  "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;

+ 0 - 2
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();