summaryrefslogtreecommitdiff
path: root/iono/iono.swift
diff options
context:
space:
mode:
Diffstat (limited to 'iono/iono.swift')
-rw-r--r--iono/iono.swift148
1 files changed, 114 insertions, 34 deletions
diff --git a/iono/iono.swift b/iono/iono.swift
index 23e0104..1f07140 100644
--- a/iono/iono.swift
+++ b/iono/iono.swift
@@ -27,48 +27,127 @@ func notification_callback(payload: Optional<UnsafePointer<Int8>>,
native.internalOnNotify(payload: string)
}
+struct Queue<T> {
+ var contents: [T]
+
+ init() {
+ self.contents = []
+ }
+
+ mutating func push(_ element: T) {
+ contents.append(element)
+ }
+
+ mutating func pop() -> T? {
+ if (contents.isEmpty) {
+ return nil
+ } else {
+ return contents.remove(at: 0)
+ }
+ }
+}
+
+class NodeThread: Thread {
+ var iono: Iono!
+ var workQueue: Queue<() -> ()>
+ var initialized: Bool
+ var initCondition: NSCondition
+
+ override init() {
+ self.workQueue = Queue<() -> ()>()
+ self.initialized = false
+ self.initCondition = NSCondition()
+ super.init()
+ }
+
+ override func main() {
+ iono.instance = __initNative()
+ __setNotifyHandler(iono.instance, notification_callback, Unmanaged.passUnretained(iono).toOpaque())
+ self.initialized = true
+ initCondition.broadcast()
+ while true {
+ __runNode(iono.instance)
+ while let workItem = workQueue.pop() {
+ workItem()
+ }
+ if iono.stopped {
+ break
+ }
+ }
+ }
+
+ func waitUntilInitialized(block: @escaping () -> ()) {
+ if (self.initialized) {
+ block()
+ return
+ }
+
+ initCondition.lock()
+ while (!self.initialized) {
+ initCondition.wait()
+ }
+
+ block()
+
+ initCondition.unlock()
+ }
+}
+
public class Iono {
+ var stopped: Bool
+ var thread: NodeThread
+
var instance: OpaquePointer!
- var work_queue: DispatchQueue
- var initialization_group: DispatchGroup
- var messageHandler: IonoMessageHandler?
-
- public 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())
- }
+ public var messageHandler: IonoMessageHandler?
+
+ public init() { // We need to be calling runNode!
+ self.stopped = false
+ self.thread = NodeThread()
+ self.thread.iono = self
+
+ self.thread.start()
}
-
+
deinit {
__destroyNative(instance)
}
-
- private func scheduleNodeThreadAsync(block: @escaping () -> Void) {
- initialization_group.wait()
- work_queue.async(execute: block)
- notifyNative()
+
+ private func scheduleNodeThreadAsync(block: @escaping () -> ()) {
+ thread.waitUntilInitialized {
+ self.thread.workQueue.push(block)
+ self.notifyNative()
+ }
}
-
+
private func scheduleNodeThreadSync(block: @escaping () -> Void) {
- initialization_group.wait()
- work_queue.sync(execute: block)
- notifyNative()
+ var hasExecuted = false
+ let executeCondition = NSCondition()
+
+ executeCondition.lock()
+ thread.waitUntilInitialized {
+ self.thread.workQueue.push {
+ block()
+ hasExecuted = true
+ executeCondition.broadcast()
+ }
+ self.notifyNative()
+ }
+ while (!hasExecuted) {
+ executeCondition.wait()
+ }
+ executeCondition.unlock()
}
-
+
public func internalOnNotify(payload: String) {
if let handler = messageHandler {
handler.handleMessage(message: payload)
}
}
-
+
public func notifyNative() {
- initialization_group.wait()
__notifyNative(instance)
}
-
+
public func evalSimpleJs(source: String) -> String {
var result: String?
scheduleNodeThreadSync {
@@ -80,13 +159,13 @@ public class Iono {
}
return result!
}
-
+
public func evalNodeCode(source: String) {
scheduleNodeThreadAsync {
__makeCallbackNative(self.instance, source.cString(using: .utf8))
}
}
-
+
public func sendMessage(message: String) {
let encoded = message.data(using: .utf8)!.base64EncodedString()
let source = """
@@ -99,15 +178,16 @@ public class Iono {
"""
evalNodeCode(source: source)
}
-
+
public func waitStopped() {
-
- }
-
- public func putModuleCode(modName: String, code: String) {
scheduleNodeThreadSync {
- __putModuleCodeNative(self.instance, modName.cString(using: .utf8),
- code.cString(using: .utf8))
+ self.stopped = true
}
+ thread.cancel()
+ }
+
+ public func putModuleCode(modName: String, code: String) {
+ __putModuleCodeNative(self.instance, modName.cString(using: .utf8),
+ code.cString(using: .utf8))
}
}