Document.swift 7.6 KB

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