grpc_kit 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db6a319fa0f74330575752eb203e867d4882d869ec12f73643bf11bc3f147c8d
4
- data.tar.gz: 376c711925c3f8534d7e286ed1bc7015ae711f7d4e2998b89fd8a2a2a2a0daac
3
+ metadata.gz: 287f67b56117d3821a209c4be0892d6a9b7327fae3f7db509427afd2b53ef01b
4
+ data.tar.gz: f2e75960649d6f0c76fa6aae4d6370e0a7d4285d7154ca5bd1a640b5a1d458f0
5
5
  SHA512:
6
- metadata.gz: 6fa2789ac0febc6e8dfac1f57d59488d1ab4db39b32c0e529a3fb91240d890abe9021f65db6d539c0d8218dc89204ca284db3b1e302c02d5f2ff785e76d8e9a0
7
- data.tar.gz: a8d7f9a5446308d2d31fcde7f4de762a262b58a6068ded6b8a60a0787d68001b7f2cd555a7910977ab9c8cf9e8d811cbbb2da76b55aa1d96b26961af3112be75
6
+ metadata.gz: ccf9c72baa32cdecfe2d1fe8e7b1126ebb9c7e6604eef084d59ec478b34ad565912f8ebf648dadecf2cd4208441abe9cdfc31781a3f7460d542de395ee98e596
7
+ data.tar.gz: 5dbd7080945c3d1d47f4b19c488eb36a2cf60e71a28803344fc8f81d4054d42fa0cbe93929260d2e1709dd7f213c015188b8d209e34763de63a36d49b93f3e18
data/.rubocop.yml CHANGED
@@ -35,6 +35,9 @@ Style/TrailingCommaInArguments:
35
35
  Style/SafeNavigation:
36
36
  Enabled: false
37
37
 
38
+ Style/WhileUntilModifier:
39
+ Enabled: false
40
+
38
41
  Naming/PredicateName:
39
42
  NamePrefixBlacklist:
40
43
  - "is_"
data/.travis.yml CHANGED
@@ -1,5 +1,44 @@
1
- sudo: false
2
1
  language: ruby
2
+ cache:
3
+ - bundler
4
+ - apt
5
+ dist: trusty
6
+ sudo: required
7
+ compiler:
8
+ - clang
9
+ addons:
10
+ apt:
11
+ sources:
12
+ - ubuntu-toolchain-r-test
13
+ packages:
14
+ - g++-7
15
+ - autoconf
16
+ - automake
17
+ - autotools-dev
18
+ - libtool
19
+ - pkg-config
20
+ - zlib1g-dev
21
+ - libcunit1-dev
22
+ - libssl-dev
23
+ - libxml2-dev
24
+ - libev-dev
25
+ - libevent-dev
26
+ - libjansson-dev
27
+ - libjemalloc-dev
28
+ - libc-ares-dev
29
+ - cmake
30
+ - cmake-data
3
31
  rvm:
4
- - 2.4.3
5
- before_install: gem install bundler -v 1.16.0
32
+ - ruby-head
33
+ - 2.5.3
34
+ - 2.4.5
35
+ - 2.3.8
36
+ before_install:
37
+ - bin/nghttp2
38
+ - export LD_LIBRARY_PATH=$HOME/lib:$LD_LIBRARY_PATH
39
+ - export PKG_CONFIG_PATH=$HOME/lib/pkgconfig:$PKG_CONFIG_PATH
40
+ - gem install bundler -v 1.16.0
41
+
42
+ matrix:
43
+ allow_failures:
44
+ - rvm: ruby-head
data/README.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # GrpcKit
2
2
 
