@@ -3,6 +3,7 @@ local code = require "core.grpc.code"
3
3
local codename = require " core.grpc.codename"
4
4
local transport = require " core.http.transport"
5
5
local pb = require " pb"
6
+
6
7
local assert = assert
7
8
local pack = string.pack
8
9
local unpack = string.unpack
@@ -11,22 +12,23 @@ local sub = string.sub
11
12
local concat = table.concat
12
13
local tonumber = tonumber
13
14
local setmetatable = setmetatable
15
+
14
16
local M = {}
15
17
16
18
local HDR_SIZE <const> = 5
17
19
local BODY_START <const> = HDR_SIZE + 1
18
20
local MAX_LEN <const> = 4 * 1024 * 1024
19
21
20
- --- @param stream core.http.h2stream
21
- --- @param read fun ( stream : core.http.h2stream , timeout : number ): string ?, string ?
22
+ --- @param h2stream core.http.h2stream
22
23
--- @param is_server boolean
23
- --- @param timeout number
24
+ --- @param timeout number ?
24
25
--- @return string ?, string ? error
25
- local function read_body (stream , read , is_server , timeout )
26
+ local function read_body (h2stream , is_server , timeout )
26
27
local data = " "
27
28
-- read header
29
+ local read = h2stream .read
28
30
for i = 1 , HDR_SIZE do
29
- local d , err = read (stream , timeout )
31
+ local d , err = read (h2stream , timeout )
30
32
if not d or d == " " then
31
33
return nil , err
32
34
end
@@ -38,7 +40,7 @@ local function read_body(stream, read, is_server, timeout)
38
40
local compress , frame_size = unpack (" >I1I4" , data )
39
41
assert (compress == 0 , " grpc: compression not supported" )
40
42
if is_server and frame_size > MAX_LEN then
41
- stream :respond (200 , {
43
+ h2stream :respond (200 , {
42
44
[' content-type' ] = ' application/grpc' ,
43
45
[' grpc-status' ] = code .ResourceExhausted ,
44
46
}, true )
@@ -49,7 +51,7 @@ local function read_body(stream, read, is_server, timeout)
49
51
local buf = {data }
50
52
frame_size = frame_size - # data
51
53
while frame_size > 0 do
52
- local d , err = read (stream , timeout )
54
+ local d , err = read (h2stream , timeout )
53
55
if not d or d == " " then
54
56
return nil , err
55
57
end
@@ -66,11 +68,11 @@ local function dispatch(registrar)
66
68
local output_name = registrar .output_name
67
69
local handlers = registrar .handlers
68
70
-- use closure for less hash
69
- --- @param stream core.http.h2stream
70
- return function (stream )
71
- local status , header = stream :readheader ()
71
+ --- @param h2stream core.http.h2stream
72
+ return function (h2stream )
73
+ local status , header = h2stream :readheader ()
72
74
if status ~= 200 then
73
- stream :respond (200 , {
75
+ h2stream :respond (200 , {
74
76
[' content-type' ] = ' application/grpc' ,
75
77
[' grpc-status' ] = code .Unknown ,
76
78
[' grpc-message' ] = " grpc: invalid header"
@@ -80,9 +82,9 @@ local function dispatch(registrar)
80
82
local method = header [' :path' ]
81
83
local itype = input_name [method ]
82
84
local otype = output_name [method ]
83
- local data , err = read_body (stream , stream . read , true , nil )
85
+ local data , err = read_body (h2stream , true , nil )
84
86
if not data then
85
- stream :close ()
87
+ h2stream :close ()
86
88
logger .warn (" [core.grpc] read body failed" , err )
87
89
return
88
90
end
@@ -91,10 +93,10 @@ local function dispatch(registrar)
91
93
local outdata = pb .encode (otype , output )
92
94
-- payloadFormat, length, data
93
95
outdata = pack (" >I1I4" , 0 , # outdata ) .. outdata
94
- stream :respond (200 , {
96
+ h2stream :respond (200 , {
95
97
[' content-type' ] = ' application/grpc' ,
96
98
})
97
- stream :close (outdata , {
99
+ h2stream :close (outdata , {
98
100
[' grpc-status' ] = code .OK ,
99
101
})
100
102
end
@@ -156,55 +158,59 @@ end
156
158
157
159
local alpn_protos = {" h2" }
158
160
159
- --- @param stream core.http.h2stream
160
- local function streaming_write_wrapper (stream , method , timeout )
161
- local itype = method .input_type
162
- local write = stream .write
163
- --- @param stream core.http.h2stream
164
- --- @param req table
165
- return function (stream , req )
166
- local reqdat = pb .encode (itype , req )
167
- reqdat = pack (" >I1I4" , 0 , # reqdat ) .. reqdat
168
- return write (stream , reqdat )
169
- end
161
+ --- @class core.grpc.streaming
162
+ --- @field h2stream core.http.h2stream
163
+ --- @field need_header boolean
164
+ --- @field input_type string
165
+ --- @field output_type string
166
+ local grpc_streaming = {}
167
+ local grpc_streaming_mt = { __index = grpc_streaming }
168
+
169
+ --- @param self core.grpc.streaming
170
+ function grpc_streaming :write (req )
171
+ local h2stream = self .h2stream
172
+ local reqdat = pb .encode (self .input_type , req )
173
+ reqdat = pack (" >I1I4" , 0 , # reqdat ) .. reqdat
174
+ return h2stream :write (reqdat )
170
175
end
171
176
172
- --- @param stream core.http.h2stream
173
- local function streaming_read_wrapper (stream , method , timeout )
174
- local need_header = true
175
- local read = stream .read
176
- local otype = method .output_type
177
- return function (steam )
178
- if need_header then
179
- local status , header = stream :readheader (timeout )
180
- if not status then
181
- return nil , header
182
- end
183
- need_header = false
184
- end
185
- local data , err = read_body (stream , read , false , timeout )
186
- if not data then
187
- return nil , err
188
- end
189
- local resp = pb .decode (otype , data )
190
- if not resp then
191
- return nil , " decode error"
177
+ --- @param self core.grpc.streaming
178
+ --- @param timeout number ?
179
+ function grpc_streaming :read (timeout )
180
+ local h2stream = self .h2stream
181
+ if self .need_header then
182
+ local status , header = h2stream :readheader (timeout )
183
+ if not status then
184
+ return nil , header
192
185
end
193
- return resp , nil
186
+ self . need_header = false
194
187
end
188
+ local data , err = read_body (h2stream , false , timeout )
189
+ if not data then
190
+ return nil , err
191
+ end
192
+ local resp = pb .decode (self .output_type , data )
193
+ if not resp then
194
+ return nil , " decode error"
195
+ end
196
+ return resp , nil
195
197
end
196
198
197
199
--- @return core.grpc.stream | nil , string | nil
198
200
local function stream_call (timeout , connect , method , fullname )
199
201
return function ()
200
202
--- @class core.grpc.stream : core.http.h2stream
201
- local stream , err = connect (fullname )
202
- if not stream then
203
+ local h2stream , err = connect (fullname )
204
+ if not h2stream then
203
205
return nil , err
204
206
end
205
- stream .write = streaming_write_wrapper (stream , method , timeout )
206
- stream .read = streaming_read_wrapper (stream , method , timeout )
207
- return stream , nil
207
+ local streaming = setmetatable ({
208
+ h2stream = h2stream ,
209
+ input_type = method .input_type ,
210
+ output_type = method .output_type ,
211
+ need_header = true ,
212
+ }, grpc_streaming_mt )
213
+ return streaming , nil
208
214
end
209
215
end
210
216
@@ -213,17 +219,17 @@ local function general_call(timeout, connect, method, fullname)
213
219
local itype = method .input_type
214
220
local otype = method .output_type
215
221
return function (req )
216
- local stream <close> , err = connect (fullname )
217
- if not stream then
222
+ local h2stream <close> , err = connect (fullname )
223
+ if not h2stream then
218
224
return nil , err
219
225
end
220
226
local reqdat = pb .encode (itype , req )
221
227
reqdat = pack (" >I1I4" , 0 , # reqdat ) .. reqdat
222
- local ok , err = stream :write (reqdat )
228
+ local ok , err = h2stream :write (reqdat )
223
229
if not ok then
224
230
return nil , err
225
231
end
226
- local status , header = stream :readheader (timeout )
232
+ local status , header = h2stream :readheader (timeout )
227
233
if not status then
228
234
return nil , header
229
235
end
@@ -232,11 +238,11 @@ local function general_call(timeout, connect, method, fullname)
232
238
local grpc_status = header [' grpc-status' ]
233
239
if not grpc_status then -- normal header
234
240
local reason
235
- body , reason = read_body (stream , stream . read , false , timeout )
241
+ body , reason = read_body (h2stream , false , timeout )
236
242
if not body then
237
243
return nil , reason
238
244
end
239
- local trailer , reason = stream :readtrailer (timeout )
245
+ local trailer , reason = h2stream :readtrailer (timeout )
240
246
if not trailer then
241
247
return nil , reason
242
248
end
0 commit comments