Swift3 Framework Slimane and Server Side Swift (ja)

9ebab3d4f66a62a859ad238e7e97597f?s=47 Yuki Takei
August 19, 2016

Swift3 Framework Slimane and Server Side Swift (ja)

iOSDC 2016 Aug, 19

9ebab3d4f66a62a859ad238e7e97597f?s=128

Yuki Takei

August 19, 2016
Tweet

Transcript

  1. 3.
  2. 32.
  3. 34.

    • C7ɿCore standards for Swift • S4: HTTP standards for

    Swift • D5: Database standards for Swift ҎԼͷ3ͭͷϨϙδτϦ͕ଘࡏ͢Δ
  4. 35.

    C7 • Stream • Connection • Data • URI •

    JSON Stream(TCPɺPipe etc..)ɺURIɺDataߏ଄ͳͲͷɺ ΞϓϦέʔγϣϯͷجຊ෦෼ͷ࢓༷ɺΠϯλʔϑΣʔε
  5. 36.

    • Request • Response • HTTP Status Code • Server

    • Middleware • Responder S4 WebͷͨΊͷ࢓༷ɺΠϯλʔϑΣʔε(rubyͷrackʹ͍ۙ)
  6. 43.
  7. 44.
  8. 45.

    • ExpressΛinspireͨܰ͠ྔWAF/Web Server • Node.jsͷ5ഒɺRevelͷ2ഒߴ଎ʢͩͬͨʣ • ΠϕϯτϧʔϓϞσϧɺϊϯϒϩοΩϯάI/O • Master/WorkerύλʔϯʹΑΔϚϧνεϨουରԠ •

    Core Foundationʹґଘ͠ͳ͍ • ϚΠΫϩαʔϏε޲͚ͷAPIαʔόʔ΍SwiftͰඇಉظωοτ ϫʔΫϓϩάϥϛϯάΛߦ͏͜ͱ͕ओ໨త Slimaneͱ͸
  9. 48.

    Layer system call thread pool event loop Swift bindings of

    libuv Async net working platform TCP, UDP, Process, FS, DNS etc.. HTTP Server WAF(Routing, Middleware)
  10. 49.

    Runtime EVENT LOOP FILE SYSTEM NETWORK NETWORK System Operation &

    Register Callback COMPUTATION Operation Complete Trigger Callback Requests Suv(libuv wapper) epoll kqueue worker threads
  11. 53.

    ➜ slimane git:(master) ✗ slimane new TestApp [~/Documents/program/oss/slimane/slimane] /Users/yuki/Documents/program/oss/Slimane/Slimane/TestApp ├──

    Makefile ├── Package.swift ├── Sources │ ├── app.swift │ └── main.swift └── public └── images └── Slimane_logo.jpg 3 directories, 5 files ➜ TestApp git:(master) ✗ slimane build ここでSPMの依存解決、コンパイルが走る。(結構時間かかります。) ➜ TestApp git:(master) ✗ .build/debug/TestApp [~/Documents/program/oss/slimane/slimane/TestApp] The server is listening at 0.0.0.0:3000 [pid:50928] Monday, August 01 2016 00:11:48 /
  12. 54.

    ➜ slimane git:(master) ✗ slimane new TestApp [~/Documents/program/oss/slimane/slimane] /Users/yuki/Documents/program/oss/Slimane/Slimane/TestApp ├──

    Makefile ├── Package.swift ├── Sources │ ├── app.swift │ └── main.swift └── public └── images └── Slimane_logo.jpg 3 directories, 5 files ➜ TestApp git:(master) ✗ slimane build ここでSPMの依存解決、コンパイルが走る。(結構時間かかります。) ➜ TestApp git:(master) ✗ .build/debug/TestApp [~/Documents/program/oss/slimane/slimane/TestApp] The server is listening at 0.0.0.0:3000 [pid:50928] Monday, August 01 2016 00:11:48 / ϓϩδΣΫτͷεχϖοτΛ࡞੒
  13. 55.

    ➜ slimane git:(master) ✗ slimane new TestApp [~/Documents/program/oss/slimane/slimane] /Users/yuki/Documents/program/oss/Slimane/Slimane/TestApp ├──

    Makefile ├── Package.swift ├── Sources │ ├── app.swift │ └── main.swift └── public └── images └── Slimane_logo.jpg 3 directories, 5 files ➜ TestApp git:(master) ✗ slimane build ここでSPMの依存解決、コンパイルが走る。(結構時間かかります。) ➜ TestApp git:(master) ✗ .build/debug/TestApp [~/Documents/program/oss/slimane/slimane/TestApp] The server is listening at 0.0.0.0:3000 [pid:50928] Monday, August 01 2016 00:11:48 /
  14. 56.

    ➜ slimane git:(master) ✗ slimane new TestApp [~/Documents/program/oss/slimane/slimane] /Users/yuki/Documents/program/oss/Slimane/Slimane/TestApp ├──

    Makefile ├── Package.swift ├── Sources │ ├── app.swift │ └── main.swift └── public └── images └── Slimane_logo.jpg 3 directories, 5 files ➜ TestApp git:(master) ✗ slimane build ここでSPMの依存解決、コンパイルが走る。(結構時間かかります。) ➜ TestApp git:(master) ✗ .build/debug/TestApp [~/Documents/program/oss/slimane/slimane/TestApp] The server is listening at 0.0.0.0:3000 [pid:50928] Monday, August 01 2016 00:11:48 / SPMɺModuleMapͷґଘղܾ / ίϯύΠϧ
  15. 57.

    ➜ slimane git:(master) ✗ slimane new TestApp [~/Documents/program/oss/slimane/slimane] /Users/yuki/Documents/program/oss/Slimane/Slimane/TestApp ├──

    Makefile ├── Package.swift ├── Sources │ ├── app.swift │ └── main.swift └── public └── images └── Slimane_logo.jpg 3 directories, 5 files ➜ TestApp git:(master) ✗ slimane build ここでSPMの依存解決、コンパイルが走る。(結構時間かかります。) ➜ TestApp git:(master) ✗ .build/debug/TestApp [~/Documents/program/oss/slimane/slimane/TestApp] The server is listening at 0.0.0.0:3000 [pid:50928] Monday, August 01 2016 00:11:48 /
  16. 58.

    ➜ slimane git:(master) ✗ slimane new TestApp [~/Documents/program/oss/slimane/slimane] /Users/yuki/Documents/program/oss/Slimane/Slimane/TestApp ├──

    Makefile ├── Package.swift ├── Sources │ ├── app.swift │ └── main.swift └── public └── images └── Slimane_logo.jpg 3 directories, 5 files ➜ TestApp git:(master) ✗ slimane build ここでSPMの依存解決、コンパイルが走る。(結構時間かかります。) ➜ TestApp git:(master) ✗ .build/debug/TestApp [~/Documents/program/oss/slimane/slimane/TestApp] The server is listening at 0.0.0.0:3000 [pid:50928] Monday, August 01 2016 00:11:48 / Ϗϧυޙʹग़དྷ্͕ͬͨόΠφϦΛ࣮ߦ
  17. 62.
  18. 63.
  19. 66.

    struct HelloWorldResponser: AsyncResponder { public func respond(to request: Request, result:

    ((Void) throws -> Response) -> Void) result { Response(body: “Hello world") } } } Responder
  20. 71.

    MiddlewareͷίʔυʢϩάΠϯνΣοΫʣ public struct AuthenticationMiddleware: AsyncMiddleware { public func respond(to request:

    Request, chainingTo next: AsyncResponder, result: ((Void) throws -> Response) -> Void) { if request.session?["isAuthorized"] != nil { return next.respond(to: request, result: result) } result { Response(status: .unauthorized) } } }
  21. 72.

    MiddlewareͷίʔυʢϩάΠϯνΣοΫʣ public struct AuthenticationMiddleware: AsyncMiddleware { public func respond(to request:

    Request, chainingTo next: AsyncResponder, result: ((Void) throws -> Response) -> Void) { if request.session?["isAuthorized"] != nil { return next.respond(to: request, result: result) } result { Response(status: .unauthorized) } } } ϩάΠϯ͍ͯͨ͠Β࣍ͷMiddlewareʹνΣΠϯ
  22. 73.

    MiddlewareͷίʔυʢϩάΠϯνΣοΫʣ public struct AuthenticationMiddleware: AsyncMiddleware { public func respond(to request:

    Request, chainingTo next: AsyncResponder, result: ((Void) throws -> Response) -> Void) { if request.session?["isAuthorized"] != nil { return next.respond(to: request, result: result) } result { Response(status: .unauthorized) } } } ϩάΠϯ͍ͯ͠ͳ͚Ε͹ɺ401Λฦ͢
  23. 77.

    ૊Έ߹ΘͤΔͱ…. import Slimane let app = Slimane() app.use { req,

    next, result in print("middleware") next.respond(to: req, result: result) } app.get("/") { req, responder in responder { Response(body: "Hello iOSDC") } } try! app.listen() // => listening at 0.0.0.0:3000
  24. 78.

    Express Slimane const express = require('express'); const app = express();

    app.use((req, res, next) => { console.log("middleware"); next(); }); app.get("/", (req, res) => { res.send("Hello iOSDC"); }); app.listen(); // => listening at 0.0.0.0:3000 import Slimane let app = Slimane() app.use { req, next, result in print("middleware") next.respond(to: req, result: result) } app.get("/") { req, responder in responder { Response(body: "Hello iOSDC") } } try! app.listen() // => listening at 0.0.0.0:3000 ίʔυΛExpressͱൺֱ
  25. 79.

    Express Slimane const express = require('express'); const app = express();

    app.use((req, res, next) => { console.log("middleware"); next(); }); app.get("/", (req, res) => { res.send("Hello iOSDC"); }); app.listen(); // => listening at 0.0.0.0:3000 import Slimane let app = Slimane() app.use { req, next, result in print("middleware") next.respond(to: req, result: result) } app.get("/") { req, responder in responder { Response(body: "Hello iOSDC") } } try! app.listen() // => listening at 0.0.0.0:3000 ίʔυΛExpressͱൺֱ ׂͱࣅͯ·͢Ͷɻ
  26. 82.
  27. 83.
  28. 85.

    import Slimane import Render import MustacheViewEngine let app = Slimane()

    app.get("/") { req, result in result { let templateData: TemplateData = ["name": "Slimane"] let render = Render(engine: MustacheViewEngine(templateData: templateData), path: “index”) return Response(custom: render) } } try! app.listen() RenderΛ࢖ͬͯHTMLΛ഑৴͢Δྫ
  29. 86.

    import Slimane import Render import MustacheViewEngine let app = Slimane()

    app.get("/") { req, result in result { let templateData: TemplateData = ["name": "Slimane"] let render = Render(engine: MustacheViewEngine(templateData: templateData), path: “index”) return Response(costom: render) } } try! app.listen() RenderΛ࢖ͬͯHTMLΛ഑৴͢Δྫ MustacheViewEngineΛengineͱͯ͠ɺ RenderΦϒδΣΫτΛ࡞੒
  30. 87.

    import Slimane import Render import MustacheViewEngine let app = Slimane()

    app.get("/") { req, result in result { let templateData: TemplateData = ["name": "Slimane"] let render = Render(engine: MustacheViewEngine(templateData: templateData), path: “index”) return Response(custom: render) } } try! app.listen() RenderΛ࢖ͬͯHTMLΛ഑৴͢Δྫ Response.initializerͷcostom labelʹ render ObjectΛ౉͢
  31. 89.
  32. 90.
  33. 92.

    import Slimane import BodyParser import JSON let app = Slimane()

    app.use(BodyParser.JSON()) app.post("/") { req, responder in print(req.json?[“string”].asString) print(req.json?[“number”].asNumber) print(req.json?[“object”].asObject) responder { let successJSON: JSON = ["message": "OK"] Response( status: .created, headers: Header([“Content-Type”: “application/json“]), body: try JSONMapSerializer.serialize(successJSON) ) } } application/jsonͷRequest/Responseͷྫ
  34. 93.

    import Slimane import BodyParser import JSON let app = Slimane()

    app.use(BodyParser.JSON()) app.post("/") { req, responder in print(req.json?[“string”].asString) print(req.json?[“number”].asNumber) print(req.json?[“object”].asObject) responder { let successJSON: Map = ["message": "OK"] Response( status: .created, headers: Header([“Content-Type”: “application/json“]), body: try JSONMapSerializer.serialize(successJSON) ) } } main.swift JSON BodyParserΛMiddlewareʹొ࿥
  35. 94.

    import Slimane import BodyParser import JSON let app = Slimane()

    app.use(BodyParser.JSON()) app.post("/") { req, responder in print(req.json?[“string”].asString) print(req.json?[“number”].asNumber) print(req.json?[“object”].asObject) responder { let successJSON: Map = ["message": "OK"] Response( status: .created, headers: Header([“Content-Type”: “application/json“]), body: try JSONMapSerializer.serialize(successJSON) ) } } main.swift JSON Value΁ͷΞΫηε
  36. 95.

    import Slimane import BodyParser import JSON let app = Slimane()

    app.use(BodyParser.JSON()) app.post("/") { req, responder in print(req.json?[“string”].asString) print(req.json?[“number”].asNumber) print(req.json?[“object”].asObject) responder { let successJSON: JSON = ["message": "OK"] Response( status: .created, headers: Header([“Content-Type”: “application/json“]), body: try JSONSerializer.serialize(successJSON) ) } } main.swift JSONܕ(Type safeͳߏ଄ܕ)ͰDictionaryΛੜ੒͠ɺ JSONSerializer.serializeʹ౉͢͜ͱͰJSONStringʹ
  37. 101.

    ίʔυ import Suv let onThread = { ctx in let

    sql = "select * from foo where bar = 1" let ctx.storage[“result”] = mysql_real_query(con, sql, sql.characters.count) let res = mysql_use_result(con) result = mysql_foo..... } let onFinish = { ctx in print(ctx.storage[“result”]) } Process.qwork(onThread: onThread, onFinish: onFinish)
  38. 105.
  39. 108.

    • HTTPS Client • JSON • Session • DataBaseClient •

    View • Web socket Server/Client • Deploy SlimaneҎ֎ͰɺGithubΞΧ΢ϯτΛ࢖ͬͨ ChatαʔϏεʹඞཁͳ΋ͷ
  40. 109.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON • Session •

    DataBaseClient • View • Web socket • Deploy SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  41. 110.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON -> Zewo/JSON, slimane-swift/BodyParser

    • Session • DataBaseClient • View • Web socket • Deploy SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  42. 111.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON -> Zewo/JSON, slimane-swift/BodyParser

    • Session -> slimane-swift/SessionMiddleware • DataBaseClient • View • Web socket • Deploy SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  43. 112.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON -> Zewo/JSON, slimane-swift/BodyParser

    • Session -> slimane-swift/SessionMiddleware • DataBaseClient -> noppoMan/swift-redis • View • Web socket • Deploy SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  44. 113.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON -> Zewo/JSON, slimane-swift/BodyParser

    • Session -> slimane-swift/SessionMiddleware • DataBaseClient -> noppoMan/swift-redis • View -> slimane-swift/Render • Web socket • Deploy SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  45. 114.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON -> Zewo/JSON, slimane-swift/BodyParser

    • Session -> slimane-swift/SessionMiddleware • DataBaseClient -> noppoMan/swift-redis • View -> slimane-swift/Render • Web socket -> slimane-swift/WS • Deploy SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  46. 115.

    • HTTPS Client -> slimane-swift/SecureHanger • JSON -> Zewo/JSON, slimane-swift/BodyParser

    • Session -> slimane-swift/SessionMiddleware • DataBaseClient -> noppoMan/swift-redis • View -> slimane-swift/Render • Web socket -> slimane-swift/WS • Deploy -> Suv.Cluster and Suv.Signal SlimaneҎ֎ͰɺTwitterΞΧ΢ϯτΛ࢖ͬͨ ChatΞϓϦʹඞཁͳ΋ͷ
  47. 118.
  48. 122.
  49. 124.

    • TLS/HTTP 2.0 • QUIC • Async/Await • Actors or

    Coroutines(Other Project) Next Step