Document.swift 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Copyright 2016, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Cocoa
  17. import SwiftGRPC
  18. // https://gist.github.com/rickw/cc198001f5f3aa59ae9f
  19. extension NSTextView {
  20. func appendText(line: String) {
  21. if let textStorage = self.textStorage {
  22. textStorage.append(NSAttributedString(string: line + "\n",
  23. attributes: [NSFontAttributeName: NSFont.systemFont(ofSize: 12.0)]))
  24. }
  25. if let contents = self.string {
  26. scrollRangeToVisible(NSRange(location: contents.lengthOfBytes(using: String.Encoding.utf8), length: 0))
  27. }
  28. }
  29. }
  30. // http://stackoverflow.com/a/28976644/35844
  31. func sync(lock: AnyObject, closure: () -> Void) {
  32. objc_sync_enter(lock)
  33. closure()
  34. objc_sync_exit(lock)
  35. }
  36. class Document: NSDocument {
  37. @IBOutlet var hostField: NSTextField!
  38. @IBOutlet var portField: NSTextField!
  39. @IBOutlet var connectionSelector: NSSegmentedControl!
  40. @IBOutlet var startButton: NSButton!
  41. @IBOutlet var textView: NSTextView!
  42. // http://stackoverflow.com/questions/24062437/cannot-form-weak-reference-to-instance-of-class-nstextview
  43. var channel: Channel!
  44. var server: Server!
  45. var running: Bool // all accesses to this should be synchronized
  46. override init() {
  47. running = false
  48. super.init()
  49. }
  50. override func close() {
  51. textView = nil // prevents logging to the textView
  52. stop()
  53. super.close()
  54. }
  55. override var windowNibName: String? {
  56. return "Document"
  57. }
  58. func log(_ line: String) {
  59. DispatchQueue.main.async {
  60. if let view = self.textView {
  61. view.appendText(line: line)
  62. }
  63. }
  64. }
  65. @IBAction func startButtonPressed(sender: NSButton) {
  66. if sender.title == "Start" {
  67. updateInterfaceBeforeStarting()
  68. let address = hostField.stringValue + ":" + portField.stringValue
  69. if connectionSelector.selectedSegment == 0 {
  70. runClient(address: address)
  71. } else {
  72. runServer(address: address)
  73. }
  74. } else {
  75. stop()
  76. }
  77. }
  78. func updateInterfaceBeforeStarting() {
  79. startButton.title = "Stop"
  80. hostField.isEnabled = false
  81. portField.isEnabled = false
  82. connectionSelector.isEnabled = false
  83. if let textStorage = self.textView.textStorage {
  84. textStorage.setAttributedString(NSAttributedString(string: "", attributes: [:]))
  85. }
  86. }
  87. func updateInterfaceAfterStopping() {
  88. DispatchQueue.main.async {
  89. if self.startButton != nil {
  90. self.startButton.title = "Start"
  91. self.hostField.isEnabled = true
  92. self.portField.isEnabled = true
  93. self.connectionSelector.isEnabled = true
  94. }
  95. }
  96. }
  97. func setIsRunning(_ value: Bool) {
  98. sync(lock: self) {
  99. self.running = value
  100. }
  101. }
  102. func isRunning() -> Bool {
  103. var result: Bool = false
  104. sync(lock: self) {
  105. result = self.running
  106. }
  107. return result
  108. }
  109. func stop() {
  110. if channel != nil {
  111. setIsRunning(false) // stops client
  112. }
  113. if server != nil {
  114. server.stop() // stops server
  115. }
  116. }
  117. func runClient(address: String) {
  118. DispatchQueue.global().async {
  119. self.log("Client Starting")
  120. self.log("GRPC version " + gRPC.version())
  121. self.channel = gRPC.Channel(address: address, secure: false)
  122. self.channel.host = "foo.test.google.fr"
  123. let messageData = "hello, server!".data(using: .utf8)
  124. let steps = 10
  125. self.setIsRunning(true)
  126. for i in 1...steps {
  127. if !self.isRunning() {
  128. break
  129. }
  130. let method = (i < steps) ? "/hello" : "/quit"
  131. let call = self.channel.makeCall(method)
  132. let metadata = Metadata([
  133. ["x": "xylophone"],
  134. ["y": "yu"],
  135. ["z": "zither"]
  136. ])
  137. do {
  138. try call.start(.unary,
  139. metadata: metadata,
  140. message: messageData) { callResult in
  141. if let initialMetadata = callResult.initialMetadata {
  142. for j in 0..<initialMetadata.count() {
  143. self.log("\(i): Received initial metadata -> " + initialMetadata.key(j)
  144. + " : " + initialMetadata.value(j))
  145. }
  146. }
  147. self.log("\(i): Received status: \(callResult.statusCode) \(callResult.statusMessage)")
  148. if callResult.statusCode != 0 {
  149. self.setIsRunning(false)
  150. }
  151. if let messageData = callResult.resultData {
  152. let messageString = String(data: messageData as Data, encoding: .utf8)
  153. self.log("\(i): Received message: " + messageString!)
  154. }
  155. if let trailingMetadata = callResult.trailingMetadata {
  156. for j in 0..<trailingMetadata.count() {
  157. self.log("\(i): Received trailing metadata -> " + trailingMetadata.key(j)
  158. + " : " + trailingMetadata.value(j))
  159. }
  160. }
  161. }
  162. } catch (let callError) {
  163. Swift.print("call error \(callError)")
  164. }
  165. self.log("------------------------------")
  166. sleep(1)
  167. }
  168. self.log("Client Stopped")
  169. self.updateInterfaceAfterStopping()
  170. }
  171. }
  172. func runServer(address: String) {
  173. log("Server Starting")
  174. log("GRPC version " + gRPC.version())
  175. setIsRunning(true)
  176. server = gRPC.Server(address: address)
  177. var requestCount = 0
  178. server.run { requestHandler in
  179. do {
  180. requestCount += 1
  181. self.log("\(requestCount): Received request " + requestHandler.host
  182. + " " + requestHandler.method
  183. + " from " + requestHandler.caller)
  184. let initialMetadata = requestHandler.requestMetadata
  185. for i in 0..<initialMetadata.count() {
  186. self.log("\(requestCount): Received initial metadata -> " + initialMetadata.key(i)
  187. + ":" + initialMetadata.value(i))
  188. }
  189. let initialMetadataToSend = Metadata([
  190. ["a": "Apple"],
  191. ["b": "Banana"],
  192. ["c": "Cherry"]
  193. ])
  194. try requestHandler.receiveMessage(initialMetadata: initialMetadataToSend) { messageData in
  195. let messageString = String(data: messageData!, encoding: .utf8)
  196. self.log("\(requestCount): Received message: " + messageString!)
  197. }
  198. if requestHandler.method == "/quit" {
  199. self.stop()
  200. }
  201. let replyMessage = "hello, client!"
  202. let trailingMetadataToSend = Metadata([
  203. ["0": "zero"],
  204. ["1": "one"],
  205. ["2": "two"]
  206. ])
  207. try requestHandler.sendResponse(message: replyMessage.data(using: .utf8)!,
  208. statusCode: 0,
  209. statusMessage: "OK",
  210. trailingMetadata: trailingMetadataToSend)
  211. self.log("------------------------------")
  212. } catch (let callError) {
  213. Swift.print("call error \(callError)")
  214. }
  215. }
  216. server.onCompletion {
  217. self.log("Server Stopped")
  218. self.updateInterfaceAfterStopping()
  219. }
  220. }
  221. }