You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
6.8 KiB

2 years ago
  1. //////////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // WebSocketServer.swift
  4. // Starscream
  5. //
  6. // Created by Dalton Cherry on 4/5/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. #if canImport(Network)
  23. import Foundation
  24. import Network
  25. /// WebSocketServer is a Network.framework implementation of a WebSocket server
  26. @available(watchOS, unavailable)
  27. @available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *)
  28. public class WebSocketServer: Server, ConnectionDelegate {
  29. public var onEvent: ((ServerEvent) -> Void)?
  30. private var connections = [String: ServerConnection]()
  31. private var listener: NWListener?
  32. private let queue = DispatchQueue(label: "com.vluxe.starscream.server.networkstream", attributes: [])
  33. public init() {
  34. }
  35. public func start(address: String, port: UInt16) -> Error? {
  36. //TODO: support TLS cert adding/binding
  37. let parameters = NWParameters(tls: nil, tcp: NWProtocolTCP.Options())
  38. let p = NWEndpoint.Port(rawValue: port)!
  39. parameters.requiredLocalEndpoint = NWEndpoint.hostPort(host: NWEndpoint.Host.name(address, nil), port: p)
  40. guard let listener = try? NWListener(using: parameters, on: p) else {
  41. return WSError(type: .serverError, message: "unable to start the listener at: \(address):\(port)", code: 0)
  42. }
  43. listener.newConnectionHandler = {[weak self] conn in
  44. let transport = TCPTransport(connection: conn)
  45. let c = ServerConnection(transport: transport)
  46. c.delegate = self
  47. self?.connections[c.uuid] = c
  48. }
  49. // listener.stateUpdateHandler = { state in
  50. // switch state {
  51. // case .ready:
  52. // print("ready to get sockets!")
  53. // case .setup:
  54. // print("setup to get sockets!")
  55. // case .cancelled:
  56. // print("server cancelled!")
  57. // case .waiting(let error):
  58. // print("waiting error: \(error)")
  59. // case .failed(let error):
  60. // print("server failed: \(error)")
  61. // @unknown default:
  62. // print("wat?")
  63. // }
  64. // }
  65. self.listener = listener
  66. listener.start(queue: queue)
  67. return nil
  68. }
  69. public func didReceive(event: ServerEvent) {
  70. onEvent?(event)
  71. switch event {
  72. case .disconnected(let conn, _, _):
  73. guard let conn = conn as? ServerConnection else {
  74. return
  75. }
  76. connections.removeValue(forKey: conn.uuid)
  77. default:
  78. break
  79. }
  80. }
  81. }
  82. @available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *)
  83. public class ServerConnection: Connection, HTTPServerDelegate, FramerEventClient, FrameCollectorDelegate, TransportEventClient {
  84. let transport: TCPTransport
  85. private let httpHandler = FoundationHTTPServerHandler()
  86. private let framer = WSFramer(isServer: true)
  87. private let frameHandler = FrameCollector()
  88. private var didUpgrade = false
  89. public var onEvent: ((ConnectionEvent) -> Void)?
  90. public weak var delegate: ConnectionDelegate?
  91. private let id: String
  92. var uuid: String {
  93. return id
  94. }
  95. init(transport: TCPTransport) {
  96. self.id = UUID().uuidString
  97. self.transport = transport
  98. transport.register(delegate: self)
  99. httpHandler.register(delegate: self)
  100. framer.register(delegate: self)
  101. frameHandler.delegate = self
  102. }
  103. public func write(data: Data, opcode: FrameOpCode) {
  104. let wsData = framer.createWriteFrame(opcode: opcode, payload: data, isCompressed: false)
  105. transport.write(data: wsData, completion: {_ in })
  106. }
  107. // MARK: - TransportEventClient
  108. public func connectionChanged(state: ConnectionState) {
  109. switch state {
  110. case .connected:
  111. break
  112. case .waiting:
  113. break
  114. case .failed(let error):
  115. print("server connection error: \(error ?? WSError(type: .protocolError, message: "default error, no extra data", code: 0))") //handleError(error)
  116. case .viability(_):
  117. break
  118. case .shouldReconnect(_):
  119. break
  120. case .receive(let data):
  121. if didUpgrade {
  122. framer.add(data: data)
  123. } else {
  124. httpHandler.parse(data: data)
  125. }
  126. case .cancelled:
  127. print("server connection cancelled!")
  128. //broadcast(event: .cancelled)
  129. }
  130. }
  131. /// MARK: - HTTPServerDelegate
  132. public func didReceive(event: HTTPEvent) {
  133. switch event {
  134. case .success(let headers):
  135. didUpgrade = true
  136. let response = httpHandler.createResponse(headers: [:])
  137. transport.write(data: response, completion: {_ in })
  138. delegate?.didReceive(event: .connected(self, headers))
  139. onEvent?(.connected(headers))
  140. case .failure(let error):
  141. onEvent?(.error(error))
  142. }
  143. }
  144. /// MARK: - FrameCollectorDelegate
  145. public func frameProcessed(event: FrameEvent) {
  146. switch event {
  147. case .frame(let frame):
  148. frameHandler.add(frame: frame)
  149. case .error(let error):
  150. onEvent?(.error(error))
  151. }
  152. }
  153. public func didForm(event: FrameCollector.Event) {
  154. switch event {
  155. case .text(let string):
  156. delegate?.didReceive(event: .text(self, string))
  157. onEvent?(.text(string))
  158. case .binary(let data):
  159. delegate?.didReceive(event: .binary(self, data))
  160. onEvent?(.binary(data))
  161. case .pong(let data):
  162. delegate?.didReceive(event: .pong(self, data))
  163. onEvent?(.pong(data))
  164. case .ping(let data):
  165. delegate?.didReceive(event: .ping(self, data))
  166. onEvent?(.ping(data))
  167. case .closed(let reason, let code):
  168. delegate?.didReceive(event: .disconnected(self, reason, code))
  169. onEvent?(.disconnected(reason, code))
  170. case .error(let error):
  171. onEvent?(.error(error))
  172. }
  173. }
  174. public func decompress(data: Data, isFinal: Bool) -> Data? {
  175. return nil
  176. }
  177. }
  178. #endif