From fb476e123b5771ba1cf43b9b8210fca3543cc596 Mon Sep 17 00:00:00 2001 From: Joseph Werle Date: Tue, 1 Aug 2023 10:45:18 +0200 Subject: [PATCH] refactor(): 'socket://' URI wip --- api/module.js | 26 +++++++---- api/path/path.js | 36 +++++++++------ src/desktop/main.cc | 6 ++- src/ipc/bridge.cc | 108 +++++++++++++++++++++++++++++++++----------- 4 files changed, 123 insertions(+), 53 deletions(-) diff --git a/api/module.js b/api/module.js index ed0c24ea90..18745ebe46 100644 --- a/api/module.js +++ b/api/module.js @@ -8,6 +8,7 @@ import { ModuleNotFoundError } from './errors.js' import { ErrorEvent, Event } from './events.js' import { Headers } from './ipc.js' +import { config } from './application.js' import { Stats } from './fs/stats.js' import * as exports from './module.js' @@ -76,7 +77,7 @@ function request (url) { ANDROID_ASSET_HTTP_PROTOCOL_PREFIX ) - if (/^https?:/.test(globalThis.location?.href || '') && (url.startsWith('/') || url.startsWith('\\'))) { + if (/^(https?|socket):/.test(globalThis.location?.href || '') && (url.startsWith('/') || url.startsWith('\\'))) { const base = globalThis.location?.href if (path.extname(base)) { url = new URL(url, path.dirname(base)) @@ -90,10 +91,11 @@ function request (url) { const isAndroidAssetRequest = String(url) .includes(ANDROID_ASSET_HTTP_PROTOCOL_PREFIX) - if (!isAndroidAssetRequest && !exists(url)) { - return {} - } + //if (!isAndroidAssetRequest && !exists(url)) { + //return {} + //} + console.log('GET %s', url) request.open('GET', url, false) request.send(null) @@ -186,7 +188,10 @@ export const COMMONJS_WRAPPER = CommonJSModuleScope * @type {string} */ export const MAIN_SOURCE_URL = ( - globalThis.location?.href || `file://${process.cwd() || ''}` + globalThis.location?.href?.includes?.(ANDROID_ASSET_HTTP_PROTOCOL_PREFIX) + ? globalThis.location.href + : `socket://${config.meta_bundle_identifier}/index.html` + //globalThis.location?.href || `file://${process.cwd() || ''}` ) /** @@ -424,11 +429,7 @@ export class Module extends EventTarget { * @type {URL} */ get url () { - return String( - this.sourceURL?.startsWith('.') - ? new URL(this.id, Module.main.sourceURL) - : new URL(this.sourceURL, Module.main.sourceURL) - ) + return String(new URL(this.sourceURL, Module.main.sourceURL)) } /** @@ -464,6 +465,7 @@ export class Module extends EventTarget { } } + console.log({ queries }) for (const query of queries) { const result = request(query) if (result.response) { @@ -473,6 +475,7 @@ export class Module extends EventTarget { } if (!this.loaded) { + console.log({ url }) loadPackage(this, url) } @@ -497,12 +500,15 @@ export class Module extends EventTarget { } while (dirname !== root && --max > 0) { + console.log('JOIN', path.join(dirname, prefix, this.sourceURL)) paths.add(path.join(dirname, prefix, this.sourceURL)) dirname = path.dirname(dirname) } + console.log({ paths }) for (const prefixed of paths) { const url = String(new URL(prefixed, Module.main.id)) + console.log({ url }) if (loadPackage(this, url)) { break } diff --git a/api/path/path.js b/api/path/path.js index 3e028c05a6..9df45fc8c9 100644 --- a/api/path/path.js +++ b/api/path/path.js @@ -86,8 +86,8 @@ export class Path extends URL { static relative (options, from, to) { const { sep } = options if (from === to) return '' - from = this.resolve(options, from).replace('file:', '') - to = this.resolve(options, to).replace('file:', '') + from = this.resolve(options, from).replace('socket:', '') + to = this.resolve(options, to).replace('socket:', '') const components = { output: [], @@ -115,7 +115,7 @@ export class Path extends URL { .filter(Boolean) ) - const relative = components.output.join(sep).replace(/^file:/g, '') + const relative = components.output.join(sep).replace(/^socket:/g, '') if (windowsDriveRegex.test(from) || windowsDriveRegex.test(to)) { return relative.replace(windowsDriveRegex, '') @@ -137,7 +137,7 @@ export class Path extends URL { while (components.length) { const component = String(components.shift() || '') - const parts = component.split(sep) + const parts = component.split(sep).filter(Boolean) while (parts.length) { queries.push(parts.shift()) } @@ -147,7 +147,13 @@ export class Path extends URL { if (query === '..' && joined.length > 1 && joined[0] !== '..') { joined.pop() } else if (query !== '.') { - joined.push(query) + if (query.startsWith(sep)) { + joined.push(query.slice(1)) + } else if (query.endsWith(sep)) { + joined.push(query.slice(0, query.length - 1)) + } else { + joined.push(query) + } } } @@ -162,11 +168,11 @@ export class Path extends URL { */ static dirname (options, path) { const { sep } = options - const protocol = path.startsWith('file://') - ? 'file://' - : path.startsWith('file:') ? 'file:' : '' + const protocol = path.startsWith('socket://') + ? 'socket://' + : path.startsWith('socket:') ? 'socket:' : '' - path = path.replace('file://', '') + path = path.replace('socket://', '') if (isWin32 && windowsDriveInPathRegex.test(path)) { path = path.slice(1) @@ -283,8 +289,8 @@ export class Path extends URL { if (!drive) { if ( - url.protocol !== 'file:' || - (url.protocol === 'file:' && path.startsWith('file:')) + url.protocol !== 'socket:' || + (url.protocol === 'socket:' && path.startsWith('socket:')) ) { if (protocolStrictSlashesRegex.test(path)) { output = url.protocol + '//' + url.hostname + output @@ -376,14 +382,14 @@ export class Path extends URL { pathname = String(pathname || '.').trim() if (cwd) { - cwd = new URL(`file://${cwd.replace('file://', '')}`) + cwd = new URL(`socket://${cwd.replace('socket://', '')}`) } else if (pathname.startsWith('..')) { pathname = pathname.slice(2) - cwd = 'file://..' + cwd = 'socket://..' } else if (isRelative) { - cwd = new URL('file://.') + cwd = new URL('socket://.') } else { - cwd = new URL(`file://${Path.cwd()}`) + cwd = new URL(`socket://${Path.cwd()}`) } super(pathname, cwd) diff --git a/src/desktop/main.cc b/src/desktop/main.cc index 40f81685e0..bd3ae6f3de 100644 --- a/src/desktop/main.cc +++ b/src/desktop/main.cc @@ -993,7 +993,11 @@ MAIN { ";" )); } else { - defaultWindow->navigate(EMPTY_SEQ, "file://" + (fs::path(cwd) / "index.html").string()); + //defaultWindow->navigate(EMPTY_SEQ, "file://" + (fs::path(cwd) / "index.html").string()); + defaultWindow->navigate( + EMPTY_SEQ, + "socket://" + (fs::path(app.appData["meta_bundle_identifier"]) / "index.html").string() + ); } // diff --git a/src/ipc/bridge.cc b/src/ipc/bridge.cc index 59194f1fad..9c858cde93 100644 --- a/src/ipc/bridge.cc +++ b/src/ipc/bridge.cc @@ -1,6 +1,8 @@ #include "ipc.hh" #include "../extension/extension.hh" +#include + #define SOCKET_MODULE_CONTENT_TYPE "text/javascript" #define IPC_BINARY_CONTENT_TYPE "application/octet-stream" #define IPC_JSON_CONTENT_TYPE "text/json" @@ -1517,6 +1519,9 @@ static void registerSchemeHandler (Router *router) { @implementation SSCIPCSchemeHandler - (void) webView: (SSCBridgedWebView*) webview stopURLSchemeTask: (Task) task {} - (void) webView: (SSCBridgedWebView*) webview startURLSchemeTask: (Task) task { + static auto userConfig = SSC::getUserConfig(); + static auto bundleIdentifier = userConfig["meta_bundle_identifier"]; + auto request = task.request; auto url = String(request.URL.absoluteString.UTF8String); auto message = Message {url}; @@ -1545,14 +1550,17 @@ static void registerSchemeHandler (Router *router) { } if (String(request.URL.scheme.UTF8String) == "socket") { + auto host = request.URL.host; auto headers = [NSMutableDictionary dictionary]; auto components = [NSURLComponents componentsWithURL: request.URL resolvingAgainstBaseURL: YES ]; + String moduleSource = ""; + components.scheme = @"file"; - components.host = @""; + components.host = request.URL.host; auto path = String(components.path.UTF8String); auto ext = String( @@ -1561,34 +1569,83 @@ static void registerSchemeHandler (Router *router) { : ".js" ); - #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR - components.path = [[[NSBundle mainBundle] resourcePath] - stringByAppendingPathComponent: [NSString - stringWithFormat: @"/ui/socket/%s%s", path.c_str(), ext.c_str() - ] - ]; - #else - components.path = [[[NSBundle mainBundle] resourcePath] - stringByAppendingPathComponent: [NSString - stringWithFormat: @"/socket/%s%s", path.c_str(), ext.c_str() - ] - ]; - #endif + if ( + host.UTF8String != nullptr && + String(host.UTF8String) == bundleIdentifier + ) { + #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + components.path = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent: [NSString + stringWithFormat: @"/ui/%s", request.URL.path.UTF8String + ] + ]; + #else + components.path = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent: [NSString + stringWithFormat: @"/%s", request.URL.path.UTF8String + ] + ]; + #endif - auto data = [NSData dataWithContentsOfURL: components.URL]; + } else { + #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + components.path = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent: [NSString + stringWithFormat: @"/ui/socket/%s%s", path.c_str(), ext.c_str() + ] + ]; + #else + components.path = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent: [NSString + stringWithFormat: @"/socket/%s%s", path.c_str(), ext.c_str() + ] + ]; + #endif - auto moduleSource = trim(tmpl( - moduleTemplate, - Map { {"url", String(components.URL.absoluteString.UTF8String)} } - )); + moduleSource = trim(tmpl( + moduleTemplate, + Map { {"url", String(components.URL.absoluteString.UTF8String)} } + )); + } + + auto data = [NSData dataWithContentsOfURL: components.URL]; headers[@"access-control-allow-origin"] = @"*"; headers[@"access-control-allow-methods"] = @"*"; headers[@"access-control-allow-headers"] = @"*"; - headers[@"content-location"] = components.URL.absoluteString; - headers[@"content-length"] = [@(moduleSource.size()) stringValue]; - headers[@"content-type"] = @"text/javascript"; + headers[@"content-location"] = request.URL.absoluteString; + + if (moduleSource.size() > 0 && data.length > 0) { + headers[@"content-length"] = [@(moduleSource.size()) stringValue]; + headers[@"content-type"] = @"text/javascript"; + components.host = @(userConfig["meta_bundle_identifier"].c_str()); + #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + components.path = [NSString + stringWithFormat: @"/ui/socket/%s%s", path.c_str(), ext.c_str() + ]; + #else + components.path = [NSString + stringWithFormat: @"/socket/%s%s", path.c_str(), ext.c_str() + ]; + #endif + } else { + auto types = [UTType + typesWithTag: request.URL.pathExtension + tagClass: UTTagClassFilenameExtension + conformingToType: nullptr + ]; + + headers[@"content-length"] = [@(data.length) stringValue]; + + if (types.count > 0 && types.firstObject.preferredMIMEType) { + headers[@"content-type"] = types.firstObject.preferredMIMEType; + } + + components.path = request.URL.path; + } + + components.scheme = @("socket"); auto response = [[NSHTTPURLResponse alloc] initWithURL: components.URL @@ -1599,11 +1656,8 @@ static void registerSchemeHandler (Router *router) { [task didReceiveResponse: response]; - if (data != nullptr) { - [task didReceiveData: [NSData - dataWithBytes: moduleSource.data() - length: moduleSource.size() - ]]; + if (data.length > 0) { + [task didReceiveData: data]; } [task didFinish];