LinuxサーバーでSwift 4、Perfect、Protobuf、MySQLを使用するとうまくいきます

長い間、3つのことを見ることができます。水の流れ、 CoreFoundationの Linux Swiftでの実装方法、およびPerfectドキュメントが更新されない方法です。


まず、知らない人のために簡単に説明します。Perfectは、Swiftで最も安定したサーバーフレームワークの1つです。 ( ベンチマーク


チャレンジ:


クライアントアプリケーションと通信するためのMySQLおよびプロトコルバッファーを備えたLinux上の完璧なサーバー


重要な要件:


私たちはプログレッシブスイフトヒップスター(皮肉)なので、 Swift 4.0.2の最新バージョンを提供


ステップ0.ツールキットのインストール


  1. Swift 4.0.2を直接インストールします( 詳細はこちらをご覧ください
  2. MySQLがすでにインストールされていることを前提としています 。 そうでない場合は、多くのチュートリアルがあります(たとえば、Ubuntu用)
  3. また、 Protocol Buffersコンパイラパッケージが必要です(ソースからコンパイルすることもできます)

ステップ1.完璧なセットアップ


Perfectには、使用するPerfectTemplateの素晴らしい例があります。 ただし、承認プロセスで更新された構文とロシア語のドキュメントが含まれる公式のプルリクエストリポジトリでは、フォークを使用します。


git clone https://github.com/nickaroot/PerfectTemplate.git 

待つことなくすぐに実行しようとします


 cd PerfectTemplate swift run 

すべてが順調に進んだ場合、コレクターが表示されます。


 [INFO] Starting HTTP server localhost on 0.0.0.0:8181 

やった! サーバーは「Hello、World!」を提供するはずです。 http://127.0.0.1:8181


MySQLでのステップ2.0テーブルテスト


画像


ステップ2.1 MySQLモジュールの準備


Package.swiftを開き、 PerfectMySQL依存関係を追加して、取得します


 // Dependencies declare other packages that this package depends on. .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.3"), .package(url: "https://github.com/PerfectlySoft/Perfect-MySQL", from: "3.0.0"), 

同様に


 dependencies: ["PerfectHTTPServer", "PerfectMySQL"], 

次に、 main.swiftのすべてのインポートの後に追加します


 import PerfectMySQL 

データベースに接続するための変数を宣言します。値を置き換えることを忘れないでください


 let testHost = "example.com" //   /  IP let testUser = "foo" //   let testPassword = "bar" //  let testDB = "swift_example_db" //    

ステップ2.2 リクエストの処理とデータベースからのデータの受信


このプロセスはドキュメントで説明されていますが、 PerfectMySQLモジュールはすでにドキュメントをはるかに超えており、コミットを調査した後にのみコードを収集することができました(必要はありません)


要求ハンドラーfetchDataHandler()を作成します。これには、ハンドラー()関数の後に、


 func fetchDataHandler(data: [String:Any]) throws -> RequestHandler { return { request, response in print("Request Handled!") response.completed() } } 

構成で、ハンドラーイベントを追加します


 ["method":"get", "uri":"/fetchDataHandler", "handler":fetchDataHandler], 

前に


 ["method":"get", "uri":"/", "handler":handler], 

データベースに接続しています。 これを行うには、 印刷後にコードを挿入します(「Request Handled!」)


 let mysql = MySQL() // c  MySQL     let connected = mysql.connect(host: testHost, user: testUser, password: testPassword) guard connected else { // ,    print(mysql.errorMessage()) return } defer { mysql.close() //    ,            } //    guard mysql.selectDatabase(named: testDB) else { Log.info(message: "Failure: \(mysql.errorCode()) \(mysql.errorMessage())") return } 

次に、データベースへの準備されたクエリを作成して実行します


 let stmt = MySQLStmt(mysql) //   _ = stmt.prepare(statement: "SELECT * FROM test") //     test let querySuccess = stmt.execute() //   // ,    guard querySuccess else { print(mysql.errorMessage()) return } 

ポイントは小さい-結果を処理するためだけに残っている


 let results = stmt.results() let fieldNames = stmt.fieldNames() //     ,      var arrayResults: [[String:Any]] = [] //     _ = results.forEachRow { row in var rowDictionary = [String: Any]() var i = 0 //       while i != results.numFields { rowDictionary[fieldNames[i]!] = row[i] //        ["_":""] i += 1 } arrayResults.append(rowDictionary) } 

結果のデータ配列を印刷するだけです


 print(arrayResults) response.setHeader(.contentType, value: "text/html") response.appendBody(string: "<html><title>Testing...</title><body>\(arrayResults)</body></html>") 

ハンドラーを確認する


 swift run 

エラーなしですべてがコンパイルされて開始された場合、 http://127.0.0.1:8181 / fetchDataにMySQLから受信した配列が表示されます。


ステップ3.1 プロトコルバッファの準備


サンプルコンテンツを含むPerson.protoファイルを作成する


 syntax = "proto3"; message Person { string name = 1; int32 id = 2; string email = 3; } 

迅速なファイルをコンパイルする


 protoc --swift_out=. Person.proto 

Package.swiftを開き、 SwiftProtobuf依存関係を追加して、取得します


 // Dependencies declare other packages that this package depends on. .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.3"), .package(url: "https://github.com/PerfectlySoft/Perfect-MySQL", from: "3.0.0"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.0.1"), 

同様に


 dependencies: ["PerfectHTTPServer", "PerfectMySQL", "SwiftProtobuf"], 

モジュールをmain.swiftにインポートします


 import SwiftProtobuf 

ステップ3.2 Protobufを送受信するためのハンドラーを作成する


すぐに2つのパスを追加します


 ["method":"post", "uri":"/send", "handler":sendHandler], ["method":"post", "uri":"/receive", "handler":receiveHandler], 

protobufを送信するSendHandler(data :)メソッド


 func sendHandler(data: [String:Any]) throws -> RequestHandler { return { request, response in if !request.postParams.isEmpty { var name: String? = nil var id: Int32? = nil var email: String? = nil for param in request.postParams { //  POST-   if param.0 == "name" { name = param.1 } else if param.0 == "id" { id = Int32(param.1) } else if param.0 == "email" { email = param.1 } } if let personName = name, let personId = id, let personEmail = email { var person = Person() person.name = personName person.id = personId person.email = personEmail do { let data = try person.serializedData() //    Data print("Serialized Proto into Data") print("Sending Proto…") ProtoSender().send(data) //    } catch { print("Failed to Serialize Protobuf Object into Data") } } } response.setHeader(.contentType, value: "text/plain") response.appendBody(string: "1") response.completed() } } 

問題が発生します: ProtoSenderとは何ですか?
重要なことを覚えておいてください:冒頭で述べたように、Foundationは実装段階にあり、 URLSessionを介してすべてのデータを喜んで送信することは可能ですが、Linuxプラットフォームではshared()メソッドは利用できません今のところ


解決策があります


cURLソリューションが呼び出され、そのラッパーはPerfectCURLに既に実装されています。これを使用します


Package.swiftを既によく知っており、 PerfectCURL依存関係を追加します


 // Dependencies declare other packages that this package depends on. .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.3"), .package(url: "https://github.com/PerfectlySoft/Perfect-MySQL", from: "3.0.0"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.0.1"), .package(url: "https://github.com/PerfectlySoft/Perfect-CURL.git", from: "3.0.1"), 

同様に


 dependencies: ["PerfectHTTPServer", "PerfectMySQL", "SwiftProtobuf", "PerfectCURL"], 

モジュールをmain.swiftにインポートします


 import PerfectCURL 

ProtoSender構造を追加する


 struct ProtoSender { func send(_ data: Data) { let url = "http://localhost:8181/receive" //     do { _ = try CURLRequest(url, .failOnError, .postData(Array(data))).perform() // Array(data) ..  [UInt8] } catch { print("Sending failed") } } } 

記事のほぼ最後にいます。receiveHandlerを追加するだけです。


 func receiveHandler(data: [String:Any]) throws -> RequestHandler { return { request, response in print("Proto Received!") if let bytes = request.postBodyBytes { let data = Data(bytes: bytes) // Protobuf    ,   Data do { let person = try Person(serializedData: data) //  Protobuf print("Proto was received and converted into a person with: \nname: \(person.name) \nid: \(person.id) \nemail: \(person.email)") let mysql = MySQL() //        let connected = mysql.connect(host: testHost, user: testUser, password: testPassword) guard connected else { print(mysql.errorMessage()) return } defer { mysql.close() } guard mysql.selectDatabase(named: testDB) else { Log.info(message: "Failure: \(mysql.errorCode()) \(mysql.errorMessage())") return } let stmt = MySQLStmt(mysql) _ = stmt.prepare(statement: "INSERT INTO test (id, name, email) VALUES (?, ?, ?)") //      stmt.bindParam(Int(person.id)) //   ,   php stmt.bindParam(person.name) stmt.bindParam(person.email) let querySuccess = stmt.execute() guard querySuccess else { print(mysql.errorMessage()) return } } catch { print("Failed to Decode Proto") } } response.setHeader(.contentType, value: "text/plain") response.appendBody(string: "1") response.completed() } } 

性能を確認する


 swift run 

すべてが起動したら、別のターミナルウィンドウを開いてPOSTリクエストを送信します


 curl 127.0.0.1:8181/send --data "name=foobar&id=8&email=foobar@example.com" -X POST 

最初のコンソールウィンドウには、フォームのデータが表示されます。


 Serialized Proto into Data Sending Proto… Proto Received! Proto was received and converted into a person with: name: foobar id: 8 email: foobar@example.com 

追加の検証のために、127.0.0.1 / fetchDataを開くことができますが、データを送信するときは、すべてのIDが一意でなければならないことを忘れないでください(テストの一部としてIDを渡します)


これで、サーバーでSwiftを実行できます


完成したプロジェクトを含むリポジトリ


願いと批判を書きましょう。 素材はテクニックを紹介するために作成されたため、記事の過程ですべてが1つのファイルに収められました(完成したプロジェクトを参照)。



Source: https://habr.com/ru/post/J341980/


All Articles