You can look at three things for a long time: how water flows, how CoreFoundation is implemented in Linux Swift, and how Perfect documentation is not updated.
First, briefly for those who do not know: Perfect is one of the most stable Swift server frameworks. ( benchmark )
Perfect Server on Linux with MySQL and Protocol Buffers to communicate with the client application
We are progressive hipsters with swifts (sarcasm), so give the latest version of Swift 4.0.2
Perfect has a great example of PerfectTemplate , which we will use. However, in the official Pull Request repository with the updated syntax and Russian documentation in the approval process, so we will use my fork.
git clone https://github.com/nickaroot/PerfectTemplate.git
We will not wait and immediately try to run it.
cd PerfectTemplate swift run
If everything went smoothly, then we will see a collector, and then
[INFO] Starting HTTP server localhost on 0.0.0.0:8181
Open the Package.swift and add the PerfectMySQL dependency so that it turns out
// 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"),
And
dependencies: ["PerfectHTTPServer", "PerfectMySQL"],
Next, after all the import'ov add to main.swift
import PerfectMySQL
We declare variables for the connection with the base, not forgetting to substitute our values
let testHost = "example.com" // / IP let testUser = "foo" // let testPassword = "bar" // let testDB = "swift_example_db" //
Although this process is described in the documentation, the PerfectMySQL module has already gone far beyond the documentation, and it turned out to collect the code only after studying commits (it’s not necessary)
Create a request handler fetchDataHandler (), to do this, after the handler () function, insert
func fetchDataHandler(data: [String:Any]) throws -> RequestHandler { return { request, response in print("Request Handled!") response.completed() } }
In the configuration, add the event handler
["method":"get", "uri":"/fetchDataHandler", "handler":fetchDataHandler],
before
["method":"get", "uri":"/", "handler":handler],
Connect to the database. To do this, insert the code after print ("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 }
Next, create a prepared request to the database and execute it.
let stmt = MySQLStmt(mysql) // _ = stmt.prepare(statement: "SELECT * FROM test") // test let querySuccess = stmt.execute() // // , guard querySuccess else { print(mysql.errorMessage()) return }
Things are going well - it remains only to process the results
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) }
Now simply output the resulting data array.
print(arrayResults) response.setHeader(.contentType, value: "text/html") response.appendBody(string: "<html><title>Testing...</title><body>\(arrayResults)</body></html>")
Check handler
swift run
Create a file Person.proto with the help of an example
syntax = "proto3"; message Person { string name = 1; int32 id = 2; string email = 3; }
Compile the swift file
protoc --swift_out=. Person.proto
Open Package.swift and add the SwiftProtobuf dependency so that we can
// 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"),
And
dependencies: ["PerfectHTTPServer", "PerfectMySQL", "SwiftProtobuf"],
Import the module into main.swift
import SwiftProtobuf
Immediately add two ways
["method":"post", "uri":"/send", "handler":sendHandler], ["method":"post", "uri":"/receive", "handler":receiveHandler],
SendHandler (data :) method to send protobuf
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() } }
The question arises: What is ProtoSender and where to get it
Remember something important: As stated at the beginning, the Foundation is in the implementation stage, and you could gladly send all the data through the URLSession , but its shared () method is not available ( yet ) on the Linux platform
The solution is called cURL, and its wrapper is already implemented in PerfectCURL , which we will use
Already familiarly open Package.swift and add the PerfectCURL dependency
// 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"),
And
dependencies: ["PerfectHTTPServer", "PerfectMySQL", "SwiftProtobuf", "PerfectCURL"],
Import the module into main.swift
import PerfectCURL
Add a ProtoSender structure
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") } } }
You are almost at the very end of the article, it remains only to add
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
If everything started, we will open another terminal window and send a POST request.
curl 127.0.0.1:8181/send --data "name=foobar&id=8&email=foobar@example.com" -X POST
The first console window should display the data in the form
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
For additional verification, you can open 127.0.0.1/fetchData, but when sending data, do not forget that all id must be unique (id we pass as part of testing)
Repository with a ready project
Write wishes and criticism. The material was created in order to introduce the technique, so during the article everything was in one file (see the finished project).
Source: https://habr.com/ru/post/341980/
All Articles