Slide 1

Slide 1 text

7BQPSΛ࢖ͬͯ7JTJPO1SPͱ 8FC4PDLFU௨৴Λͯ͠ΈΔ

Slide 2

Slide 2 text

ݪҰߒ ΧϯιΫΠϯμετϦʔζ୅ද 8FCσβΠϯ΍ϑϩϯτΤϯυΛத৺ʹ όοΫΤϯυɺΠϯϑϥͳͲࡶ৯తʹ͍Ζ͍Ζ ʮΑΓͻΖ͍ϑϩϯτΤϯυʯͱ͍͏αΠτΛ΍ͬͯΔ 93&"-"3+".ड৆ !LBSB@E

Slide 3

Slide 3 text

ຊ೔ͷߏ੒ ‣ 7BQPSฤ 7BQPSͱ͸ 7BQPSΛ8FC4PDLFUαʔόʔʹ͢Δ ‣ 7JTJPO1SPฤ 7JTJPO1SPͰ8FC4PDLFUΛѻ͏ ‣ ·ͱΊ ਐΊ͍ͯΔϓϩδΣΫτ

Slide 4

Slide 4 text

Ϟνϕʔγϣϯ ‣ ΋ͱ΋ͱɺγϦίϯ౥ࡌ.BD͸.BDNJOJͷΈॴ༗ ‣ ϝΠϯ͸8JOEPXTػͩͬͨ ౰࣌ ‣ 7BQPS͸ଞͱൺ΂ͯಋೖָ͕ͩͬͨ ‣ 7BQPS͍͍ײ͡ͳͷͰ8FC4PDLFUʹ΋खΛͩ͢ ීஈ࢖͍ʹ4XJGUॻ࣌ؒ͘Λ૿΍͍ͨ͠

Slide 5

Slide 5 text

7BQPSฤ $MJFOUTJEF7JTJPO1SP 4FSWFS4JEF7BQPS

Slide 6

Slide 6 text

