diff --git a/src/puter-js/src/index.js b/src/puter-js/src/index.js index a7d2f126..8a50cfbe 100644 --- a/src/puter-js/src/index.js +++ b/src/puter-js/src/index.js @@ -13,7 +13,7 @@ import path from './lib/path.js'; import Util from './modules/Util.js'; import Drivers from './modules/Drivers.js'; import putility from '@heyputer/putility'; -import { FSHostService } from './services/FSHost.js'; +import { FSRelayService } from './services/FSRelay.js'; import { FilesystemService } from './services/Filesystem.js'; import { APIAccessService } from './services/APIAccess.js'; import { XDIncomingService } from './services/XDIncoming.js'; @@ -69,8 +69,10 @@ window.puter = (function() { // "modules" in puter.js are external interfaces for the developer this.modules_ = []; // "services" in puter.js are used by modules and may interact with each other - const context = new putility.libs.context.Context(); + const context = new putility.libs.context.Context() + .follow(this, ['env', 'util']); this.services = new putility.system.ServiceManager({ context }); + this.context = context; context.services = this.services; // Holds the query parameters found in the current URL @@ -148,12 +150,12 @@ window.puter = (function() { this.APIOrigin = 'https://api.' + URLParams.get('puter.domain'); } + this.services.register('no-puter-yet', NoPuterYetService); + this.services.register('filesystem', FilesystemService); + this.services.register('api-access', APIAccessService); + this.services.register('xd-incoming', XDIncomingService); if ( this.env !== 'app' ) { - this.services.register('no-puter-yet', NoPuterYetService); - this.services.register('filesystem', FilesystemService); - this.services.register('api-access', APIAccessService); - this.services.register('xd-incoming', XDIncomingService); - // this.services.register('fs-host', FSHostService); + this.services.register('fs-relay', FSRelayService); } // When api-access is initialized, bind `.authToken` and @@ -162,15 +164,18 @@ window.puter = (function() { await this.services.wait_for_init(['api-access']); const svc_apiAccess = this.services.get('api-access'); - svc_apiAccess.authToken = this.authToken; - svc_apiAccess.APIOrigin = this.APIOrigin; - ['authToken', 'APIOrigin'].forEach(key => { - Object.defineProperty(this, key, { + svc_apiAccess.auth_token = this.authToken; + svc_apiAccess.api_origin = this.APIOrigin; + [ + ['authToken','auth_token'], + ['APIOrigin','api_origin'], + ].forEach(([k1,k2]) => { + Object.defineProperty(this, k1, { get () { - return svc_apiAccess[key]; + return svc_apiAccess[k2]; }, set (v) { - svc_apiAccess[key] = v; + svc_apiAccess[k2] = v; return true; } }); @@ -243,7 +248,7 @@ window.puter = (function() { new OS(this.authToken, this.APIOrigin, this.appID, this.env)); // FileSystem this.registerModule('fs', - new PuterJSFileSystemModule(this.authToken, this.APIOrigin, this.appID, this.env)); + new PuterJSFileSystemModule(this.authToken, this.APIOrigin, this.appID, this.context)); // UI this.registerModule('ui', new UI(this.appInstanceID, this.parentInstanceID, this.appID, this.env, this.util)); diff --git a/src/puter-js/src/modules/FileSystem/APIFS.js b/src/puter-js/src/lib/filesystem/APIFS.js similarity index 95% rename from src/puter-js/src/modules/FileSystem/APIFS.js rename to src/puter-js/src/lib/filesystem/APIFS.js index 2f5dfce9..308a99eb 100644 --- a/src/puter-js/src/modules/FileSystem/APIFS.js +++ b/src/puter-js/src/lib/filesystem/APIFS.js @@ -1,7 +1,7 @@ -import * as utils from '../../lib/utils.js'; +import * as utils from '../utils.js'; import putility from "@heyputer/putility"; import { TeePromise } from "@heyputer/putility/src/libs/promise"; -import getAbsolutePathForApp from './utils/getAbsolutePathForApp.js'; +import getAbsolutePathForApp from '../../modules/FileSystem/utils/getAbsolutePathForApp.js'; import { TFilesystem } from './definitions.js'; export class PuterAPIFilesystem extends putility.AdvancedBase { diff --git a/src/puter-js/src/modules/FileSystem/CacheFS.js b/src/puter-js/src/lib/filesystem/CacheFS.js similarity index 99% rename from src/puter-js/src/modules/FileSystem/CacheFS.js rename to src/puter-js/src/lib/filesystem/CacheFS.js index 444f3f2d..9e90b88c 100644 --- a/src/puter-js/src/modules/FileSystem/CacheFS.js +++ b/src/puter-js/src/lib/filesystem/CacheFS.js @@ -1,7 +1,7 @@ import putility from "@heyputer/putility"; import { RWLock } from "@heyputer/putility/src/libs/promise"; import { ProxyFilesystem, TFilesystem } from "./definitions"; -import { uuidv4 } from "../../lib/utils"; +import { uuidv4 } from "../utils"; export const ROOT_UUID = '00000000-0000-0000-0000-000000000000'; const TTL = 5 * 1000; diff --git a/src/puter-js/src/lib/filesystem/PostMessageFS.js b/src/puter-js/src/lib/filesystem/PostMessageFS.js new file mode 100644 index 00000000..74e995b4 --- /dev/null +++ b/src/puter-js/src/lib/filesystem/PostMessageFS.js @@ -0,0 +1,40 @@ +import putility from "@heyputer/putility"; +import { TFilesystem } from "./definitions"; + +const example = { + "id": "f485f1ba-de07-422c-8c4b-c2da057d4a44", + "uid": "f485f1ba-de07-422c-8c4b-c2da057d4a44", + "is_dir": true, + "immutable": true, + "name": "Test", + }; + +export class PostMessageFilesystem extends putility.AdvancedBase { + constructor ({ rpc, messageTarget }) { + super(); + this.rpc = rpc; + this.messageTarget = messageTarget; + } + static IMPLEMENTS = { + [TFilesystem]: { + stat: async function (o) { + return example; + }, + readdir: async function (o) { + const tp = new putility.libs.promise.TeePromise(); + const $callback = this.rpc.registerCallback((result) => { + tp.resolve(result); + }); + // return [example]; + this.messageTarget.postMessage({ + $: 'puter-fs', + $callback, + op: 'readdir', + args: o, + }, '*'); + + return await tp; + } + } + } +} diff --git a/src/puter-js/src/modules/FileSystem/definitions.js b/src/puter-js/src/lib/filesystem/definitions.js similarity index 100% rename from src/puter-js/src/modules/FileSystem/definitions.js rename to src/puter-js/src/lib/filesystem/definitions.js diff --git a/src/puter-js/src/modules/FileSystem/index.js b/src/puter-js/src/modules/FileSystem/index.js index 16c31ac3..55276991 100644 --- a/src/puter-js/src/modules/FileSystem/index.js +++ b/src/puter-js/src/modules/FileSystem/index.js @@ -13,10 +13,10 @@ import sign from "./operations/sign.js"; // Why is this called deleteFSEntry instead of just delete? because delete is // a reserved keyword in javascript import deleteFSEntry from "./operations/deleteFSEntry.js"; -import { ProxyFilesystem, TFilesystem } from './definitions.js'; +import { ProxyFilesystem, TFilesystem } from '../../lib/filesystem/definitions.js'; import { AdvancedBase } from '../../../../putility/index.js'; -import { CachedFilesystem } from './CacheFS.js'; -import { PuterAPIFilesystem } from './APIFS.js'; +import { CachedFilesystem } from '../../lib/filesystem/CacheFS.js'; +import { PuterAPIFilesystem } from '../../lib/filesystem/APIFS.js'; export class PuterJSFileSystemModule extends AdvancedBase { @@ -38,14 +38,16 @@ export class PuterJSFileSystemModule extends AdvancedBase { positional: ['path'], firstarg_options: true, async fn (parameters) { - return this.filesystem.stat(parameters); + const svc_fs = await this.context.services.aget('filesystem'); + return svc_fs.filesystem.stat(parameters); } }, readdir: { positional: ['path'], firstarg_options: true, - fn (parameters) { - return this.filesystem.readdir(parameters); + async fn (parameters) { + const svc_fs = await this.context.services.aget('filesystem'); + return svc_fs.filesystem.readdir(parameters); } }, } @@ -59,11 +61,12 @@ export class PuterJSFileSystemModule extends AdvancedBase { * @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs. * @param {string} appID - ID of the app to use. */ - constructor (authToken, APIOrigin, appID) { + constructor (authToken, APIOrigin, appID, context) { super(); this.authToken = authToken; this.APIOrigin = APIOrigin; this.appID = appID; + this.context = context; // Connect socket. this.initializeSocket(); @@ -76,21 +79,6 @@ export class PuterJSFileSystemModule extends AdvancedBase { Object.defineProperty(api_info, 'APIOrigin', { get: () => this.APIOrigin, }); - - // Construct the decorator chain for the client-side filesystem. - this.fs_nocache_ = new PuterAPIFilesystem({ api_info }).as(TFilesystem); - this.fs_cache_ = new CachedFilesystem({ delegate: this.fs_nocache_ }).as(TFilesystem); - // this.filesystem = this.fs_nocache; - this.fs_proxy_ = new ProxyFilesystem({ delegate: this.fs_nocache_ }); - this.filesystem = this.fs_proxy_.as(TFilesystem); - // this.fs_proxy_.delegate = this.fs_cache_; - } - - cache_on () { - this.fs_proxy_.delegate = this.fs_cache_; - } - cache_off () { - this.fs_proxy_.delegate = this.fs_nocache_; } diff --git a/src/puter-js/src/services/APIAccess.js b/src/puter-js/src/services/APIAccess.js index bceaf818..3471f735 100644 --- a/src/puter-js/src/services/APIAccess.js +++ b/src/puter-js/src/services/APIAccess.js @@ -11,7 +11,7 @@ export class APIAccessService extends putility.concepts.Service { static PROPERTIES = { auth_token: { - post_set () { + post_set (v) { this.as(TTopics).pub('update'); } }, @@ -21,4 +21,24 @@ export class APIAccessService extends putility.concepts.Service { } }, }; + + // TODO: inconsistent! Update all dependents. + get_api_info () { + const self = this; + const o = {}; + [ + ['authToken','auth_token'], + ['APIOrigin','api_origin'], + ].forEach(([k1,k2]) => { + Object.defineProperty(o, k1, { + get () { + return self[k2]; + }, + set (v) { + return self; + } + }); + }); + return o; + } } diff --git a/src/puter-js/src/services/FSHost.js b/src/puter-js/src/services/FSHost.js deleted file mode 100644 index a9aeccde..00000000 --- a/src/puter-js/src/services/FSHost.js +++ /dev/null @@ -1,7 +0,0 @@ -import putility from '@heyputer/putility'; - -export class FSHostService extends putility.concepts.Service { - async _init () { - // - } -} diff --git a/src/puter-js/src/services/FSRelay.js b/src/puter-js/src/services/FSRelay.js new file mode 100644 index 00000000..38bdf397 --- /dev/null +++ b/src/puter-js/src/services/FSRelay.js @@ -0,0 +1,20 @@ +import putility from '@heyputer/putility'; + +const example = { + "id": "f485f1ba-de07-422c-8c4b-c2da057d4a44", + "uid": "f485f1ba-de07-422c-8c4b-c2da057d4a44", + "is_dir": true, + "immutable": true, + "name": "FromParentWindow", + }; + +export class FSRelayService extends putility.concepts.Service { + async _init () { + const services = this._.context.services; + const util = this._.context.util; + const svc_xdIncoming = services.get('xd-incoming'); + svc_xdIncoming.register_tagged_listener('puter-fs', event => { + util.rpc.send(event.source, event.data.$callback, [example]); + }); + } +} diff --git a/src/puter-js/src/services/Filesystem.js b/src/puter-js/src/services/Filesystem.js index 0c30e805..746290d4 100644 --- a/src/puter-js/src/services/Filesystem.js +++ b/src/puter-js/src/services/Filesystem.js @@ -1,4 +1,9 @@ import putility from "@heyputer/putility"; +import { PuterAPIFilesystem } from "../lib/filesystem/APIFS"; +import { CachedFilesystem } from "../lib/filesystem/CacheFS"; +import { ProxyFilesystem, TFilesystem } from "../lib/filesystem/definitions"; +import io from '../lib/socket.io/socket.io.esm.min.js'; +import { PostMessageFilesystem } from "../lib/filesystem/PostMessageFS.js"; export class FilesystemService extends putility.concepts.Service { static PROPERTIES = { @@ -23,9 +28,44 @@ export class FilesystemService extends putility.concepts.Service { _init () { console.log('does this init get called'); + + const env = this._.context.env; + + if ( env === 'app' ) { + // TODO: uncomment when relay is ready + // this.init_app_fs_(); + + this.init_top_fs_(); + } else { + this.init_top_fs_(); + } + this.initializeSocket(); } + init_app_fs_ () { + this.fs_nocache_ = new PostMessageFilesystem({ + messageTarget: window.parent, + rpc: this._.context.util.rpc, + }).as(TFilesystem); + this.filesystem = this.fs_nocache_; + } + init_top_fs_ () { + const api_info = this._.context.services.get('api-access').get_api_info(); + this.fs_nocache_ = new PuterAPIFilesystem({ api_info }).as(TFilesystem); + this.fs_cache_ = new CachedFilesystem({ delegate: this.fs_nocache_ }).as(TFilesystem); + // this.filesystem = this.fs_nocache; + this.fs_proxy_ = new ProxyFilesystem({ delegate: this.fs_nocache_ }); + this.filesystem = this.fs_proxy_.as(TFilesystem); + } + + cache_on () { + this.fs_proxy_.delegate = this.fs_cache_; + } + cache_off () { + this.fs_proxy_.delegate = this.fs_nocache_; + } + initializeSocket () { console.log('THIS IS RUNNING'); if (this.socket) { diff --git a/src/puter-js/src/services/XDIncoming.js b/src/puter-js/src/services/XDIncoming.js index ce5833ea..b8e97b92 100644 --- a/src/puter-js/src/services/XDIncoming.js +++ b/src/puter-js/src/services/XDIncoming.js @@ -18,10 +18,27 @@ export class XDIncomingService extends putility.concepts.Service { fn(event, tp); if ( await tp ) return; } + + const data = event.data; + + const tag = data.$; + if ( ! tag ) return; + if ( ! this.tagged_listeners_[tag] ) return; + + for ( const fn of this.tagged_listeners_[tag] ) { + fn({ data, source: event.source }); + } }); } register_filter_listener (fn) { this.filter_listeners_.push(fn); } + + register_tagged_listener (tag, fn) { + if ( ! this.tagged_listeners_[tag] ) { + this.tagged_listeners_[tag] = []; + } + this.tagged_listeners_[tag].push(fn); + } } diff --git a/src/putility/src/system/ServiceManager.js b/src/putility/src/system/ServiceManager.js index b1829986..e4e45a12 100644 --- a/src/putility/src/system/ServiceManager.js +++ b/src/putility/src/system/ServiceManager.js @@ -77,6 +77,10 @@ class ServiceManager extends AdvancedBase { } return info.instance; } + async aget (name) { + await this.wait_for_init([name]); + return this.get(name); + } /** * Wait for the specified list of services to be initialized.