diff options
author | Jonathan Buchanan <jonathan.russ.buchanan@gmail.com> | 2021-06-28 14:33:53 -0400 |
---|---|---|
committer | Jonathan Buchanan <jonathan.russ.buchanan@gmail.com> | 2021-06-29 21:00:10 -0400 |
commit | 3a6cb756b438c9de44986544ac9b78f8a0311fa1 (patch) | |
tree | 535f0669c7be498e3e4d2f7a301d4198afca2396 | |
download | iono-3a6cb756b438c9de44986544ac9b78f8a0311fa1.tar.gz iono-3a6cb756b438c9de44986544ac9b78f8a0311fa1.tar.bz2 iono-3a6cb756b438c9de44986544ac9b78f8a0311fa1.zip |
Initial Commit
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rwxr-xr-x | bootstrap | 4 | ||||
-rw-r--r-- | iono.xcodeproj/project.pbxproj | 335 | ||||
-rw-r--r-- | iono.xcodeproj/project.xcworkspace/contents.xcworkspacedata | 7 | ||||
-rw-r--r-- | iono.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist | 8 | ||||
-rw-r--r-- | iono/iono-Bridging-Header.h | 5 | ||||
-rw-r--r-- | iono/iono.cpp | 311 | ||||
-rw-r--r-- | iono/iono.hpp | 56 | ||||
-rw-r--r-- | iono/iono.swift | 113 | ||||
m--------- | ios-node-v8 | 0 |
11 files changed, 845 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d88e59c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +compiled/ +iono.xcodeproj/xcuserdata/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8f8c8d9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ios-node-v8"] + path = ios-node-v8 + url = ssh://git@git.taler.net/ios-node-v8.git diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..33aed72 --- /dev/null +++ b/bootstrap @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +xcodebuild -project iono.xcodeproj/ -target iono -arch arm64 CONFIGURATION_BUILD_DIR=./compiled/arm64 build +xcodebuild -project iono.xcodeproj/ -target iono -arch x86_64 -sdk iphonesimulator14.5 CONFIGURATION_BUILD_DIR=./compiled/x64 build diff --git a/iono.xcodeproj/project.pbxproj b/iono.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f4d27b6 --- /dev/null +++ b/iono.xcodeproj/project.pbxproj @@ -0,0 +1,335 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + D1178623268A4D8D00B63B20 /* iono.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1178622268A4D8D00B63B20 /* iono.swift */; }; + D117862C268A4E6900B63B20 /* iono.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D117862A268A4E6900B63B20 /* iono.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + D117861D268A4D8D00B63B20 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + D117861F268A4D8D00B63B20 /* libiono.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libiono.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D1178622268A4D8D00B63B20 /* iono.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iono.swift; sourceTree = "<group>"; }; + D1178629268A4E6900B63B20 /* iono-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iono-Bridging-Header.h"; sourceTree = "<group>"; }; + D117862A268A4E6900B63B20 /* iono.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = iono.cpp; sourceTree = "<group>"; }; + D117862B268A4E6900B63B20 /* iono.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = iono.hpp; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D117861C268A4D8D00B63B20 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D1178616268A4D8D00B63B20 = { + isa = PBXGroup; + children = ( + D1178621268A4D8D00B63B20 /* iono */, + D1178620268A4D8D00B63B20 /* Products */, + ); + sourceTree = "<group>"; + }; + D1178620268A4D8D00B63B20 /* Products */ = { + isa = PBXGroup; + children = ( + D117861F268A4D8D00B63B20 /* libiono.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + D1178621268A4D8D00B63B20 /* iono */ = { + isa = PBXGroup; + children = ( + D1178622268A4D8D00B63B20 /* iono.swift */, + D117862A268A4E6900B63B20 /* iono.cpp */, + D117862B268A4E6900B63B20 /* iono.hpp */, + D1178629268A4E6900B63B20 /* iono-Bridging-Header.h */, + ); + path = iono; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D117861E268A4D8D00B63B20 /* iono */ = { + isa = PBXNativeTarget; + buildConfigurationList = D1178626268A4D8D00B63B20 /* Build configuration list for PBXNativeTarget "iono" */; + buildPhases = ( + D117861B268A4D8D00B63B20 /* Sources */, + D117861C268A4D8D00B63B20 /* Frameworks */, + D117861D268A4D8D00B63B20 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = iono; + productName = iono; + productReference = D117861F268A4D8D00B63B20 /* libiono.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D1178617268A4D8D00B63B20 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1250; + LastUpgradeCheck = 1250; + TargetAttributes = { + D117861E268A4D8D00B63B20 = { + CreatedOnToolsVersion = 12.5.1; + LastSwiftMigration = 1250; + }; + }; + }; + buildConfigurationList = D117861A268A4D8D00B63B20 /* Build configuration list for PBXProject "iono" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = D1178616268A4D8D00B63B20; + productRefGroup = D1178620268A4D8D00B63B20 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D117861E268A4D8D00B63B20 /* iono */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D117861B268A4D8D00B63B20 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D117862C268A4E6900B63B20 /* iono.cpp in Sources */, + D1178623268A4D8D00B63B20 /* iono.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + D1178624268A4D8D00B63B20 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = ( + "$(ARCHS_STANDARD)", + x86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/ios-node-v8/src", + "$(PROJECT_DIR)/ios-node-v8/deps/uv/include", + "$(PROJECT_DIR)/ios-node-v8/deps/v8/include", + ); + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + D1178625268A4D8D00B63B20 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = ( + "$(ARCHS_STANDARD)", + x86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/ios-node-v8/src", + "$(PROJECT_DIR)/ios-node-v8/deps/uv/include", + "$(PROJECT_DIR)/ios-node-v8/deps/v8/include", + ); + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + D1178627268A4D8D00B63B20 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "iono/iono-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D1178628268A4D8D00B63B20 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "iono/iono-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D117861A268A4D8D00B63B20 /* Build configuration list for PBXProject "iono" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D1178624268A4D8D00B63B20 /* Debug */, + D1178625268A4D8D00B63B20 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D1178626268A4D8D00B63B20 /* Build configuration list for PBXNativeTarget "iono" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D1178627268A4D8D00B63B20 /* Debug */, + D1178628268A4D8D00B63B20 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D1178617268A4D8D00B63B20 /* Project object */; +} diff --git a/iono.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/iono.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/iono.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:"> + </FileRef> +</Workspace> diff --git a/iono.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iono.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/iono.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IDEDidComputeMac32BitWarning</key> + <true/> +</dict> +</plist> diff --git a/iono/iono-Bridging-Header.h b/iono/iono-Bridging-Header.h new file mode 100644 index 0000000..0711955 --- /dev/null +++ b/iono/iono-Bridging-Header.h @@ -0,0 +1,5 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "iono.hpp" diff --git a/iono/iono.cpp b/iono/iono.cpp new file mode 100644 index 0000000..c101e45 --- /dev/null +++ b/iono/iono.cpp @@ -0,0 +1,311 @@ +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +#include "iono.hpp" + +#include <map> +#include <string> + +#include <node.h> +#include <uv.h> + +#define NODE_WANT_INTERNALS 1 +#include <node_binding.h> + +#include <iostream> + +std::map<std::string, std::string> modmap = std::map<std::string, std::string>(); + +struct __IonoInstance +{ + /* Node/V8 */ + static std::unique_ptr<node::MultiIsolatePlatform> platform; + std::unique_ptr<node::CommonEnvironmentSetup> setup; + v8::Isolate *isolate; + node::Environment *env; + uv_async_t async_notify; + + bool break_requested; + + /* Notifications to swift */ + __NotifyHandler notification_handler; + void *notification_userdata; + + __IonoInstance(); + + char * + evalJs(const char *js); + + void + runNode(); + + void + makeCallback(const char *callback); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +struct __IonoInstance * +__initNative() +{ + __IonoInstance *instance = new __IonoInstance(); + return instance; +} + +void +__destroyNative(struct __IonoInstance *instance) +{ + delete instance; +} + +char * +__evalJs(struct __IonoInstance *instance, const char *js) +{ + return instance->evalJs(js); +} + +void +__putModuleCodeNative(struct __IonoInstance *instance, + const char *modName, const char *modCode) +{ + modmap[std::string(modName)] = std::string(modCode); +} + +void +__notifyNative(struct __IonoInstance *instance) +{ + uv_async_send(&instance->async_notify); +} + +void +__runNode(struct __IonoInstance *instance) +{ + instance->runNode(); +} + +void +__makeCallbackNative(struct __IonoInstance *instance, const char *source) +{ + instance->makeCallback(source); +} + +void +__setNotifyHandler(struct __IonoInstance *instance, __NotifyHandler handler, void *userdata) +{ + instance->notification_handler = handler; + instance->notification_userdata = userdata; +} + +#ifdef __cplusplus +} +#endif + +std::unique_ptr<node::MultiIsolatePlatform> __IonoInstance::platform = nullptr; + +static void +notifyCallback(uv_async_t *async); + +static void +sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args); + +static void +getModuleCode(const v8::FunctionCallbackInfo<v8::Value> &args); + +static const std::string main_code = "const publicRequire =" + " require('module').createRequire(process.cwd() + '/');" + " globalThis.require = publicRequire;" + " require('vm').runInThisContext(process.argv[1]);global.__node_run = (x) => {" + " 0 && console.log('running code', x);" + " global.eval(x);" + "};" + "" + "global.__iono_onMessage = (x) => {" + " 0 && console.log('got __iono_onMessage', x);" + "};"; + +static void +_register_iono(); + +__IonoInstance::__IonoInstance() : + break_requested(false), + notification_handler(nullptr) +{ + { + uv_loop_t *loop = uv_default_loop(); + uv_async_init(loop, &async_notify, ¬ifyCallback); + async_notify.data = this; + } + + std::vector<std::string> args = { "node" }; + std::vector<std::string> exec_args; + std::vector<std::string> errors; + + if (nullptr == platform) + { + int exit_code = node::InitializeNodeWithArgs(&args, &exec_args, &errors); + for (const std::string &error : errors) + { + fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str()); + if (exit_code != 0) + throw "error initializing node"; + } + + platform = node::MultiIsolatePlatform::Create(4); + v8::V8::InitializePlatform(platform.get()); + v8::V8::Initialize(); + } + + setup = node::CommonEnvironmentSetup::Create(platform.get(), &errors, args, exec_args); + if (!setup) { + for (const std::string &err : errors) + fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str()); + //return 1; + } + + isolate = setup->isolate(); + env = setup->env(); + + { + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(setup->context()); + + node::LoadEnvironment(env, main_code.c_str()); + + v8::Local<v8::ObjectTemplate> data_template = v8::ObjectTemplate::New(isolate); + data_template->SetInternalFieldCount(1); + v8::Local<v8::Object> data_object = data_template->NewInstance(setup->context()).ToLocalChecked(); + data_object->SetAlignedPointerInInternalField(0, this); + + v8::Local<v8::Function> sendMessageFunction = v8::Function::New(setup->context(), + sendMessageCallback, + data_object).ToLocalChecked(); + + v8::Local<v8::Object> global = setup->context()->Global(); + + global->Set(setup->context(), v8::String::NewFromUtf8(isolate, "__iono_sendMessage", + v8::NewStringType::kNormal).ToLocalChecked(), + sendMessageFunction).Check(); + _register_iono(); + } +} + +char * +__IonoInstance::evalJs(const char *js) +{ + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(setup->context()); + + // Create a string containing the JavaScript source code. + v8::Local<v8::String> source = + v8::String::NewFromUtf8(isolate, js, v8::NewStringType::kNormal).ToLocalChecked(); + + // Compile the source code. + v8::Local<v8::Script> script; + if (!v8::Script::Compile(setup->context(), source).ToLocal(&script)) { + return nullptr; + } + + // Run the script to get the result. + v8::Local<v8::Value> result; + if (!script->Run(setup->context()).ToLocal(&result)) { + return nullptr; + } + + // Convert the result to an UTF8 string and print it. + v8::String::Utf8Value utf8(isolate, result); + return strdup(*utf8); +} + +void +__IonoInstance::runNode() { + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(setup->context()); + break_requested = false; + while (true) { + uv_run(uv_default_loop(), UV_RUN_ONCE); + platform->DrainTasks(isolate); + if (break_requested) + break; + } +} + +void +__IonoInstance::makeCallback(const char *callback) +{ + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(setup->context()); + v8::Local<v8::Object> global = setup->context()->Global(); + v8::Local<v8::Value> argv[] = { + v8::String::NewFromUtf8(isolate, callback, + v8::NewStringType::kNormal).ToLocalChecked() + }; + node::MakeCallback(isolate, global, "__node_run", 1, argv, {0, 0}); +} + +static void +notifyCallback(uv_async_t *async) { + __IonoInstance *instance = (__IonoInstance *)async->data; + instance->break_requested = true; +} + +static void +sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args) { + v8::Isolate *isolate = args.GetIsolate(); + v8::Locker locker(isolate); + if (args.Length() < 1) + return; + v8::HandleScope scope(isolate); + v8::Local<v8::Value> arg = args[0]; + v8::String::Utf8Value value(isolate, arg); + + v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(args.Data()); + + __IonoInstance *instance = (__IonoInstance *)data->GetAlignedPointerFromInternalField(0); + instance->notification_handler(*value, instance->notification_userdata); +} + +static void +getModuleCode(const v8::FunctionCallbackInfo<v8::Value> &args) { + v8::Isolate *isolate = args.GetIsolate(); + v8::Locker locker(isolate); + if (args.Length() < 1) + return; + v8::HandleScope scope(isolate); + v8::Local<v8::Value> arg = args[0]; + v8::String::Utf8Value value(isolate, arg); + + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, + modmap[*value].c_str()).ToLocalChecked()); +} + +static void +initializeIonoInternal(v8::Local<v8::Object> target, + v8::Local<v8::Value> unused, + v8::Local<v8::Context> context, + void *priv) { + NODE_SET_METHOD(target, "getModuleCode", getModuleCode); +} + +NODE_MODULE_CONTEXT_AWARE_INTERNAL(iono, initializeIonoInternal) diff --git a/iono/iono.hpp b/iono/iono.hpp new file mode 100644 index 0000000..c106389 --- /dev/null +++ b/iono/iono.hpp @@ -0,0 +1,56 @@ +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +#ifndef iono_hpp +#define iono_hpp + +#ifdef __cplusplus +extern "C" { +#endif + +struct __IonoInstance; + +struct __IonoInstance * +__initNative(); + +void +__destroyNative(struct __IonoInstance *instance); + +char * +__evalJs(struct __IonoInstance *instance, const char *source); + +void +__putModuleCodeNative(struct __IonoInstance *instance, + const char *modName, const char *modCode); + +void +__notifyNative(struct __IonoInstance *instance); + +void +__runNode(struct __IonoInstance *instance); + +void +__makeCallbackNative(struct __IonoInstance *instance, const char *source); + +typedef void (* __NotifyHandler)(const char *payload, void *userdata); + +void +__setNotifyHandler(struct __IonoInstance *instance, __NotifyHandler handler, void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif /* node_wrapper_h */ diff --git a/iono/iono.swift b/iono/iono.swift new file mode 100644 index 0000000..77a4ec5 --- /dev/null +++ b/iono/iono.swift @@ -0,0 +1,113 @@ +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import Foundation + +protocol IonoMessageHandler { + func handleMessage(message: String) +} + +func notification_callback(payload: Optional<UnsafePointer<Int8>>, + userdata: Optional<UnsafeMutableRawPointer>) { + let native = Unmanaged<Iono>.fromOpaque(userdata!).takeUnretainedValue() + let string = String(cString: payload!) + native.internalOnNotify(payload: string) +} + +class Iono { + var instance: OpaquePointer! + var work_queue: DispatchQueue + var initialization_group: DispatchGroup + var messageHandler: IonoMessageHandler? + + init() { + work_queue = DispatchQueue(label: "NodeQueue", qos: .userInitiated) + initialization_group = DispatchGroup() + initialization_group.notify(queue: work_queue) { + self.instance = __initNative() + __setNotifyHandler(self.instance, notification_callback, Unmanaged.passUnretained(self).toOpaque()) + } + } + + deinit { + __destroyNative(instance) + } + + private func scheduleNodeThreadAsync(block: @escaping () -> Void) { + initialization_group.wait() + work_queue.async(execute: block) + notifyNative() + } + + private func scheduleNodeThreadSync(block: @escaping () -> Void) { + initialization_group.wait() + work_queue.sync(execute: block) + notifyNative() + } + + func internalOnNotify(payload: String) { + if let handler = messageHandler { + handler.handleMessage(message: payload) + } + } + + func notifyNative() { + initialization_group.wait() + __notifyNative(instance) + } + + func evalSimpleJs(source: String) -> String { + var result: String? + scheduleNodeThreadSync { + let cResult = __evalJs(self.instance, source.cString(using: .utf8)) + if let cStr = cResult { + result = String(cString: cStr) + free(cResult) + } + } + return result! + } + + func evalNodeCode(source: String) { + scheduleNodeThreadAsync { + __makeCallbackNative(self.instance, source.cString(using: .utf8)) + } + } + + func sendMessage(message: String) { + let encoded = message.data(using: .utf8)!.base64EncodedString() + let source = """ + if (global.__iono_onMessage) { + const msg = (new Buffer('\(encoded)', 'base64')).toString('ascii'); + global.__iono_onMessage(msg); + } else { + console.log("WARN: no __iono_onMessage defined"); + } + """ + evalNodeCode(source: source) + } + + func waitStopped() { + + } + + func putModuleCode(modName: String, code: String) { + scheduleNodeThreadSync { + __putModuleCodeNative(self.instance, modName.cString(using: .utf8), + code.cString(using: .utf8)) + } + } +} diff --git a/ios-node-v8 b/ios-node-v8 new file mode 160000 +Subproject 029315b48c8837b48e156f70a2362157716c8d3 |