///|
/// BiDi JSON codec
///|
/// Serialize request to JSON string
pub fn BidiRequest::to_json(self : BidiRequest) -> String {
let obj : Map[String, Json] = {}
obj["id"] = Json::number(self.id.to_double())
obj["method"] = Json::string(self.method_name)
match self.params {
Some(p) => obj["params"] = p
None => ()
}
Json::object(obj).stringify()
}
///|
/// Parse incoming command request JSON for BiDi server implementations.
pub fn parse_request(json_str : String) -> Result[BidiRequest, String] {
let json = @json.parse(json_str) catch { _ => return Err("Invalid JSON") }
match json {
Object(map) => parse_request_map(map)
_ => Err("Invalid JSON")
}
}
///|
fn parse_request_map(map : Map[String, Json]) -> Result[BidiRequest, String] {
let id = match map.get("id") {
Some(Number(n, ..)) =>
if n.trunc() == n {
n.to_int()
} else {
return Err("Invalid id field")
}
_ => return Err("Missing id field")
}
let method_name = match map.get("method") {
Some(String(method_name)) => method_name
_ => return Err("Missing method field")
}
Ok({ id, method_name, params: map.get("params") })
}
///|
/// Serialize a WebDriver BiDi success response envelope.
pub fn success_response_to_json(id : Int, result : Json?) -> String {
let obj : Map[String, Json] = {}
obj["id"] = Json::number(id.to_double())
obj["type"] = Json::string("success")
match result {
Some(value) => obj["result"] = value
None => obj["result"] = Json::object({})
}
Json::object(obj).stringify()
}
///|
/// Serialize a WebDriver BiDi error response envelope.
pub fn error_response_to_json(
id : Int,
code : String,
message : String,
) -> String {
error_response_to_json_with_stacktrace(id, code, message, "")
}
///|
/// Serialize a WebDriver BiDi error response envelope with stacktrace.
pub fn error_response_to_json_with_stacktrace(
id : Int,
code : String,
message : String,
stacktrace : String,
) -> String {
let obj : Map[String, Json] = {}
obj["id"] = Json::number(id.to_double())
obj["type"] = Json::string("error")
obj["error"] = Json::string(code)
obj["message"] = Json::string(message)
obj["stacktrace"] = Json::string(stacktrace)
Json::object(obj).stringify()
}
///|
/// Serialize a WebDriver BiDi event envelope.
pub fn event_to_json(event_method : String, params : Json) -> String {
Json::object({
"type": Json::string("event"),
"method": Json::string(event_method),
"params": params,
}).stringify()
}
///|
/// Parse incoming message (response/event)
pub fn parse_incoming(json_str : String) -> Result[BidiIncoming, String] {
let json = @json.parse(json_str) catch { _ => return Err("Invalid JSON") }
match json {
Object(map) =>
match map.get("type") {
Some(String("event")) => parse_event(map)
Some(String("success")) => parse_response(map)
Some(String("error")) => parse_response(map)
Some(String(t)) => Err("Unknown message type: " + t)
_ => Err("Missing type field")
}
_ => Err("Invalid JSON")
}
}
///|
/// Parse response from JSON object map
fn parse_response(map : Map[String, Json]) -> Result[BidiIncoming, String] {
let id = match map.get("id") {
Some(Number(n, ..)) =>
if n.trunc() == n {
n.to_int()
} else {
return Err("Invalid id field")
}
_ => return Err("Missing id field")
}
let is_error = match map.get("type") {
Some(String("error")) => true
_ => false
}
if is_error {
let error = match map.get("error") {
Some(String(s)) => s
_ => return Err("Missing error field")
}
let message = match map.get("message") {
Some(String(s)) => s
_ => return Err("Missing message field")
}
let stacktrace = match map.get("stacktrace") {
Some(String(s)) => s
_ => ""
}
let err : BidiError = { error, message, stacktrace }
Ok(BidiIncoming::Response({ id, result: None, error: Some(err) }))
} else {
let result = match map.get("result") {
Some(value) => value
None => return Err("Missing result field")
}
Ok(BidiIncoming::Response({ id, result: Some(result), error: None }))
}
}
///|
/// Parse event from JSON object map
fn parse_event(map : Map[String, Json]) -> Result[BidiIncoming, String] {
let method_name = match map.get("method") {
Some(String(s)) => s
_ => return Err("Missing method field")
}
let params = match map.get("params") {
Some(Object(obj)) => Json::object(obj)
Some(_) => return Err("Invalid params field")
None => Json::object({})
}
Ok(BidiIncoming::Event({ event_method: method_name, params }))
}
///|
/// JSON helper: get string field
fn get_string_field(json : Json, key : String) -> String? {
match json {
Object(map) =>
match map.get(key) {
Some(String(s)) => Some(s)
_ => None
}
_ => None
}
}
///|
/// JSON helper: get bool field
fn get_bool_field(json : Json, key : String) -> Bool? {
match json {
Object(map) =>
match map.get(key) {
Some(True) => Some(true)
Some(False) => Some(false)
_ => None
}
_ => None
}
}
///|
/// JSON helper: get object field
fn get_object_field(json : Json, key : String) -> Json? {
match json {
Object(map) =>
match map.get(key) {
Some(Object(obj)) => Some(Json::object(obj))
_ => None
}
_ => None
}
}
///|
/// JSON helper: get array field
fn get_array_field(json : Json, key : String) -> Array[Json]? {
match json {
Object(map) =>
match map.get(key) {
Some(Array(items)) => Some(items)
_ => None
}
_ => None
}
}