summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2021-06-28 14:33:53 -0400
committerJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2021-06-29 21:00:10 -0400
commit3a6cb756b438c9de44986544ac9b78f8a0311fa1 (patch)
tree535f0669c7be498e3e4d2f7a301d4198afca2396
downloadiono-3a6cb756b438c9de44986544ac9b78f8a0311fa1.tar.gz
iono-3a6cb756b438c9de44986544ac9b78f8a0311fa1.tar.bz2
iono-3a6cb756b438c9de44986544ac9b78f8a0311fa1.zip
Initial Commit
-rw-r--r--.gitignore3
-rw-r--r--.gitmodules3
-rwxr-xr-xbootstrap4
-rw-r--r--iono.xcodeproj/project.pbxproj335
-rw-r--r--iono.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--iono.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist8
-rw-r--r--iono/iono-Bridging-Header.h5
-rw-r--r--iono/iono.cpp311
-rw-r--r--iono/iono.hpp56
-rw-r--r--iono/iono.swift113
m---------ios-node-v80
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, &notifyCallback);
+ 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