| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- /*
- * Copyright 2016, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import Cocoa
- import SwiftGRPC
- // https://gist.github.com/rickw/cc198001f5f3aa59ae9f
- extension NSTextView {
- func appendText(line: String) {
- if let textStorage = self.textStorage {
- textStorage.append(NSAttributedString(string: line + "\n",
- attributes: [NSFontAttributeName: NSFont.systemFont(ofSize: 12.0)]))
- }
- if let contents = self.string {
- scrollRangeToVisible(NSRange(location: contents.lengthOfBytes(using: String.Encoding.utf8), length: 0))
- }
- }
- }
- // http://stackoverflow.com/a/28976644/35844
- func sync(lock: AnyObject, closure: () -> Void) {
- objc_sync_enter(lock)
- closure()
- objc_sync_exit(lock)
- }
- class Document: NSDocument {
- @IBOutlet var hostField: NSTextField!
- @IBOutlet var portField: NSTextField!
- @IBOutlet var connectionSelector: NSSegmentedControl!
- @IBOutlet var startButton: NSButton!
- @IBOutlet var textView: NSTextView!
- // http://stackoverflow.com/questions/24062437/cannot-form-weak-reference-to-instance-of-class-nstextview
- var channel: Channel!
- var server: Server!
- var running: Bool // all accesses to this should be synchronized
- override init() {
- running = false
- super.init()
- }
- override func close() {
- textView = nil // prevents logging to the textView
- stop()
- super.close()
- }
- override var windowNibName: String? {
- return "Document"
- }
- func log(_ line: String) {
- DispatchQueue.main.async {
- if let view = self.textView {
- view.appendText(line: line)
- }
- }
- }
- @IBAction func startButtonPressed(sender: NSButton) {
- if sender.title == "Start" {
- updateInterfaceBeforeStarting()
- let address = hostField.stringValue + ":" + portField.stringValue
- if connectionSelector.selectedSegment == 0 {
- runClient(address: address)
- } else {
- runServer(address: address)
- }
- } else {
- stop()
- }
- }
- func updateInterfaceBeforeStarting() {
- startButton.title = "Stop"
- hostField.isEnabled = false
- portField.isEnabled = false
- connectionSelector.isEnabled = false
- if let textStorage = self.textView.textStorage {
- textStorage.setAttributedString(NSAttributedString(string: "", attributes: [:]))
- }
- }
- func updateInterfaceAfterStopping() {
- DispatchQueue.main.async {
- if self.startButton != nil {
- self.startButton.title = "Start"
- self.hostField.isEnabled = true
- self.portField.isEnabled = true
- self.connectionSelector.isEnabled = true
- }
- }
- }
- func setIsRunning(_ value: Bool) {
- sync(lock: self) {
- self.running = value
- }
- }
- func isRunning() -> Bool {
- var result: Bool = false
- sync(lock: self) {
- result = self.running
- }
- return result
- }
- func stop() {
- if channel != nil {
- setIsRunning(false) // stops client
- }
- if server != nil {
- server.stop() // stops server
- }
- }
- func runClient(address: String) {
- DispatchQueue.global().async {
- self.log("Client Starting")
- self.log("GRPC version " + gRPC.version())
- self.channel = gRPC.Channel(address: address, secure: false)
- self.channel.host = "foo.test.google.fr"
- let messageData = "hello, server!".data(using: .utf8)
- let steps = 10
- self.setIsRunning(true)
- for i in 1...steps {
- if !self.isRunning() {
- break
- }
- let method = (i < steps) ? "/hello" : "/quit"
- let call = self.channel.makeCall(method)
- let metadata = Metadata([
- ["x": "xylophone"],
- ["y": "yu"],
- ["z": "zither"]
- ])
- do {
- try call.start(.unary,
- metadata: metadata,
- message: messageData) { callResult in
- if let initialMetadata = callResult.initialMetadata {
- for j in 0..<initialMetadata.count() {
- self.log("\(i): Received initial metadata -> " + initialMetadata.key(j)
- + " : " + initialMetadata.value(j))
- }
- }
- self.log("\(i): Received status: \(callResult.statusCode) \(callResult.statusMessage)")
- if callResult.statusCode != 0 {
- self.setIsRunning(false)
- }
- if let messageData = callResult.resultData {
- let messageString = String(data: messageData as Data, encoding: .utf8)
- self.log("\(i): Received message: " + messageString!)
- }
- if let trailingMetadata = callResult.trailingMetadata {
- for j in 0..<trailingMetadata.count() {
- self.log("\(i): Received trailing metadata -> " + trailingMetadata.key(j)
- + " : " + trailingMetadata.value(j))
- }
- }
- }
- } catch (let callError) {
- Swift.print("call error \(callError)")
- }
- self.log("------------------------------")
- sleep(1)
- }
- self.log("Client Stopped")
- self.updateInterfaceAfterStopping()
- }
- }
- func runServer(address: String) {
- log("Server Starting")
- log("GRPC version " + gRPC.version())
- setIsRunning(true)
- server = gRPC.Server(address: address)
- var requestCount = 0
- server.run { requestHandler in
- do {
- requestCount += 1
- self.log("\(requestCount): Received request " + requestHandler.host
- + " " + requestHandler.method
- + " from " + requestHandler.caller)
- let initialMetadata = requestHandler.requestMetadata
- for i in 0..<initialMetadata.count() {
- self.log("\(requestCount): Received initial metadata -> " + initialMetadata.key(i)
- + ":" + initialMetadata.value(i))
- }
- let initialMetadataToSend = Metadata([
- ["a": "Apple"],
- ["b": "Banana"],
- ["c": "Cherry"]
- ])
- try requestHandler.receiveMessage(initialMetadata: initialMetadataToSend) { messageData in
- let messageString = String(data: messageData!, encoding: .utf8)
- self.log("\(requestCount): Received message: " + messageString!)
- }
- if requestHandler.method == "/quit" {
- self.stop()
- }
- let replyMessage = "hello, client!"
- let trailingMetadataToSend = Metadata([
- ["0": "zero"],
- ["1": "one"],
- ["2": "two"]
- ])
- try requestHandler.sendResponse(message: replyMessage.data(using: .utf8)!,
- statusCode: 0,
- statusMessage: "OK",
- trailingMetadata: trailingMetadataToSend)
- self.log("------------------------------")
- } catch (let callError) {
- Swift.print("call error \(callError)")
- }
- }
- server.onCompletion {
- self.log("Server Stopped")
- self.updateInterfaceAfterStopping()
- }
- }
- }
|