///|
pub(all) enum RpcOutcome {
Success(Json)
DeclaredException(String, Json)
ApplicationFailure(Int, String)
} derive(Debug, Eq)
///|
pub fn Schema::make_call(
self : Schema,
service : String,
name : String,
arguments : Json,
sequence_id : Int,
) -> Message raise SchemaError {
let (owner, function_) = self.method_owner(service, name)
{
name,
sequence_id,
message_type: if function_.oneway {
4
} else {
1
},
body: self.fields_from_json(
owner,
function_.arguments,
arguments,
false,
Ref(0),
0,
),
}
}
///|
pub fn Schema::read_call(
self : Schema,
service : String,
request : Message,
) -> Json raise SchemaError {
let (owner, function_) = self.method_owner(service, request.name)
if request.message_type != (if function_.oneway { 4 } else { 1 }) {
raise InvalidSchema("request message type does not match method")
}
let fields = match request.body {
Struct(fields) => fields
_ => raise InvalidSchema("RPC arguments must be a struct")
}
let values = match
self.read_fields(owner, function_.arguments, fields, false, Ref(0), 0) {
Struct(values) => values
_ => []
}
self.fields_json(owner, function_.arguments, values, 0)
}
///|
/// Construct standard TApplicationException without an IDL dependency.
pub fn application_exception(
name : String,
sequence_id : Int,
code : Int,
message : String,
) -> Message {
{
name,
sequence_id,
message_type: 3,
body: Struct([(1, Binary(@utf8.encode(message))), (2, I32(code))]),
}
}
///|
pub fn Schema::make_reply(
self : Schema,
service : String,
name : String,
sequence_id : Int,
outcome : RpcOutcome,
) -> Message raise SchemaError {
let (owner, function_) = self.method_owner(service, name)
if function_.oneway {
raise InvalidSchema("oneway method has no reply")
}
let body = match outcome {
ApplicationFailure(code, message) =>
return application_exception(name, sequence_id, code, message)
Success(value) => {
let t = self.resolve(owner, function_.return_type, 0)
Struct(
if t == Base("void") {
[]
} else {
[(0, self.from_json_type(owner, t, value, Ref(0), 0))]
},
)
}
DeclaredException(label, value) => {
let mut selected : IdlField? = None
for field in function_.exceptions {
if field.name == label {
selected = Some(field)
break
}
}
let field = match selected {
Some(f) => f
None => raise InvalidSchema("unknown declared exception " + label)
}
Struct([
(
field.id,
self.from_json_type(
owner,
self.resolve(owner, field.field_type, 0),
value,
Ref(0),
0,
),
),
])
}
}
{ name, sequence_id, message_type: 2, body, }
}
///|
pub fn Schema::read_reply(
self : Schema,
service : String,
name : String,
response : Message,
) -> RpcOutcome raise SchemaError {
let (owner, function_) = self.method_owner(service, name)
if function_.oneway {
raise InvalidSchema("oneway method has no reply")
}
if response.name != name {
raise InvalidSchema("reply method mismatch")
}
let fields = match response.body {
Struct(fields) => fields
_ => raise InvalidSchema("reply must be a struct")
}
if response.message_type == 3 {
let mut code = 0
let mut message = ""
for pair in fields {
match pair {
(1, Binary(bytes)) =>
message = @utf8.decode(bytes) catch {
_ => raise InvalidSchema("invalid exception UTF-8")
}
(2, I32(n)) => code = n
_ => ()
}
}
return ApplicationFailure(code, message)
}
if response.message_type != 2 {
raise InvalidSchema("expected reply or application exception")
}
let return_type = self.resolve(owner, function_.return_type, 0)
let work = Ref(0)
let mut result : Value? = None
let exceptions = Map([])
for pair in fields {
if pair.0 == 0 && return_type != Base("void") {
if self.read_type(owner, return_type, pair.1, work, 0) is Some(v) {
result = Some(v)
}
} else {
for field in function_.exceptions {
if pair.0 == field.id {
let t = self.resolve(owner, field.field_type, 0)
if self.read_type(owner, t, pair.1, work, 0) is Some(v) {
exceptions[field.name] = (t, v)
}
break
}
}
}
}
if result is Some(value) {
return Success(self.json_type(owner, return_type, value, 0))
}
for field in function_.exceptions {
if exceptions.get(field.name) is Some(pair) {
return DeclaredException(
field.name,
self.json_type(owner, pair.0, pair.1, 0),
)
}
}
if return_type == Base("void") {
Success(Json::null())
} else {
ApplicationFailure(5, "missing result for " + name)
}
}