JavaScriptWorker.swift 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. //
  2. // JavaScriptWorker.swift
  3. // FreeAPS
  4. //
  5. // Created by Ivan Valkou on 29.01.2021.
  6. //
  7. import Foundation
  8. import JavaScriptCore
  9. private let contextLock = NSRecursiveLock()
  10. final class JavaScriptWorker {
  11. private let processQueue = DispatchQueue(label: "DispatchQueue.JavaScriptWorker")
  12. private let virtualMachine: JSVirtualMachine
  13. @SyncAccess(lock: contextLock) private var commonContext: JSContext? = nil
  14. init() {
  15. virtualMachine = processQueue.sync { JSVirtualMachine()! }
  16. }
  17. private func createContext() -> JSContext {
  18. let context = JSContext(virtualMachine: virtualMachine)!
  19. context.exceptionHandler = { _, exception in
  20. if let error = exception?.toString() {
  21. print(error)
  22. }
  23. }
  24. return context
  25. }
  26. @discardableResult
  27. func evaluate(script: Script) -> JSValue! {
  28. evaluate(string: script.body)
  29. }
  30. private func evaluate(string: String) -> JSValue! {
  31. let ctx = commonContext ?? createContext()
  32. return ctx.evaluateScript(string)
  33. }
  34. private func json(for string: String) -> JSON {
  35. evaluate(string: "JSON.stringify(\(string));")!.toString()!
  36. }
  37. func call(function: String, with arguments: [JSON]) -> JSON {
  38. let joined = arguments.map(\.string).joined(separator: ",")
  39. return json(for: "\(function)(\(joined))")
  40. }
  41. func inCommonContext<Value>(execute: (JavaScriptWorker) -> Value) -> Value{
  42. commonContext = createContext()
  43. defer {
  44. commonContext = nil
  45. }
  46. return execute(self)
  47. }
  48. }