Skip to content

Commit 30bebd3

Browse files
authored
Merge pull request #92 from BambOoxX/generalize-serialization
Implement JSON serialization interface
2 parents 5b4c4d5 + 2f1bc7f commit 30bebd3

File tree

4 files changed

+118
-7
lines changed

4 files changed

+118
-7
lines changed

src/core.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ struct Request
112112
token::Union{CancellationTokens.CancellationToken,Nothing}
113113
end
114114

115-
mutable struct JSONRPCEndpoint{IOIn <: IO,IOOut <: IO}
115+
mutable struct JSONRPCEndpoint{IOIn<:IO,IOOut<:IO,S<:JSON.Serialization}
116116
pipe_in::IOIn
117117
pipe_out::IOOut
118118

@@ -129,9 +129,11 @@ mutable struct JSONRPCEndpoint{IOIn <: IO,IOOut <: IO}
129129

130130
read_task::Union{Nothing,Task}
131131
write_task::Union{Nothing,Task}
132+
133+
serialization::S
132134
end
133135

134-
JSONRPCEndpoint(pipe_in, pipe_out, err_handler = nothing) =
136+
JSONRPCEndpoint(pipe_in, pipe_out, err_handler=nothing, serialization::JSON.Serialization=JSON.StandardSerialization()) =
135137
JSONRPCEndpoint(
136138
pipe_in,
137139
pipe_out,
@@ -143,7 +145,8 @@ JSONRPCEndpoint(pipe_in, pipe_out, err_handler = nothing) =
143145
err_handler,
144146
:idle,
145147
nothing,
146-
nothing)
148+
nothing,
149+
serialization)
147150

148151
function write_transport_layer(stream, response)
149152
response_utf8 = transcode(UInt8, response)
@@ -290,7 +293,7 @@ function send_notification(x::JSONRPCEndpoint, method::AbstractString, params)
290293

291294
message = Dict("jsonrpc" => "2.0", "method" => method, "params" => params)
292295

293-
message_json = JSON.json(message)
296+
message_json = sprint(JSON.show_json, x.serialization, message)
294297

295298
put!(x.out_msg_queue, message_json)
296299

@@ -306,7 +309,7 @@ function send_request(x::JSONRPCEndpoint, method::AbstractString, params)
306309
response_channel = Channel{Any}(1)
307310
x.outstanding_requests[id] = response_channel
308311

309-
message_json = JSON.json(message)
312+
message_json = sprint(JSON.show_json, x.serialization, message)
310313

311314
put!(x.out_msg_queue, message_json)
312315

@@ -355,7 +358,7 @@ function send_success_response(endpoint, original_request::Request, result)
355358

356359
response = Dict("jsonrpc" => "2.0", "id" => original_request.id, "result" => result)
357360

358-
response_json = JSON.json(response)
361+
response_json = sprint(JSON.show_json, endpoint.serialization, response)
359362

360363
put!(endpoint.out_msg_queue, response_json)
361364
end
@@ -369,7 +372,7 @@ function send_error_response(endpoint, original_request::Request, code, message,
369372

370373
response = Dict("jsonrpc" => "2.0", "id" => original_request.id, "error" => Dict("code" => code, "message" => message, "data" => data))
371374

372-
response_json = JSON.json(response)
375+
response_json = sprint(JSON.show_json, endpoint.serialization, response)
373376

374377
put!(endpoint.out_msg_queue, response_json)
375378
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
using TestItemRunner
22

33
@run_package_tests
4+

test/shared_test_code.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,35 @@
1818
Base.:(==)(a::Foo2,b::Foo2) = a.fieldA == b.fieldA && a.fieldB == b.fieldB
1919

2020
end
21+
22+
@testmodule NamedPipes begin
23+
using Sockets, JSONRPC
24+
25+
export get_named_pipe
26+
27+
function get_named_pipe()
28+
socket_name = JSONRPC.generate_pipe_name()
29+
30+
server_is_up = Channel(1)
31+
32+
socket1_channel = Channel(1)
33+
34+
@async try
35+
server = listen(socket_name)
36+
put!(server_is_up, true)
37+
socket1 = accept(server)
38+
39+
put!(socket1_channel, socket1)
40+
catch err
41+
Base.display_error(err, catch_backtrace())
42+
end
43+
44+
wait(server_is_up)
45+
46+
socket2 = connect(socket_name)
47+
48+
socket1 = take!(socket1_channel)
49+
50+
return socket1, socket2
51+
end
52+
end

test/test_json_serialization.jl

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
@testitem "Custom JSON serialization" setup=[NamedPipes] begin
2+
using JSON
3+
using JSON: StructuralContext, begin_object, show_pair, end_object, show_json, Serializations.StandardSerialization
4+
5+
struct OurSerialization <: JSON.Serializations.CommonSerialization end
6+
7+
struct OurStruct
8+
a::String
9+
b::String
10+
end
11+
12+
function JSON.show_json(io::StructuralContext, s::OurSerialization, f::OurStruct)
13+
show_json(io, StandardSerialization(), "$(f.a):$(f.b)")
14+
end
15+
16+
x = OurStruct("Hello", "World")
17+
18+
socket1, socket2 = NamedPipes.get_named_pipe()
19+
20+
task_done = Channel(1)
21+
22+
messages_back = Channel(Inf)
23+
24+
@async try
25+
ep2 = JSONRPCEndpoint(socket1, socket1, nothing, OurSerialization())
26+
27+
run(ep2)
28+
29+
msg = JSONRPC.get_next_message(ep2)
30+
put!(messages_back, msg)
31+
32+
msg2 = JSONRPC.get_next_message(ep2)
33+
put!(messages_back, msg2)
34+
send_success_response(ep2, msg2, [x])
35+
36+
msg3 = JSONRPC.get_next_message(ep2)
37+
put!(messages_back, msg3)
38+
send_error_response(ep2, msg3, 5, "Error", [x])
39+
40+
close(ep2)
41+
finally
42+
put!(task_done, true)
43+
catch err
44+
Base.display_error(err, catch_backtrace())
45+
end
46+
47+
ep1 = JSONRPCEndpoint(socket2, socket2, nothing, OurSerialization())
48+
49+
run(ep1)
50+
51+
send_notification(ep1, "foo", [x])
52+
53+
response1 = send_request(ep1, "bar", [x])
54+
try
55+
send_request(ep1, "bar", [x])
56+
catch err_msg
57+
if err_msg isa JSONRPC.JSONRPCError
58+
@test err_msg.data == Any["Hello:World"]
59+
else
60+
rethrow(err_msg)
61+
end
62+
end
63+
64+
close(ep1)
65+
66+
wait(task_done)
67+
68+
msg1 = take!(messages_back)
69+
msg2 = take!(messages_back)
70+
msg3 = take!(messages_back)
71+
72+
@test msg1.params == ["Hello:World"]
73+
@test msg2.params == ["Hello:World"]
74+
@test msg3.params == ["Hello:World"]
75+
end

0 commit comments

Comments
 (0)