7BQPSͱ͸ ‣ 4XJGU੡ͷ8FC ΞϓϦέʔγϣϯ ϑϨʔϜϫʔΫ ‣ 4FSWFSTJEFTXJGU ͱݺ͹Ε͍ͯΔ܈ ‣ 4XJGU/*0্ʹߏங ‣ .*5MJDFOTF

Slide 7

Slide 7 text

4XJGU/*0 ‣ 4XJGU/*0JTԿ 4XJGU/*0JTBDSPTTQMBUGPSNBTZODISPOPVTFWFOUESJWFOOFUXPSL BQQMJDBUJPOGSBNFXPSLGPSSBQJEEFWFMPQNFOUPGNBJOUBJOBCMF IJHIQFSGPSNBODFQSPUPDPMTFSWFSTDMJFOUT *UTMJLF /FUUZ CVUXSJUUFOGPS4XJGU /FUUZ͸4DBMB੡ͷ8FCΞϓϦέʔγϣϯ ϑϨʔϜϫʔΫͷ1MBZGSBNFXPSLͰ΋࠾༻͞Εͯͨ ͪͳΈʹஶॻ

Slide 8

Slide 8 text

7BQPSͷಛ௃ ‣ 7BQPS5PPMCPYͱ͍͏$-*͕͋Δ ‣ 'MVFOUͱ͍͏03.͕ඪ४Ͱར༻Մೳ ‣ -FBGͱ͍͏ςϯϓϨʔτΤϯδϯ͕༻ҙ ‣ 2VFVFTɺ8FC4PDLFUɺ+85ͳͲαϙʔτ ‣ %PDLFSDPNQPTFɺ%PDLFS fi MF΋͍ͭͯ͘Δ

Slide 9

Slide 9 text

ಋೖ΋ָ ‣ Πϯετʔϧ΍؀ڥઃఆ͸ඇৗʹָ 4XJGUͱ9DPEF͕࢖͑Δ؀ڥͳΒ$ brew install vapor͚ͩ 8JOEPXTͷ84-؀ڥͰ΋4XJGUMZͱ͔Λ࢖ͬͯ4XJGUΛಋೖ w 74$PEFͰ΋։ൃ͕Ͱ͖Δ %PDLFS؀ڥͰߏஙͯ͠΋Α͍

Slide 10

Slide 10 text

9DPEFͰͦͷ··ฤूɾϏϧυ͕Մೳ

Slide 11

Slide 11 text

ϑΝΠϧߏ੒ . ├── Dockerfile ├── Package.swift ├── Public/ ├── Sources/ │ └── App/ │ ├── Controllers/ │ ├── configure.swift │ ├── entrypoint.swift │ └── routes.swift ├── Tests/ │ └── AppTests/ │ └── AppTests.swift └── docker-compose.yml

Slide 12

Slide 12 text

8FC4PDLFUΛ͔ͭ͏ʹ͸ func routes(_ app: Application) throws { app.get { req async in ... } app.get("hello") { req async -> String in ... } app.webSocket("echo") { req, ws in ws.onText { ws, text in print(text) } } } Sources/App/routes.swift

Slide 13

Slide 13 text

3PPN؅ཧ class Room { var connections: [String: [WebSocket]] func add(ws: WebSocket, room: String) { ... // adding WebSocket to connections } func send(ws: WebSocket, room: String, text: String) { ... // broadcast to connections } init() { connections = [:] } } Sources/App/Room.swift

Slide 14

Slide 14 text

3PPNΛͲ͏อ࣋͢Δ͔ ‣ ָͯ͠ ‣ άϩʔόϧม਺ͱ͓ͯ࣋ͬͯ͘͠ͷ͸ඍົͳײ͡ 7BQPSͰ(MPCBM4UPSBHFΛߏங͢Δํ๏͕͋Δ w #VJMEJOHBHMPCBMTUPSBHFGPS7BQPSIUUQTUIFTXJGUEFWDPNCVJMEJOHBHMPCBMTUPSBHF GPSWBQPS 3FEJTͷ1VC4VCΛར༻͢Δ w 7BQPSɿ3FEJTˠ0WFSWJFXIUUQTEPDTWBQPSDPEFTSFEJTPWFSWJFX )VNNJOHCJSEͰ͸ɺϦΫΤετؒͰ৘ใΛ΍ΓͱΓͰ͖Δ࢓૊Έ͕ ͋ΔΒ͍͠ w 1FSTJTUFOUEBUBIUUQTEPDTIVNNJOHCJSEDPEFTEPDVNFOUBUJPOIVNNJOHCJSE QFSTJTUFOUEBUB nonisolated(unsafe) var room = Room()

Slide 15

Slide 15 text

ίϯιʔϧ͔Β઀ଓͯ͠ΈΔ ‣ ࢖͏ϥΠϒϥϦ XFCTPDLFUOQN ‣ αϯϓϧίʔυ ࠓճ͸γϯϓϧͳαϯϓϧͳͷͰɺ OQNʹ͋Δ΋ͷΛͦͷ··࢖͏ ઀ଓઌ͸ฤू͓ͯ͘͠ client.connect('ws://localhost:8080/echo');

Slide 16

Slide 16 text

ίϯιʔϧ͔Β઀ଓͯ͠ΈΔ ‣ ઀ଓ $ npm run start > [email protected] start > node src/client.js WebSocket Client Connected Received: '1287346' Received: '4955304' Received: '12177183' Received: '13307824' Received: '16307205' Received: '5869357' Received: '12393997' Received: '7832726'

Slide 17

Slide 17 text

7JTJPO1SPฤ $MJFOUTJEF7JTJPO1SP 4FSWFS4JEF7BQPS

Slide 18

Slide 18 text

8FC4PDLFUϥΠϒϥϦ4UBSTDSFBN ‣ ࠓճ઀ଓʹ࢖ͬͨϥΠϒϥϦ 4UBSTDSFBN ‣ ಛ௃ ಋೖָ͕ շద ڧͦ͏ Ωϟϥ͕ © IUUQTHJUIVCDPNEBMUPOJBN4UBSTDSFBN

Slide 19

Slide 19 text

8FC4PDLFUʹ઀ଓ͢Δํ๏ ‣ 9DPEFʹͯύοέʔδΛಋೖ͠ɺJNQPSU ‣ ؆୯ͳΞΫηεํ๏ import Starscream ... var request = URLRequest(url: URL(string: "http://localhost:8080/echo")!) request.timeoutInterval = 5 socket = WebSocket(request: request) socket.delegate = self socket.connect() ...

Slide 20

Slide 20 text

8FC4PDLFU$POUSPMMFSͷ༻ҙ class WebSocketController: WebSocketDelegate, ObservableObject { private var socket: WebSocket! @Published var isConnected = false @Published var messages: [String] = [] func didReceive(event: WebSocketEvent, client: WebSocketClient) { ... } init() { connect() } func connect() { ... } func disconnect() { ... } } WebSocketController.swift

Slide 21

Slide 21 text

$POUFOU7JFX͔Β࢖͏ ‣ 8FC4PDLFU$POUSPMMFS͔ΒૹΒΕͨNFTTBHFΛ औಘ struct ContentView: View { @ObservedObject var client = WebSocketController() init() { client = WebSocketController() } var body: some View { VStack { if client.isConnected { List { ForEach(client.messages, id: \.self) { m in Text(m) ...

Slide 22

Slide 22 text

ͦͷଞ΍͓ͬͯ͘ॲཧ ‣ ઀ଓॲཧ·ΘΓ ઀ଓલͷঢ়ଶɺ੾அ࣌ͷදࣔͳͲ ‣ ઀ଓΠϕϯτͷϋϯυϦϯά DPOOFDUFEEJTDPOOFDUFEUFYUCJOBSZQJOHQPOH WJBCJMJUZ$IBOHFESFDPOOFDU4VHHFTUFEDBODFMMFEFSSPS QFFS$MPTFE ‣ 4XJGU6*·ΘΓͷΠϕϯτॲཧ PO"QQFBS΍PO%JTBQQFBSͳͲ

Slide 23

Slide 23 text

·ͱΊ $MJFOUTJEF7JTJPO1SP 4FSWFS4JEF7BQPS

Slide 24

Slide 24 text

7BQPS7JTJPO1SPͰ8FC4PDLFU ‣ ͙͢ϦΞϧλΠϜίϯςϯπͮ͘ΓΛ࢝ΊΒΕΔ ‣ ͣͬͱ4XJGUΛॻ͍͍ͯΒΕΔ ‣ *%&΋͓ͳ͡Ͱ͍͚Δ ‣ 8FC4PDLFUٕज़ʹֶ͍ͭͯ΂Δ

Slide 25

Slide 25 text

7BQPSͰਐΊ͍ͯΔϓϩδΣΫτ ‣ ʮΑΓͻΖ͍ϑϩϯτΤϯυʯ7BQPSԽ ݱঢ়/FYUKT$POUFOUGVM$MPVE fl BSF1BHFT ‣ ϋοΧιϯ΍ϓϩτλΠϐϯά༻ͷ 8FC4PDLFUαʔόͷ΋ͱΛͭ͘Δ ϋοΧιϯͷରઓܕίϯςϯπͷόοΫΤϯυ෦෼୲౰ͱ͔

Slide 26

Slide 26 text

7BQPSΛ࢖ͬͯ7JTJPO1SPͱ 8FC4PDLFU௨৴Λͯ͠ΈΔ ͋Γ͕ͱ͏͍͟͝·ͨ͠