NativeEngine.swift 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. //////////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // NativeEngine.swift
  4. // Starscream
  5. //
  6. // Created by Dalton Cherry on 6/15/19
  7. // Copyright © 2019 Vluxe. All rights reserved.
  8. //
  9. // Licensed under the Apache License, Version 2.0 (the "License");
  10. // you may not use this file except in compliance with the License.
  11. // You may obtain a copy of the License at
  12. //
  13. // http://www.apache.org/licenses/LICENSE-2.0
  14. //
  15. // Unless required by applicable law or agreed to in writing, software
  16. // distributed under the License is distributed on an "AS IS" BASIS,
  17. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. // See the License for the specific language governing permissions and
  19. // limitations under the License.
  20. //
  21. //////////////////////////////////////////////////////////////////////////////////////////////////
  22. import Foundation
  23. @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
  24. public class NativeEngine: NSObject, Engine, URLSessionDataDelegate, URLSessionWebSocketDelegate {
  25. private var task: URLSessionWebSocketTask?
  26. weak var delegate: EngineDelegate?
  27. public func register(delegate: EngineDelegate) {
  28. self.delegate = delegate
  29. }
  30. public func start(request: URLRequest) {
  31. let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
  32. task = session.webSocketTask(with: request)
  33. doRead()
  34. task?.resume()
  35. }
  36. public func stop(closeCode: UInt16) {
  37. let closeCode = URLSessionWebSocketTask.CloseCode(rawValue: Int(closeCode)) ?? .normalClosure
  38. task?.cancel(with: closeCode, reason: nil)
  39. }
  40. public func forceStop() {
  41. stop(closeCode: UInt16(URLSessionWebSocketTask.CloseCode.abnormalClosure.rawValue))
  42. }
  43. public func write(string: String, completion: (() -> ())?) {
  44. task?.send(.string(string), completionHandler: { (error) in
  45. completion?()
  46. })
  47. }
  48. public func write(data: Data, opcode: FrameOpCode, completion: (() -> ())?) {
  49. switch opcode {
  50. case .binaryFrame:
  51. task?.send(.data(data), completionHandler: { (error) in
  52. completion?()
  53. })
  54. case .textFrame:
  55. let text = String(data: data, encoding: .utf8)!
  56. write(string: text, completion: completion)
  57. case .ping:
  58. task?.sendPing(pongReceiveHandler: { (error) in
  59. completion?()
  60. })
  61. default:
  62. break //unsupported
  63. }
  64. }
  65. private func doRead() {
  66. task?.receive { [weak self] (result) in
  67. switch result {
  68. case .success(let message):
  69. switch message {
  70. case .string(let string):
  71. self?.broadcast(event: .text(string))
  72. case .data(let data):
  73. self?.broadcast(event: .binary(data))
  74. @unknown default:
  75. break
  76. }
  77. break
  78. case .failure(let error):
  79. self?.broadcast(event: .error(error))
  80. return
  81. }
  82. self?.doRead()
  83. }
  84. }
  85. private func broadcast(event: WebSocketEvent) {
  86. delegate?.didReceive(event: event)
  87. }
  88. public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
  89. let p = `protocol` ?? ""
  90. broadcast(event: .connected([HTTPWSHeader.protocolName: p]))
  91. }
  92. public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
  93. var r = ""
  94. if let d = reason {
  95. r = String(data: d, encoding: .utf8) ?? ""
  96. }
  97. broadcast(event: .disconnected(r, UInt16(closeCode.rawValue)))
  98. }
  99. public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
  100. broadcast(event: .error(error))
  101. }
  102. }