3
+ [![Build Status](https://travis-ci.org/ganmacs/grpc_kit.svg?branch=master)](https://travis-ci.org/ganmacs/grpc_kit)
4
+ [![Gem Version](https://badge.fury.io/rb/grpc_kit.svg)](https://badge.fury.io/rb/grpc_kit)
5
+
3
6
  __UNDER DEVELOPMENT__
4
7
 
5
- A kit for creating [gRPC](https://grpc.io/) server/client.
8
+ A kit for creating [gRPC](https://grpc.io/) server/client in Ruby.
6
9
 
7
10
  ## Installation
8
11
 
data/TODO.md ADDED
@@ -0,0 +1,64 @@
1
+ ## Features
2
+
3
+ ### request response
4
+
5
+ - [x] recv/send msg
6
+ - [x] metadata (client)
7
+ - [x] metadata (server)
8
+ - [x] interceptor (client)
9
+ - [x] interceptor (server)
10
+ - [x] deadline (client)
11
+ - [x] deadline (server)
12
+
13
+ ### server streamer
14
+
15
+ - [x] recv/send msg
16
+ - [ ] metadata (client)
17
+ - [ ] metadata (server)
18
+ - [x] interceptor (client)
19
+ - [x] interceptor (server)
20
+ - [ ] deadline (client)
21
+ - [ ] deadline (server)
22
+
23
+ ### client streamer
24
+
25
+ - [x] recv/send msg
26
+ - [ ] metadata (client)
27
+ - [ ] metadata (server)
28
+ - [x] interceptor (client)
29
+ - [x] interceptor (server)
30
+ - [ ] deadline (client)
31
+ - [ ] deadline (server)
32
+
33
+ ### bidi_streamer
34
+
35
+ - [ ] recv/send msg
36
+ - [ ] metadata (client)
37
+ - [ ] metadata (server)
38
+ - [ ] interceptor (client)
39
+ - [ ] interceptor (server)
40
+ - [ ] deadline (client)
41
+ - [ ] deadline (server)
42
+
43
+ ## Error handling
44
+
45
+ - [x] resouce exhausted (body size is to large)
46
+ - [x] internal
47
+ - [ ] resouce exhausted (worker is exhausted)
48
+ - [ ] duration parse in header
49
+ - [ ] send `grpc-status` along with header frame if possible
50
+ - need to support https://nghttp2.org/documentation/nghttp2_submit_response.html, data_prd is not NULL
51
+ - [x] unimplemented error
52
+ - [ ] goaway
53
+ - [ ] cancel
54
+ - [ ] support h2's header continuation
55
+
56
+ ## Others
57
+
58
+ - [x] multi thread (griffin)
59
+ - [x] mutli process (griffin)
60
+ - [ ] connection persistent (client, griffin)
61
+ - [ ] send metadata in trailrs frame
62
+ - [ ] add server request spec
63
+ - [ ] add client request spec
64
+ - [ ] handle RST FRAME
data/bin/nghttp2 ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ VERSION=1.33.0
6
+
7
+ curl -sSfLO https://github.com/nghttp2/nghttp2/releases/download/v"$VERSION"/nghttp2-"$VERSION".tar.gz
8
+ tar xf nghttp2-"$VERSION".tar.gz
9
+ cd nghttp2-"$VERSION"
10
+ ./configure --prefix="$HOME" --enable-lib-only
11
+ make && make install
data/grpc_kit.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'googleapis-common-protos-types', '~> 1.0.2'
28
28
 
29
29
  spec.add_development_dependency 'bundler'
30
- spec.add_development_dependency 'grpc-tools'
30
+ spec.add_development_dependency 'grpc-tools', '~> 1.15.0'
31
31
  spec.add_development_dependency 'pry-byebug'
32
32
  spec.add_development_dependency 'rake'
33
33
  spec.add_development_dependency 'rspec'
@@ -5,31 +5,70 @@ require 'grpc_kit/status_codes'
5
5
  module GrpcKit
6
6
  module Errors
7
7
  # https://github.com/grpc/grpc/blob/23b5b1a5a9c7084c5b64d4998ee15af0f77bd589/doc/statuscodes.md
8
+
9
+ def self.from_status_code(code, message)
10
+ CODES.fetch(code).new(message)
11
+ end
12
+
8
13
  class BadStatus < StandardError
9
- def initialize(code, message)
10
- super("#{code} #{message}")
14
+ attr_reader :code, :reason
15
+
16
+ def initialize(code, reason)
11
17
  @code = code
12
- @message = message
18
+ @reason = reason
19
+ super("[#{GrpcKit::StatusCodes::CODE_NAME[code]}] #{reason}")
20
+ end
21
+ end
22
+
23
+ class Unknown < BadStatus
24
+ def initialize(mesage)
25
+ super(GrpcKit::StatusCodes::UNKNOWN, mesage)
13
26
  end
14
27
  end
15
28
 
16
- class DeadlienExceeded < BadStatus
17
- def initialize(msg)
18
- super(
19
- GrpcKit::StatusCodes::DEADLINE_EXCEEDED,
20
- msg.to_s,
21
- # "Deadline expires before server returns status: #{msg}"
22
- )
29
+ class DeadlineExceeded < BadStatus
30
+ def initialize(mesage)
31
+ super(GrpcKit::StatusCodes::DEADLINE_EXCEEDED, mesage)
23
32
  end
24
33
  end
25
34
 
26
35
  class Unimplemented < BadStatus
27
- def initialize(name)
28
- super(
29
- GrpcKit::StatusCodes::UNIMPLEMENTED,
30
- "Method not found at server: #{name}"
31
- )
36
+ def initialize(mesage)
37
+ super(GrpcKit::StatusCodes::UNIMPLEMENTED, mesage)
32
38
  end
33
39
  end
40
+
41
+ class ResourceExhausted < BadStatus
42
+ def initialize(mesage)
43
+ super(GrpcKit::StatusCodes::RESOURCE_EXHAUSTED, mesage)
44
+ end
45
+ end
46
+
47
+ class Internal < BadStatus
48
+ def initialize(mesage)
49
+ super(GrpcKit::StatusCodes::INTERNAL, mesage)
50
+ end
51
+ end
52
+
53
+ CODES = {
54
+ # GrpcKit::StatusCode::OK => 'OK',
55
+ # GrpcKit::StatusCode::CANCELLED => 'CANCELLED',
56
+ GrpcKit::StatusCodes::UNKNOWN => Unknown,
57
+ # GrpcKit::StatusCode::INVALID_ARGUMENT => 'INVALID_ARGUMENT',
58
+ GrpcKit::StatusCodes::DEADLINE_EXCEEDED => DeadlineExceeded,
59
+ # GrpcKit::StatusCode::NOT_FOUND => 'NOT_FOUND',
60
+ # GrpcKit::StatusCode::ALREADY_EXISTS => 'ALREADY_EXISTS',
61
+ # GrpcKit::StatusCode::PERMISSION_DENIED => 'PERMISSION_DENIED',
62
+ GrpcKit::StatusCodes::RESOURCE_EXHAUSTED => ResourceExhausted,
63
+ # GrpcKit::StatusCode::FAILED_PRECONDITION => 'FAILED_PRECONDITION',
64
+ # GrpcKit::StatusCode::ABORTED => 'ABORTED',
65
+ # GrpcKit::StatusCode::OUT_OF_RANGE => 'OUT_OF_RANGE',
66
+ GrpcKit::StatusCodes::UNIMPLEMENTED => Unimplemented,
67
+ GrpcKit::StatusCodes::INTERNAL => Internal,
68
+ # GrpcKit::StatusCode::UNAVAILABLE => 'UNAVAILABLE',
69
+ # GrpcKit::StatusCode::DATA_LOSS => 'DATA_LOSS',
70
+ # GrpcKit::StatusCode::UNAUTHENTICATED => 'UNAUTHENTICATED',
71
+ # GrpcKit::StatusCode::DO_NOT_USE => 'DO_NOT_USE',
72
+ }.freeze
34
73
  end
35
74
  end
@@ -39,7 +39,7 @@ module GrpcKit
39
39
  rpc_descs[rpc_desc.path] = rpc_desc
40
40
 
41
41
  define_method(rpc_desc.ruby_style_name) do |_, _|
42
- raise GrpcKit::Errors::Unimplemented, name.to_s
42
+ raise GrpcKit::Errors::Unimplemented, "Method not found: #{name}"
43
43
  end
44
44
  end
45
45
 
@@ -8,11 +8,11 @@ module GrpcKit
8
8
  class ClientStreamer < Streaming
9
9
  private
10
10
 
11
- def invoke(interceptor, call)
11
+ def invoke(interceptor, call, metadata)
12
12
  # We don't need a `:requests` parameter but,
13
13
  # it shuoldn't remove from paramters due to having a compatibility of grpc gem.
14
- interceptor.client_streamer(requests: nil, call: call, method: call.method, metadata: nil) do |s|
15
- yield(s)
14
+ interceptor.client_streamer(requests: nil, call: call, method: call.method, metadata: metadata) do
15
+ yield(call, metadata)
16
16
  end
17
17
  end
18
18
  end
@@ -21,8 +21,8 @@ module GrpcKit
21
21
  module Server
22
22
  class ClientStreamer < Streaming
23
23
  def invoke(interceptor, call)
24
- interceptor.client_streamer(call: call, method: call.method) do |s|
25
- yield(s)
24
+ interceptor.client_streamer(call: call, method: call.method) do
25
+ yield(call)
26
26
  end
27
27
  end
28
28
  end
@@ -8,11 +8,11 @@ module GrpcKit
8
8
  class ServerStreamer < Streaming
9
9
  private
10
10
 
11
- def invoke(interceptor, call)
11
+ def invoke(interceptor, call, metadata)
12
12
  # We don't need a `:request` parameter but,
13
13
  # it shuoldn't remove from paramters due to having a compatibility of grpc gem.
14
- interceptor.server_streamer(request: nil, call: call, method: call.method, metadata: nil) do |s|
15
- yield(s)
14
+ interceptor.server_streamer(request: nil, call: call, method: call.method, metadata: metadata) do
15
+ yield(call, metadata)
16
16
  end
17
17
  end
18
18
  end
@@ -23,8 +23,8 @@ module GrpcKit
23
23
  def invoke(interceptor, call)
24
24
  # We don't need a `:request` parameter but,
25
25
  # it shuoldn't remove from paramters due to having a compatibility of grpc gem.
26
- interceptor.server_streamer(request: nil, call: call, method: call.method) do |s|
27
- yield(s)
26
+ interceptor.server_streamer(request: nil, call: call, method: call.method) do
27
+ yield(call)
28
28
  end
29
29
  end
30
30
  end
@@ -11,25 +11,25 @@ module GrpcKit
11
11
  @interceptors = nil
12
12
  end
13
13
 
14
- def intercept(call, &block)
14
+ def intercept(call, metadata, &block)
15
15
  if @interceptors && !@interceptors.empty?
16
- do_intercept(@interceptors.dup, call, &block)
16
+ do_intercept(@interceptors.dup, call, metadata, &block)
17
17
  else
18
- yield(call)
18
+ yield(call, metadata)
19
19
  end
20
20
  end
21
21
 
22
22
  private
23
23
 
24
- def do_intercept(interceptors, call)
24
+ def do_intercept(interceptors, call, metadata)
25
25
  if interceptors.empty?
26
- return yield(call)
26
+ return yield(call, metadata)
27
27
  end
28
28
 
29
29
  interceptor = interceptors.pop
30
- invoke(interceptor, call) do |inter_call|
31
- do_intercept(interceptors, inter_call) do |c|
32
- yield(c)
30
+ invoke(interceptor, call, metadata) do |inter_call, meta|
31
+ do_intercept(interceptors, inter_call, meta) do |c, m|
32
+ yield(c, m)
33
33
  end
34
34
  end
35
35
  end
@@ -7,9 +7,9 @@ module GrpcKit
7
7
  module Client
8
8
  class ClientStreamer < Base
9
9
  def invoke(session, _request, authority:, metadata: {}, timeout: nil, **opts)
10
- cs = GrpcKit::Streams::Client.new(path: @config.path, protobuf: @config.protobuf, session: session, authority: authority)
10
+ cs = GrpcKit::Streams::Client.new(config: @config, session: session, authority: authority)
11
11
  call = GrpcKit::Rpcs::Call.new(metadata, @config.method_name, @config.service_name, cs)
12
- @config.interceptor.intercept(call) do |s|
12
+ @config.interceptor.intercept(call, metadata) do |s|
13
13
  s
14
14
  end
15
15
  end
@@ -19,7 +19,7 @@ module GrpcKit
19
19
  module Server
20
20
  class ClientStreamer < Base
21
21
  def invoke(stream, session)
22
- ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: @config.protobuf, session: session)
22
+ ss = GrpcKit::Streams::Server.new(stream: stream, session: session, config: @config)
23
23
  call = GrpcKit::Rpcs::Call.new(stream.headers.metadata, @config.method_name, @config.service_name, ss)
24
24
 
25
25
  if @config.interceptor
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/status_codes'
4
+
5
+ module GrpcKit
6
+ module Rpcs
7
+ module Client
8
+ class Error
9
+ # def invoke(session, request, authority:, error)
10
+ # end
11
+ end
12
+ end
13
+
14
+ module Server
15
+ class Error
16
+ def send_bad_status(stream, session, bad_status)
17
+ ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: nil, session: session)
18
+ ss.send_status(status: bad_status.code, msg: bad_status.grpc_message)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,19 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'grpc_kit/rpcs/base'
4
+ require 'grpc_kit/status_codes'
4
5
 
5
6
  module GrpcKit
6
7
  module Rpcs
7
8
  module Client
8
9
  class RequestResponse < Base
9
10
  def invoke(session, request, authority:, metadata: {}, timeout: nil, **opts)
10
- cs = GrpcKit::Streams::Client.new(path: @config.path, protobuf: @config.protobuf, session: session, authority: authority)
11
+ cs = GrpcKit::Streams::Client.new(config: @config, session: session, authority: authority)
11
12
 
12
13
  call = GrpcKit::Rpcs::Call.new(metadata, @config.method_name, @config.service_name, cs)
13
14
  @config.interceptor.intercept(request, call, metadata) do |r, c, m|
14
15
  if timeout
15
16
  # XXX: when timeout.to_timeout is 0
16
- Timeout.timeout(timeout.to_timeout, GrpcKit::Errors::DeadlienExceeded) do
17
+ Timeout.timeout(timeout.to_timeout, GrpcKit::Errors::DeadlineExceeded) do
17
18
  c.send_msg(r, timeout: timeout.to_s, metadata: m, last: true)
18
19
  c.recv(last: true)
19
20
  end
@@ -29,10 +30,23 @@ module GrpcKit
29
30
  module Server
30
31
  class RequestResponse < Base
31
32
  def invoke(stream, session)
32
- ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: @config.protobuf, session: session)
33
+ ss = GrpcKit::Streams::Server.new(stream: stream, session: session, config: @config)
33
34
  call = GrpcKit::Rpcs::Call.new(stream.headers.metadata, @config.method_name, @config.service_name, ss)
34
35
 
36
+ begin
37
+ do_invoke(ss, call)
38
+ rescue GrpcKit::Errors::BadStatus => e
39
+ ss.send_status(status: e.code, msg: e.reason, metadata: {}) # TODO: metadata should be set
40
+ rescue StandardError => e
41
+ ss.send_status(status: GrpcKit::StatusCodes::UNKNOWN, msg: e.message, metadata: {})
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def do_invoke(ss, call)
35
48
  request = ss.recv(last: true)
49
+
36
50
  resp =
37
51
  if @config.interceptor
38
52
  @config.interceptor.intercept(request, call) do |req, c|
@@ -7,11 +7,11 @@ module GrpcKit
7
7
  module Client
8
8
  class ServerStreamer < Base
9
9
  def invoke(session, request, authority:, metadata: {}, timeout: nil, **opts)
10
- cs = GrpcKit::Streams::Client.new(path: @config.path, protobuf: @config.protobuf, session: session, authority: authority)
10
+ cs = GrpcKit::Streams::Client.new(config: @config, session: session, authority: authority)
11
11
  call = GrpcKit::Rpcs::Call.new(metadata, @config.method_name, @config.service_name, cs)
12
12
 
13
- @config.interceptor.intercept(call) do |c|
14
- c.send_msg(request, last: true)
13
+ @config.interceptor.intercept(call, metadata) do |c, m|
14
+ c.send_msg(request, metadata: m, last: true)
15
15
  c
16
16
  end
17
17
  end
@@ -21,7 +21,7 @@ module GrpcKit
21
21
  module Server
22
22
  class ServerStreamer < Base
23
23
  def invoke(stream, session)
24
- ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: @config.protobuf, session: session)
24
+ ss = GrpcKit::Streams::Server.new(stream: stream, session: session, config: @config)
25
25
  call = GrpcKit::Rpcs::Call.new(stream.headers.metadata, @config.method_name, @config.service_name, ss)
26
26
 
27
27
  if @config.interceptor
@@ -34,7 +34,7 @@ module GrpcKit
34
34
  @handler.send(@config.ruby_style_method_name, request, call)
35
35
  end
36
36
 
37
- stream.end_write
37
+ ss.send_trailer
38
38
  end
39
39
  end
40
40
  end
data/lib/grpc_kit/rpcs.rb CHANGED
@@ -4,6 +4,7 @@ require 'grpc_kit/rpcs/request_response'
4
4
  require 'grpc_kit/rpcs/client_streamer'
5
5
  require 'grpc_kit/rpcs/server_streamer'
6
6
  require 'grpc_kit/rpcs/bidi_streamer'
7
+ require 'grpc_kit/rpcs/error'
7
8
 
8
9
  module GrpcKit
9
10
  module Rpcs
@@ -8,8 +8,11 @@ module GrpcKit
8
8
  def initialize(interceptors: [])
9
9
  @sessions = []
10
10
  @rpc_descs = {}
11
+ @error_rpc = GrpcKit::Rpcs::Server::Error.new
11
12
  @interceptors = interceptors
12
13
  @mutex = Mutex.new
14
+
15
+ GrpcKit.logger.debug("Launched grpc_kit(v#{GrpcKit::VERSION})")
13
16
  end
14
17
 
15
18
  # @params handler [object]
@@ -24,7 +27,6 @@ module GrpcKit
24
27
  end
25
28
 
26
29
  def run(conn)
27
- GrpcKit.logger.debug("Run grpc_kit(v#{GrpcKit::VERSION})")
28
30
  establish_session(conn) do |s|
29
31
  s.submit_settings([])
30
32
  s.start
@@ -42,7 +44,7 @@ module GrpcKit
42
44
  def dispatch(stream, session)
43
45
  rpc = @rpc_descs[stream.headers.path]
44
46
  unless rpc
45
- raise "Unkown path #{path}"
47
+ return @error_rpc.send_bad_status(stream, session, GrpcKit::Errors::Unimplemented.new(stream.headers.path))
46
48
  end
47
49
 
48
50
  rpc.invoke(stream, session)
@@ -10,27 +10,30 @@ module GrpcKit
10
10
  @end_read = false
11
11
  @end_write = false
12
12
  @finish = false
13
- @write_byte_size = 0
14
13
  end
15
14
 
16
15
  def write(data, last: false)
16
+ return 0 if data.empty?
17
+
17
18
  end_write if last
18
- @write_byte_size += data.size
19
19
 
20
20
  if @buffer
21
21
  @buffer << data
22
22
  else
23
- @buffer = data
23
+ @buffer = data.dup
24
24
  end
25
+
26
+ data.bytesize
25
27
  end
26
28
 
27
29
  def read(len = nil, last: false)
28
- end_read if last
29
-
30
- if @buffer.nil?
30
+ if @buffer.nil? || @buffer.empty?
31
31
  return ''
32
32
  end
33
33
 
34
+ end_read if last
35
+
36
+ # TODO: more efficient code
34
37
  if len
35
38
  @buffer.slice!(0...len)
36
39
  else
@@ -33,7 +33,7 @@ module GrpcKit
33
33
  stream = @streams.fetch(stream_id)
34
34
 
35
35
  loop do
36
- if (!want_read? && !want_write?) || stream.end_stream?
36
+ if (!want_read? && !want_write?) || stream.close?
37
37
  break
38
38
  end
39
39
 
@@ -81,7 +81,7 @@ module GrpcKit
81
81
  stream = @streams[frame.stream_id]
82
82
 
83
83
  if frame.end_stream?
84
- stream.remote_end_stream = true
84
+ stream.close_remote
85
85
  end
86
86
 
87
87
  unless stream.inflight
@@ -92,7 +92,7 @@ module GrpcKit
92
92
  stream = @streams[frame.stream_id]
93
93
 
94
94
  if frame.end_stream?
95
- stream.remote_end_stream = true
95
+ stream.close_remote
96
96
  end
97
97
 
98
98
  # when DS9::Frames::Goaway
@@ -109,7 +109,7 @@ module GrpcKit
109
109
  when DS9::Frames::Data, DS9::Frames::Headers
110
110
  stream = @streams[frame.stream_id]
111
111
  if frame.end_stream?
112
- stream.local_end_stream = true
112
+ stream.close_local
113
113
  end
114
114
  end
115
115
 
@@ -122,7 +122,7 @@ module GrpcKit
122
122
  stream = @streams.delete(stream_id)
123
123
  return unless stream
124
124
 
125
- stream.end_stream
125
+ stream.close
126
126
  end
127
127
 
128
128
  # nghttp2_session_callbacks_set_on_data_chunk_recv_callback
@@ -137,9 +137,12 @@ module GrpcKit
137
137
  # def on_frame_not_send(frame, reason)
138
138
  # end
139
139
 
140
- # # for nghttp2_session_callbacks_set_on_header_callback
141
- # def on_header(name, value, frame, flags)
142
- # end
140
+ # for nghttp2_session_callbacks_set_on_header_callback
141
+ def on_header(name, value, frame, _flags)
142
+ GrpcKit.logger.debug("#{name} => #{value}")
143
+ stream = @streams[frame.stream_id]
144
+ stream.add_header(name, value)
145
+ end
143
146
 
144
147
  # # for nghttp2_session_callbacks_set_on_begin_headers_callback
145
148
  # def on_begin_header(name, value, frame, flags)
@@ -12,6 +12,7 @@ module GrpcKit
12
12
 
13
13
  # @params val [String]
14
14
  def self.decode(value)
15
+ value = value.dup
15
16
  size = value.size
16
17
  if size < 2
17
18
  raise "Invalid format: too short #{value}"
@@ -36,19 +36,18 @@ module GrpcKit
36
36
  when ':path'
37
37
  self.path = val
38
38
  when ':status'
39
- self.http_status = val.to_i
39
+ self.http_status = Integer(val)
40
40
  when 'content-type'
41
41
  # TODO
42
42
  metadata[key] = val
43
43
  when 'grpc-encoding'
44
44
  self.grpc_encoding = val
45
45
  when 'grpc-status'
46
- self.grpc_status = val.to_i
46
+ self.grpc_status = val
47
47
  when 'grpc-timeout'
48
48
  self.timeout = Duration.decode(val)
49
49
  when 'grpc-message'
50
- # TODO
51
- GrpcKit.logger.warn('grpc-message is unsupported header now')
50
+ self.status_message = val
52
51
  when 'grpc-status-details-bin'
53
52
  # TODO
54
53
  GrpcKit.logger.warn('grpc-status-details-bin is unsupported header now')