Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Server Side? Swift

Server Side? Swift

HackerTackle 2016/09/10の発表資料です。

Takaaki Tanaka

September 10, 2016
Tweet

More Decks by Takaaki Tanaka

Other Decks in Programming

Transcript

  1. • ాத ޹໌ (Takaaki Tanaka) • Ϋϥεϝιουגࣜձࣾ • iOS ΞϓϦέʔγϣϯΤϯδχΞ

    • @kongmingtrap • iOS Developer (Swift / Objective-C) • GyazSquare / GitHub
  2. Swift Swift is a powerful and intuitive programming language for

    macOS, iOS, watchOS and tvOS. Writing Swift code is interactive and fun, the syntax is concise yet expressive, and Swift includes modern features developers love. Swift code is safe by design, yet also produces software that runs lightning-fast.
  3. History of Swift • 0.x (2014/06) • 1.0 (2014/09) •

    1.1 (2014/10) • 1.2 (2015/02) • 2.0 (2015/06) • 2.1 (2015/10) • 2.2 (2016/03) • 3.0 (2016/09)
  4. History of Swift • 0.x (2014/06) • 1.0 (2014/09) •

    1.1 (2014/10) • 1.2 (2015/02) • 2.0 (2015/06) • 2.1 (2015/10) • 2.2 (2016/03) • 3.0 (2016/09) ᴈ໌ظ
  5. History of Swift • 0.x (2014/06) • 1.0 (2014/09) •

    1.1 (2014/10) • 1.2 (2015/02) • 2.0 (2015/06) • 2.1 (2015/10) • 2.2 (2016/03) • 3.0 (2016/09) ੒௕ظ
  6. History of Swift • 0.x (2014/06) • 1.0 (2014/09) •

    1.1 (2014/10) • 1.2 (2015/02) • 2.0 (2015/06) • 2.1 (2015/10) • 2.2 (2016/03) • 3.0 (2016/09) શ੝ظ
  7. [swift-evolution] Looking back on Swift 3 and ahead to Swift

    4 https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025676.html "#*҆ఆԽͳͲɺ4XJGUͰ࣮૷༧ఆͩͬ ͨػೳ͕ݟૹΒΕɺ4XJGU·Ͱ࣋ͪӽ ͞ΕΔɻɻɻ
  8. $ swift —version Apple Swift version 3.0 (swiftlang-800.0.43.6 clang-800.0.38) Target:

    x86_64-apple-macosx10.9 $ xcode-select --switch /Applications/Xcode.app/Contents/Developer Build
  9. $ brew install openssl $ brew link openssl --force Build

    $ git clone https://github.com/PerfectlySoft/PerfectTemplate.git $ cd PerfectTemplate $ swift build $ .build/debug/PerfectTemplate
  10. // Create HTTP server. let server = HTTPServer() // Register

    your own routes and handlers var routes = Routes() // Add the routes to the server. server.addRoutes(routes) // Set a listen port of 8181 server.serverPort = 8181 // Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot" // Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server) do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") } Server Start
  11. // Create HTTP server. let server = HTTPServer() // Register

    your own routes and handlers var routes = Routes() // Add the routes to the server. server.addRoutes(routes) // Set a listen port of 8181 server.serverPort = 8181 // Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot" // Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server) do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") } Server Start
  12. // Create HTTP server. let server = HTTPServer() // Register

    your own routes and handlers var routes = Routes() // Add the routes to the server. server.addRoutes(routes) // Set a listen port of 8181 server.serverPort = 8181 // Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot" // Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server) do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") } Server Start
  13. // Create HTTP server. let server = HTTPServer() // Register

    your own routes and handlers var routes = Routes() // Add the routes to the server. server.addRoutes(routes) // Set a listen port of 8181 server.serverPort = 8181 // Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot" // Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server) do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") } Server Start
  14. // Create HTTP server. let server = HTTPServer() // Register

    your own routes and handlers var routes = Routes() // Add the routes to the server. server.addRoutes(routes) // Set a listen port of 8181 server.serverPort = 8181 // Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot" // Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server) do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") } Server Start
  15. Router // list routes.add(method: .get, uri: "/list", handler: listHandler) //

    login routes.add(method: .post, uri: "/login", handler: loginHandler) // get message routes.add(method: .get, uri: "/message", handler: getMessageHandler) // post message routes.add(method: .post, uri: "/message", handler: postMessageHandler) IUUQTHJUIVCDPN1FSGFDUMZ4PGU1FSGFDU&YBNQMF 63-3PVUJOH
  16. GET Method // listHandler func listHandler(request: HTTPRequest, _ response: HTTPResponse)

    { defer { response.completed() } response.setHeader(.contentType, value: "application/json") do { let listArray: [String : Any] = [ "name1": 300, "name2": 230.45, "name3": 150 ] try response.setBody(json: listArray) } catch let error as NSError { print(error) } }
  17. GET Method curl -v -H "Accept: application/json" -H "Content-type: application/json"

    - X GET http://0.0.0.0:8181/list * Trying 0.0.0.0... * Connected to 0.0.0.0 (127.0.0.1) port 8181 (#0) > GET /list HTTP/1.1 > Host: 0.0.0.0:8181 > User-Agent: curl/7.43.0 > Accept: application/json > Content-type: application/json > < HTTP/1.1 200 OK < Content-Type: application/json < Connection: Keep-Alive < Content-Length: 40 < * Connection #0 to host 0.0.0.0 left intact {"name1":300,"name2":230.45,"name3":150}
  18. GET Method // check thread let thread = Thread.current print(thread)

    [INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot <NSThread: 0x7fab61c15530>{number = 2, name = (null)} <NSThread: 0x7fab61e06cd0>{number = 3, name = (null)} <NSThread: 0x7fab61f05290>{number = 4, name = (null)} શͯͷϦΫΤετ͕ผͷ5ISFBEͰ࣮ߦ͞ Ε͍ͯΔ͜ͱ͕Θ͔Δ
  19. POST Method // loginHandler func loginHandler(request: HTTPRequest, _ response: HTTPResponse)

    { defer { response.completed() } do { let json = try request.postBodyString?.jsonDecode() response.setHeader(.contentType, value: "application/json") guard let decoded = json as? [String : Any] else { return } let result: [String : Any] = decoded["user"].map { ["result": true, "user": $0] } ?? ["result": false] try response.setBody(json: result) } catch let error as NSError { print(error) } }
  20. POST Method curl -v -H "Accept: application/json" -H "Content-type: application/json"

    - X POST -d '{"user": "tana"}' http://0.0.0.0:8181/login * Trying 0.0.0.0... * Connected to 0.0.0.0 (127.0.0.1) port 8181 (#0) > POST /login HTTP/1.1 > Host: 0.0.0.0:8181 > User-Agent: curl/7.43.0 > Accept: application/json > Content-type: application/json > Content-Length: 16 > * upload completely sent off: 16 out of 16 bytes < HTTP/1.1 200 OK < Content-Type: application/json < Connection: Keep-Alive < Content-Length: 29 < * Connection #0 to host 0.0.0.0 left intact {"result":true,"user":"tana"}
  21. w 1FSGFDU3FEJT w 1FSGFDU42-JUF w 1FSGFDU1PTUHSF42- w 1FSGFDU.Z42- w 1FSGFDU.POHP%#

    w 1FSGFDU'JMF.BLFS DB Connector IUUQTHJUIVCDPN1FSGFDUMZ4PGU1FSGFDU1PTUHSF42-
  22. let package = Package( name: "PerfectTemplate", targets: [], dependencies: [

    .Package( url: "https://github.com/PerfectlySoft/ Perfect-PostgreSQL.git", versions: Version(0,0,0)..<Version(10,0,0)) ] ) Postgresql ϓϩδΣΫτ௚ԼͷQBDLBHFTXJGUʹ 1FSGFDU1PTUHSFT42-Λ௥Ճ͢Δ
  23. create table message ( id serial primary key, message text,

    created_at timestamp with time zone, updated_at timestamp with time zone ); w DSFBUFNFTTBHFUBCMF Create Table
  24. GET Method // get message routes.add(method: .get, uri: "/message", handler:

    { request, response in defer { response.completed() } do { response.setHeader(.contentType, value: "application/json") let connection = PGConnection() let status = connection.connectdb(db) let result = connection.exec( statement: "select * FROM message order by updated_at desc") … // DB let db = "postgresql://samplefuku:fukuoka@localhost:5432/exampledb"
  25. GET Method … let num = result.numTuples() let messages: [[String

    : Any]] = (0..<num).map { x in let t1 = result.getFieldString(tupleIndex: x, fieldIndex: 0) let t2 = result.getFieldString(tupleIndex: x, fieldIndex: 1) let t3 = result.getFieldString(tupleIndex: x, fieldIndex: 2) let t4 = result.getFieldString(tupleIndex: x, fieldIndex: 3) let message: [String : Any] = [ "id" : t1, "message" : t2, "created_at" : t3, "updated_at" : t4 ] return message } result.clear() connection.close() try response.setBody(json: ["messages" : messages]) } catch let error as NSError { print(error) } })
  26. POST Method // post message routes.add(method: .post, uri: "/message", handler:

    { request, response in defer { response.completed() } do { let json = try request.postBodyString?.jsonDecode() response.setHeader(.contentType, value: “application/json") guard let decoded = json as? [String : Any] else { return } …
  27. POST Method … let result: [String : Any] = decoded["message"].map

    { message in let connection = PGConnection() let status = connection.connectdb(db) let date = Date() let createdAt = RFC3339DateFormatter.string(from: date) let updatedAt = RFC3339DateFormatter.string(from: date) let result = connection.exec( statement: "insert into message (message, created_at, updated_at) values($1, $2, $3)", params: ["\(message)", "\(createdAt)", "\(updatedAt)"]) result.clear() connection.close() return ["message" : message] } ?? [:] try response.setBody(json: result) …
  28. AMI $ wget https://swift.org/builds/development/ubuntu1510/swift-DEVELOPMENT- SNAPSHOT-2016-08-26-a/swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a-ubuntu15.10.tar.gz $ tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a-ubuntu15.10.tar.gz IUUQTTXJGUPSHEPXOMPBEVTJOHEPXOMPBET

    ".*ʹΠϯετʔϧ͞Ε͍ͯΔͷ͕4XJGUͷͨΊɺ Ϗϧυ͢ΔͨΊʹαϙʔτ͞Ε͍ͯΔ4XJGUͷ 4/"14)05Λऔಘ͢Δ $ export PATH=./swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a-ubuntu15.10/usr/bin:"$ {PATH}"
  29. Call Shell // Commandline func command(launchPath: String, arguments: [String]) ->

    String { let task = Process() task.launchPath = launchPath task.arguments = arguments let pipe = Pipe() task.standardOutput = pipe task.launch() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String( data: data, encoding: String.Encoding.utf8)! return output } let cl = command(launchPath: "/bin/echo", arguments: ["aaaa"])