-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathmsgformat.jl
121 lines (101 loc) · 3.65 KB
/
msgformat.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
abstract type AbstractMsgFormat end
"""
Intermediate format based on JSON.
A JSON object with `cmd` (string), `args` (array), `vargs` (dict).
"""
struct JSONMsgFormat <: AbstractMsgFormat
end
wireformat(fmt::JSONMsgFormat, cmd::String, args...; data...) = JSON.json(_dict_fmt(cmd, args...; data...))
wireformat(fmt::JSONMsgFormat, code::Int, headers::Dict{String,String}, resp, id=nothing) = JSON.json(_dict_fmt(code, headers, resp, id))
juliaformat(fmt::JSONMsgFormat, msgstr) = JSON.parse(msgstr)
"""
Intermediate format based on Julia serialization.
A dict with `cmd` (string), `args` (array), `vargs` (dict).
"""
struct SerializedMsgFormat <: AbstractMsgFormat
end
wireformat(fmt::SerializedMsgFormat, cmd::String, args...; data...) = _dict_ser(_dict_fmt(cmd, args...; data...))
wireformat(fmt::SerializedMsgFormat, code::Int, headers::Dict{String,String}, resp, id=nothing) = _dict_ser(_dict_fmt(code, headers, resp, id))
juliaformat(fmt::SerializedMsgFormat, msgstr) = _dict_dser(msgstr)
"""
Intermediate format that is just a Dict. No serialization.
A Dict with `cmd` (string), `args` (array), `vargs` (dict).
"""
struct DictMsgFormat <: AbstractMsgFormat
end
wireformat(fmt::DictMsgFormat, cmd::String, args...; data...) = _dict_fmt(cmd, args...; data...)
wireformat(fmt::DictMsgFormat, code::Int, headers::Dict{String,String}, resp, id=nothing) = _dict_fmt(code, headers, resp, id)
juliaformat(fmt::DictMsgFormat, msg) = msg
##############################################
# common interface methods for message formats
##############################################
cmd(fmt::AbstractMsgFormat, msg) = get(msg, "cmd", "")
args(fmt::AbstractMsgFormat, msg) = get(msg, "args", [])
function data(fmt::AbstractMsgFormat, msg)
vargs = get(msg, "vargs", Dict{Symbol,Any}())
isa(vargs, Dict{Symbol,Any}) && (return vargs)
dict = Dict{Symbol,Any}()
for (n,v) in vargs
dict[Symbol(n)] = v
end
dict
end
"""
extract and return the response data as a direct function call would have returned
but throw error if the call was not successful.
"""
fnresponse(fmt::AbstractMsgFormat, resp) = _dict_fnresponse(resp)
"""construct an HTTP Response object from the API response"""
httpresponse(fmt::AbstractMsgFormat, resp) = _dict_httpresponse(resp)
##############################################
# common utility methods for message formats
##############################################
function data_dict(data)
d = Dict{Symbol,Any}()
for (n,v) in data
d[n] = v
end
d
end
function _dict_ser(d)
io = IOBuffer()
serialize(io, d)
take!(io)
end
_dict_dser(b) = deserialize(IOBuffer(b))
function _dict_fmt(cmd::String, args...; data...)
req = Dict{String,Any}()
req["cmd"] = cmd
isempty(args) || (req["args"] = args)
isempty(data) || (req["vargs"] = data_dict(data))
req
end
function _dict_fmt(code::Int, headers::Dict{String,String}, resp, id=nothing)
msg = Dict{String,Any}()
(id == nothing) || (msg["nid"] = id)
if !isempty(headers)
msg["hdrs"] = headers
@debug("sending headers", headers)
end
msg["code"] = code
msg["data"] = resp
msg
end
function _dict_httpresponse(resp)
hdrs = Dict{String,String}()
if "hdrs" in keys(resp)
for (k,v) in resp["hdrs"]
hdrs[k] = v
end
end
data = get(resp, "data", "")
respdata = isa(data, Array) ? convert(Array{UInt8}, data) :
isa(data, Dict) ? JSON.json(data) :
string(data)
HTTP.Response(resp["code"], hdrs; body=respdata)
end
function _dict_fnresponse(resp)
data = get(resp, "data", "")
(resp["code"] == ERR_CODES[:success][1]) || error("API error: $data")
data
end