Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
iosdc_2018.pdf
Kyohei Ito
August 31, 2018
2
2.2k
iosdc_2018.pdf
Kyohei Ito
August 31, 2018
Tweet
Share
More Decks by Kyohei Ito
See All by Kyohei Ito
flutter_kaigi_2021.pdf
kyoheig3
0
530
flutter_kmm_1.pdf
kyoheig3
1
780
ca.swift_10.pdf
kyoheig3
0
540
orecon_vol1.pdf
kyoheig3
4
1.3k
iosdc_2017.pdf
kyoheig3
4
730
ca.swift_2.pdf
kyoheig3
9
1k
ca.swift.pdf
kyoheig3
1
1.8k
protocol_buffers.pdf
kyoheig3
6
5.8k
abema_devcon.pdf
kyoheig3
8
6.6k
Featured
See All Featured
Teambox: Starting and Learning
jrom
124
7.9k
Embracing the Ebb and Flow
colly
75
3.6k
YesSQL, Process and Tooling at Scale
rocio
159
12k
KATA
mclloyd
12
9.7k
Designing the Hi-DPI Web
ddemaree
273
32k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
236
1.1M
Building Adaptive Systems
keathley
27
1.3k
A Modern Web Designer's Workflow
chriscoyier
689
180k
The Invisible Customer
myddelton
113
12k
For a Future-Friendly Web
brad_frost
166
7.8k
Large-scale JavaScript Application Architecture
addyosmani
499
110k
Robots, Beer and Maslow
schacon
154
7.3k
Transcript
grpc-swiftΛͬͯ iOSΞϓϦͰշదͳ gRPC௨৴Λߦ͏ɹɹ 2018/08/31 iOSDC
About Me ҏ౻ɹګฏ Github : KyoheiG3 Twitter : @KyoheiG3
About Me ΩϡϨʔγϣϯ Ameba OWND AbemaTV SUPERCHOICE ࠓ·ͨ৽ن
gPRC
gRPCͬͯԿʁ • Google͕࡞ͬͨRPCΛ࣮ݱ͢ΔͨΊͷϑϨʔϜϫʔΫ • ͚ࣾͷStubbyΛɺ2015ʹΦʔϓϯԽͨ͠ͷ • HTTP2
RPCͬͯԿʁ • ϦϞʔτϓϩγʔδϟίʔϧͷུ • ϓϩάϥϜ͔ΒผͷΞυϨεۭؒʹ͋Δαϒϧʔνϯखଓ ͖Λ࣮ߦ͢Δ͜ͱΛՄೳʹ͢Δٕज़
HTTP2 • SPDYΛج൫ʹ࡞Γग़͞Εͨ • SPDYGoogle
Մೳͳ௨৴ํࣜ
Unaryʢ୯ൃͷ௨৴ʣ • 1ͭͷϦΫΤετʹର͠ɺϨεϙϯεΛ1ͭฦ͢ • HTTP1ܥͱಉ͡Α͏ͳεςʔτϨεͳ௨৴ํࣜ
Server StreamingʢαʔόετϦʔϛϯάʣ • 1ͭͷϦΫΤετʹର͠ɺϨεϙϯεΛෳฦ͢ • αʔόpush ϙʔϦϯάʹஔ͖ΘΔ
Client StreamingʢΫϥΠΞϯτετϦʔϛϯάʣ • ෳͷϦΫΤετʹର͠ɺϨεϙϯεΛ1ͭฦ͢ • ϑΝΠϧΞοϓϩʔυͳͲ
Bi-Directional StreamingʢํετϦʔϛϯάʣ • ෳͷϦΫΤετʹର͠ɺϨεϙϯεΛෳฦ͢ • νϟοτͳͲ
Αࣖ͘ʹ͢ΔProtocol Buffersͱͷҧ͍ͬͯʁ • Protocol Buffers௨৴͢Δσʔλͷܗࣜʢjson, xml...ʣ • gRPC௨৴ͷखஈ
͢͜͠Protocol Buffersͷ͓͞Β͍
protobuf • protobufͱུ͞ΕΔ͜ͱ͕ଟ͍ • όΠφϦϕʔε • .protoϑΝΠϧͰσʔλܗࣜΛఆٛ
echo.proto syntax = "proto3"; package echo; message EchoRequest { string
text = 1; } message EchoResponse { string text = 1; }
protobuf • .protoϑΝΠϧ͔ΒɺswiftgoϑΝΠϧΛ࡞Մೳ
protobuf $ protoc echo.proto --plugin=./protoc-gen-swift --swift_out=.
echo.pb.swift struct Echo_EchoRequest { var text: String = String() var
unknownFields = SwiftProtobuf.UnknownStorage() init() {} } struct Echo_EchoResponse { var text: String = String() var unknownFields = SwiftProtobuf.UnknownStorage() init() {} }
protobuf • swiftͰApple͕ެࣜʹαϙʔτ1 • όΠφϦͷγϦΞϥΠζɾσγϦΞϥΠζͷϥΠϒϥ Ϧʹґଘ • ܰͯ͘ܕ҆શ 1 https://github.com/apple/swift-protobuf
protobuf σϝϦοτ • ௨৴σʔλͷՄಡੑ͕͗͢Δʢͱ͍͏͔ಡΊͳ͍ʣ • ಋೖʹҰखؒඞཁ
protobuf ϝϦοτ ׂѪ͠·͢ɻ ϝϦοτͨ͘͞Μ͋ΔͷͰɺσʔλܗࣜͷબࢶͷҰͭʹೖ ΕΔͷ͋Γͩͱࢥ͍·͢ɻ
gRPC × protobuf • gRPC͕ར༻͢ΔσϑΥϧτͷσʔλܗ͕ࣜprotobuf • gRPC͋͘·Ͱ௨৴ͷखஈͳͷͰɺσʔλܗࣜҰԠjsonͱ ͔Մೳ • ͚ͲɺprotobufͱgRPCζϒζϒͳͷͰҰॹʹ͏લఏ
SwiftGRPC
SwiftGRPC • objective-cͰc++Ͱ࣮͞ΕͨgrpcΛར༻2 • swiftͰར༻͢Δʹগʑ໘ 2 https://github.com/grpc/grpc
SwiftGRPC • grpcͷΠϯλʔϑΣʔεΛswiftͰϥοϓ
Officially Supported Platforms3 C/C++, C#, Dart *, Go, Java, Node.js,
PHP *, Python, Ruby * ·ͩbeta SwiftΞϯΦϑΟγϟϧͰ͔͢?! 3 https://grpc.io/about/#osp
ಋೖ
ಋೖ • ͱʹ͔͘protobufલఏ • SwiftGRPCͷprotocϓϥάΠϯΛ࡞ • .protoϑΝΠϧ͔Β.swiftϑΝΠϧΛ࡞
protobufΛΠϯετʔϧ $ brew install protobuf
SwiftGRPCͷprotocϓϥάΠϯΛ࡞ • grpc-swiftΛcloneͯ͠build $ git clone https://github.com/grpc/grpc-swift.git $ cd grpc-swift
$ make all > .protoc-gen-swift .protoc-gen-swiftgrpc
ඞཁʹԠͯ͡pathΛ௨͢ • ࣮ߦ࣌ʹϓϥάΠϯͷpathΛࢦఆͰ͖ΔͷͰඞਢͰͳ͍ $ mkdir ~/.protoc $ cp ./protoc-gen-swift ./protoc-gen-swiftgrpc
~/.protoc $ echo 'export PATH=$PATH:$HOME/.protoc' >> ~/.bash_profile $ source ~/.bash_profile
protoc-gen-swiftgrpc • SwiftGRPCͷprotocϓϥάΠϯ • protobufͱಉ༷ʹ.proto͔Β.swiftΛ࡞
echo.protoʢbeforeʣ syntax = "proto3"; package echo; message EchoRequest { string
text = 1; } message EchoResponse { string text = 1; }
echo.protoʢserviceʣ • serviceͷதʹɺrpcϑΟʔϧυΛఆٛ͢Δ service Echo { rpc }
echo.protoʢserviceʣ • rpcϑΟʔϧυʹҙͷϝιουΛఆٛ͢Δ service Echo { rpc Get }
echo.protoʢserviceʣ • ϦΫΤετͷΦϒδΣΫτΛఆٛ͢Δ service Echo { rpc Get(EchoRequest) }
echo.protoʢserviceʣ • ϨεϙϯεͷΦϒδΣΫτΛఆٛ͢Δ service Echo { rpc Get(EchoRequest) returns(EchoResponse) {}
}
echo.protoʢserviceʣ • streamෳճͷॲཧΛՄೳʹ͢Δఆٛ service Echo { rpc Get(EchoRequest) returns (EchoResponse)
{} rpc Expand(EchoRequest) returns (stream EchoResponse) {} rpc Collect(stream EchoRequest) returns (EchoResponse) {} rpc Update(stream EchoRequest) returns (stream EchoResponse) {} }
echo.protoʢafterʣ syntax = "proto3"; package echo; message EchoRequest { string
text = 1; } message EchoResponse { string text = 1; } service Echo { rpc Get(EchoRequest) returns (EchoResponse) {} rpc Expand(EchoRequest) returns (stream EchoResponse) {} rpc Collect(stream EchoRequest) returns (EchoResponse) {} rpc Update(stream EchoRequest) returns (stream EchoResponse) {} }
protoc-gen-swiftgrpc $ protoc echo.proto --plugin=./protoc-gen-swiftgrpc --swiftgrpc_out=.
echo.grpc.swift protocol Echo_EchoProvider: ServiceProvider { func get(request: Echo_EchoRequest, session: Echo_EchoGetSession)
throws -> Echo_EchoResponse func expand(request: Echo_EchoRequest, session: Echo_EchoExpandSession) throws -> ServerStatus? func collect(session: Echo_EchoCollectSession) throws -> Echo_EchoResponse? func update(session: Echo_EchoUpdateSession) throws -> ServerStatus? } protocol Echo_EchoService: ServiceClient { func get(_ request: Echo_EchoRequest) throws -> Echo_EchoResponse func get(_ request: Echo_EchoRequest, completion: @escaping (Echo_EchoResponse?, CallResult) -> Void) throws -> Echo_EchoGetCall func expand(_ request: Echo_EchoRequest, completion: ((CallResult) -> Void)?) throws -> Echo_EchoExpandCall func collect(completion: ((CallResult) -> Void)?) throws -> Echo_EchoCollectCall func update(completion: ((CallResult) -> Void)?) throws -> Echo_EchoUpdateCall }
EchoʢαϯϓϧʣͰίʔυղઆ
Echoͷಈ͔͠ํ • SwiftGRPC.xcodeprojΛ࡞͢Δ $ make project
Echoͷಈ͔͠ํ • ./third_party/swift-protobuf͕ඞཁ • ࠷ۙऔಘεΫϦϓτ͕আ͞Εͨ4 $ mkdir third_party $ cd
third_party $ git clone https://github.com/apple/swift-protobuf.git 4 https://github.com/grpc/grpc-swift/pull/296
Echoͷಈ͔͠ํ • ./Examples/EchoXcode/Echo.xcodeprojΛ։͘
Echoͷಈ͔͠ํ • ./SwiftGRPC.xcodeprojΛϓϩδΣΫτʹՃ͢Δ
Echoͷಈ͔͠ํ • Target DependenciesʹSwiftGRPC.frameworkΛՃ͢Δ
Echo for Client
Echo_EchoServiceClient • ΫϥΠΞϯτ͔ΒαʔόͷଓΛཧ • ෦ͰChannelΦϒδΣΫτΛอ࣋ • Echo_EchoServiceʹ४ڌ • get, expand,
collect, updateϝιουΛ࣮ߦͯ͠ɺετ ϦʔϛϯάΛߦ͏ͨΊͷCallΦϒδΣΫτΛ࡞
Echo_EchoServiceClient let service = Echo_EchoServiceClient(address: "YOUR_ADDRESS", secure: false)
Echo_EchoExpandCallʢServerStreamingʣ • expand()ϝιουͰऔಘ • αʔόετϦʔϛϯά͕Մೳ • receive()ϝιουΛ࣮ߦՄೳ
Echo_EchoExpandCallʢServerStreamingʣ var requestMessage = Echo_EchoRequest() requestMessage.text = "message" let expandCall
= try service.expand(requestMessage) { _ in } try expandCall.receive { response in // ϨεϙϯεΛड͚औΔ }
Echo_EchoCollectCallʢClientStreamingʣ • collect()ϝιουͰऔಘ • ΫϥΠΞϯτετϦʔϛϯά͕Մೳ • send(), closeAndReceive()ϝιουΛ࣮ߦՄೳ
Echo_EchoCollectCallʢClientStreamingʣ let collectCall = try service.collect { _ in }
var requestMessage = Echo_EchoRequest() requestMessage.text = "message" try collectCall.send(requestMessage) { error in // ΤϥʔΛड͚औΔ } try collectCall.closeAndReceive { response in // close࣌ʹ1͚ͩσʔλΛड͚औΕΔ }
Echo_EchoUpdateCallʢBidirectionalStreamingʣ • update()ϝιουͰऔಘ • ํετϦʔϛϯά͕Մೳ • send(), receive(), closeSend()ϝιουΛ࣮ߦՄೳ
Echo_EchoUpdateCallʢBidirectionalStreamingʣ let updateCall = try service.update { _ in }
try updateCall.receive { response in // ϨεϙϯεΛड͚औΔ } var requestMessage = Echo_EchoRequest() requestMessage.text = "message" try updateCall.send(requestMessage) { error in // ΤϥʔΛड͚औΔ } try updateCall.closeSend {}
ΫϥΠΞϯτ࣮ͷجຊతͳྲྀΕ • Service͔ΒCallΦϒδΣΫτΛ࡞͢Δ • ࡞ͨ͠CallΦϒδΣΫτʹ༻ҙ͞Ε͍ͯΔstreamingͷϝ ιουΛݺͼग़͢ • CallΦϒδΣΫτstreaming͕ऴྃ͢Δ·Ͱอ͓࣋ͯ͘͠ ※ Unaryྫ֎
Echo_EchoGetCallʢUnaryʣ • get()ϝιουͰऔಘ • streaming༻ͷϝιου༻ҙ͞Ε͍ͯͳ͍
Echo_EchoGetCallʢUnaryʣ var requestMessage = Echo_EchoRequest() requestMessage.text = "message" let getCall
= try service.get(requestMessage) { response, callResult in }
ΫϥΠΞϯτ࣮ͷಛ • CallΦϒδΣΫτΛ࡞͔ͬͨ࣌ΒtimeoutΧϯτμϯ • σϑΥϧτ600ඵͰɺϦΫΤετݸผʹઃఆෆՄ • ClientStreamingͷsend()ʹҾͰͤΔtimeoutɺಉظ ௨৴͢Δࡍͷsemaphoreͷػ࣌ؒ
ΫϥΠΞϯτ࣮ͷಛ • receive()ɺ1ͰσʔλΛड͚औΔͱͦΕҎ࣮߱ߦ͞ Εͳ͍ͷͰɺ࠶receive()ΛݺͿඞཁ͕͋Δ • ͳʹ͔͠ΒͷΤϥʔ͕ग़ͨΒͦΕҎ߱ૹड৴Ͱ͖ͳ͍ͷͰɺ CallΦϒδΣΫτ͔Β࠶࡞͢Δඞཁ͕͋Δ • throws͕ͨΒଟ͍
ΫϥΠΞϯτͷstubʹ͍ͭͯ • ServerΛϩʔΧϧʹ࣮ͯ͠stubԽ
Echo for Server
ServiceServer • αʔόͷΫϥΠΞϯτ͔ΒͷଓΛཧ • ෦ͰServerΦϒδΣΫτΛอ࣋ • Echo_EchoProviderʹ४ڌͨ͠ΦϒδΣΫτΛड͚औΔ • startϝιουͰɺଓͷड৴Λ։࢝
ServiceServer class EchoProvider: Echo_EchoProvider { func get() {} func expand()
{} func collect() {} func update() {} } let provider = EchoProvider() let server = ServiceServer(address: "YOUR_ADDRESS", serviceProviders: [provider]) server.start()
Echo_EchoProvider • get, expand, collect, updateϝιουͰɺΫϥΠΞϯ τͷϨεϙϯεΛߦ͏ • ҾͰ͞ΕΔSessionΦϒδΣΫτͰৼΔ͍Λ࣮
Echo_EchoProviderʢget == Unaryʣ • Echo_EchoRequestΦϒδΣΫτΛऔಘ • Echo_EchoResponseΛฦͨ͠Βऴྃ
Echo_EchoProviderʢget == Unaryʣ func get(request: Echo_EchoRequest, session _: Echo_EchoGetSession) throws
-> Echo_EchoResponse { var response = Echo_EchoResponse() response.text = request.text + " response" return response }
Echo_EchoProviderʢexpand == ServerStreamingʣ • Echo_EchoRequestΦϒδΣΫτΛऔಘ • ඞཁʹԠͯ͡sessionͷsend()Λ࣮ߦ • ServerStatusΛฦ͠ɺ͔ͭsend()͕ྃͨ͠Βऴྃ
Echo_EchoProviderʢexpand == ServerStreamingʣ func expand(request: Echo_EchoRequest, session: Echo_EchoExpandSession) throws ->
ServerStatus? { var response = Echo_EchoResponse() response.text = request.text + " response" try! session.send(response) { // ΤϥʔΛड͚औΔ } return .ok }
Echo_EchoProviderʢcollect == ClientStreamingʣ • ϦΫΤετsessionͷreceive()Ͱऔಘ • Echo_EchoResponseΛฦͨ͠Βऴྃ
Echo_EchoProviderʢcollect == ClientStreamingʣ func collect(session: Echo_EchoCollectSession) throws -> Echo_EchoResponse? {
var response = Echo_EchoResponse() let request = try! session.receive() response.text = request.text + " response" return response }
Echo_EchoProviderʢupdate == BidiStreamingʣ • ϦΫΤετsessionͷreceive()Ͱऔಘ • ඞཁʹԠͯ͡sessionͷsend()Λ࣮ߦ • ServerStatusΛฦ͠ɺ͔ͭsend()͕ྃͨ͠Βऴྃ
Echo_EchoProviderʢupdate == BidiStreamingʣ func update(session: Echo_EchoUpdateSession) throws -> ServerStatus? {
let request = try! session.receive() var response = Echo_EchoResponse() response.text = request.text + " response" try! session.send(response) { // ΤϥʔΛड͚औΔ } return .ok }
αʔό࣮ͷجຊతͳྲྀΕ • Echo_EchoProviderʹ४ڌͨ͠ΦϒδΣΫτΛ࡞͢Δ • ProviderͷϝιουͰಉظతʹॲཧ͠ɺΛฦͯ͠ऴྃ
SwiftGRPCClient
None
SwiftGRPCClient > https://github.com/cats-oss/grpc-swift-client • ΫϥΠΞϯτઐ༻ͷgRPCϥΠϒϥϦ • SwiftGRPCʹґଘ • timeoutΛϦΫΤετ୯ҐͰܾΊͨΓ •
ϦΫΤετͷ్தͰॲཧΛΠϯλʔηϓτͨ͠Γ • receive()ΛࣗಈͰϦτϥΠͯ͘͠ΕͨΓ
protoc-gen-swiftgrpc-client $ protoc echo.proto --plugin=./protoc-gen-swiftgrpc-client --swiftgrpc-client_out=.
protoc-gen-swiftgrpc-client enum Echo_EchoMethod: String, CallMethod { case get = "Get"
static let service = "echo.Echo" } protocol _Echo_EchoGetRequest { typealias InputType = Echo_EchoRequest typealias OutputType = Echo_EchoResponse } protocol Echo_EchoGetRequest: _Echo_EchoGetRequest, UnaryStreamingRequest {} extension Echo_EchoGetRequest { var method: CallMethod { return Echo_EchoMethod.get } }
SwiftGRPCʢClientStreamingʣ let collectCall = try service.collect { _ in }
var requestMessage = Echo_EchoRequest() requestMessage.text = "message" try collectCall.send(requestMessage) { error in // ΤϥʔΛड͚औΔ } try collectCall.closeAndReceive { response in // close࣌ʹ1͚ͩσʔλΛड͚औΕΔ }
SwiftGRPCClientʢClientStreamingʣ let stream = Session.shared.stream(with: EchoClientRequest()) stream .send("message") { response
in // ૹ৴݁ՌΛड͚औΔ } stream .closeAndReceive { response in // close࣌ʹ1͚ͩσʔλΛड͚औΕΔ }
SwiftGRPCʢServerStreamingʣ var requestMessage = Echo_EchoRequest() requestMessage.text = "message" let expandCall
= try service.expand(requestMessage) { _ in } try expandCall.receive { response in // ϨεϙϯεΛड͚औΔ }
SwiftGRPCClientʢServerStreamingʣ let stream = Session.shared.stream(with: EchoServerRequest(text: "message")) .receive { response
in // ϨεϙϯεΛड͚औΔ }
SwiftGPRCClientʢRxʣ extension Reactive where Base: Streaming, Base.Request: UnaryRequest { func
data() -> Observable<Base.Request.OutputType> { return .create { observer in self.base.data { result in switch result { case .success(let data): observer.onNext(data) observer.onCompleted() case .failure(let error): observer.onError(error) } } return Disposables.create { self.base.cancel() } } } }
SwiftGPRCClientʢRxʣ Session.shared.stream(with: EchoUnaryRequest()).rx.data() .subscribe(onNext: { response in // ϨεϙϯεΛड͚औΔ },
onError: { error in // ΤϥʔΛड͚औΔ }) .disposed(by: disposeBag)
SwiftGPRCClient • ΫϥΠΞϯτʹSwiftGPRCClientΛར༻ͯ͠ɺstubͱͯ͠ SwiftGRPCͷαʔό࣮Λར༻͢Δ
ॴײͱࠓޙ
ॴײ • ࠷ॳcallͷcancel͢Βແ͔ͬͨ • ಋೖ͕ਏ͔ͬͨ • Τϥʔ࣌ͷࡉ͔͍ڍಈ͕௫ΈͮΒ͍
Swift Summit
ࠓޙ • ࠷ۙυΠπਓͷΤϯδχΞ͕ฃಆͯ͠ϝϯςφϯε • Network.frameworkͷಋೖͷݕ౼ͳͲ͕͞Ε͍ͯΔ • ͱΓ͋͑ͣਖ਼ࣜʹgrpcҰʹೖͬͯཉ͍͠
grpc-swiftΛͬͯiOSΞϓϦͰշదͳgRPC௨৴Λߦ͏ɹɹ https://github.com/cats-oss/grpc-swift-client Github : KyoheiG3 Twitter : @KyoheiG3
Thanks!