1 import Foundation
2 
3 class EXDevLauncherRemoteLogsManager {
4   private var batch: [String] = []
5   private let url: URL
6 
7   init(withUrl url: URL) {
8     self.url = url
9   }
10 
deferErrornull11   func deferError(exception: NSException) {
12     batch.append("\(exception.name.rawValue): \(exception.reason ?? exception.description)")
13     batch.append("  \(exception.callStackSymbols.joined(separator: "\n  "))")
14   }
15 
deferErrornull16   func deferError(message: String) {
17     batch.append(message)
18   }
19 
sendSyncnull20   func sendSync() {
21     // message format comes from
22     // https://github.com/facebook/react-native/blob/0.69-stable/Libraries/Utilities/HMRClient.js#L119-L134
23     let messageJson = [
24       "type": "log",
25       "level": "error",
26       "mode": "BRIDGE",
27       // `data` is an array whose members are simply concatenated with a space before printing to
28       // the console, so we join messages with a newline and send an array consisting of just a
29       // single item.
30       "data": [batch.joined(separator: "\n")]
31     ] as [String: Any]
32     guard let data = try? JSONSerialization.data(withJSONObject: messageJson, options: []) else {
33       batch.removeAll()
34       return
35     }
36 
37     batch.removeAll()
38 
39     if #available(iOS 13.0, *) {
40       let group = DispatchGroup()
41       group.enter()
42 
43       let task = URLSession.shared.webSocketTask(with: self.url)
44       task.resume()
45 
46       guard let dataString = String(data: data, encoding: .utf8) else {
47         group.leave()
48         return
49       }
50       let message = URLSessionWebSocketTask.Message.string(dataString)
51       task.send(message) { _ in
52         group.leave()
53       }
54       _ = group.wait(timeout: DispatchTime.now() + .seconds(2))
55     }
56   }
57 }
58