///|
let ipc_protocol_version = 1
///|
/// Returns the protocol version used in all IPC envelopes and payloads.
pub fn protocol_version() -> Int {
ipc_protocol_version
}
///|
/// One operation invocation sent from the JavaScript bridge to the user process.
pub(all) struct IpcOpRequest {
version : Int
id : String
name : String
payload : Json
} derive(ToJson, FromJson, Eq, Debug)
///|
/// One operation completion sent from the user process back to JavaScript.
///
/// `status == 0` means success. Any non-zero status means `body` contains a JSON
/// string error message suitable for rejecting the JavaScript promise.
pub(all) struct IpcOpResponse {
version : Int
id : String
status : Int
body : Json
} derive(ToJson, FromJson, Eq, Debug)
///|
/// One extension event sent from the user process to JavaScript.
pub(all) struct IpcExtensionEvent {
version : Int
extension_namespace : String
event_name : String
payload : Json
} derive(ToJson, FromJson, Eq, Debug)
///|
/// One JavaScript-facing API exposed for a remote extension namespace.
pub(all) struct IpcExtensionApi {
api_name : String
} derive(ToJson, FromJson, Eq, Debug)
///|
/// JavaScript bridge metadata for one remote extension.
pub(all) struct IpcExtensionDescriptor {
id : String
js_namespace : String
apis : Array[IpcExtensionApi]
scripts : Array[String]
} derive(ToJson, FromJson, Eq, Debug)
///|
/// Creates one operation request frame.
pub fn IpcOpRequest::new(
id : String,
name : String,
payload : Json,
) -> IpcOpRequest {
IpcOpRequest::{ version: ipc_protocol_version, id, name, payload }
}
///|
/// Creates one successful operation response frame.
pub fn IpcOpResponse::ok(id : String, body : Json) -> IpcOpResponse {
IpcOpResponse::{ version: ipc_protocol_version, id, status: 0, body }
}
///|
/// Creates one failed operation response frame.
pub fn IpcOpResponse::err(id : String, message : String) -> IpcOpResponse {
IpcOpResponse::{
version: ipc_protocol_version,
id,
status: 1,
body: Json(message),
}
}
///|
/// Returns whether this response represents success.
pub fn IpcOpResponse::is_ok(self : IpcOpResponse) -> Bool {
self.status == 0
}
///|
/// Serializes an operation request as one JSON IPC payload.
pub fn IpcOpRequest::stringify(self : IpcOpRequest) -> String {
ToJson::to_json(self).stringify()
}
///|
/// Serializes an operation response as one JSON IPC payload.
pub fn IpcOpResponse::stringify(self : IpcOpResponse) -> String {
ToJson::to_json(self).stringify()
}
///|
/// Parses one JSON IPC operation request.
pub fn parse_ipc_op_request(raw : String) -> IpcOpRequest raise IpcError {
let request : IpcOpRequest = @json.from_json(parse_json(raw)) catch {
err => raise InvalidPayload(kind="request", detail=err.to_string())
}
validate_ipc_op_request(request)
}
///|
/// Parses one JSON IPC operation response.
pub fn parse_ipc_op_response(raw : String) -> IpcOpResponse raise IpcError {
let response : IpcOpResponse = @json.from_json(parse_json(raw)) catch {
err => raise InvalidPayload(kind="response", detail=err.to_string())
}
validate_ipc_op_response(response)
}
///|
/// Creates one extension event IPC frame.
pub fn IpcExtensionEvent::new(
extension_namespace : String,
event_name : String,
payload : Json,
) -> IpcExtensionEvent {
IpcExtensionEvent::{
version: ipc_protocol_version,
extension_namespace,
event_name,
payload,
}
}
///|
/// Creates one remote extension API descriptor.
pub fn IpcExtensionApi::new(api_name : String) -> IpcExtensionApi {
IpcExtensionApi::{ api_name, }
}
///|
/// Creates one remote extension bridge descriptor.
pub fn IpcExtensionDescriptor::new(
id : String,
js_namespace : String,
apis : Array[IpcExtensionApi],
scripts? : Array[String] = [],
) -> IpcExtensionDescriptor {
IpcExtensionDescriptor::{
id,
js_namespace,
apis: apis.map(fn(api) { api }),
scripts: scripts.map(fn(script) { script }),
}
}
///|
/// Validates one decoded operation request.
pub fn IpcOpRequest::validate(
self : IpcOpRequest,
) -> IpcOpRequest raise IpcError {
validate_ipc_op_request(self)
}
///|
/// Validates one decoded operation response.
pub fn IpcOpResponse::validate(
self : IpcOpResponse,
) -> IpcOpResponse raise IpcError {
validate_ipc_op_response(self)
}
///|
/// Validates one decoded extension event.
pub fn IpcExtensionEvent::validate(
self : IpcExtensionEvent,
) -> IpcExtensionEvent raise IpcError {
validate_ipc_extension_event(self)
}
///|
fn parse_json(raw : String) -> Json raise IpcError {
@json.parse(raw) catch {
err => raise MalformedJson(detail=err.to_string())
}
}
///|
fn validate_ipc_op_request(
request : IpcOpRequest,
) -> IpcOpRequest raise IpcError {
guard request.version == ipc_protocol_version else {
raise UnsupportedVersion(
scope="protocol",
actual=request.version,
supported=ipc_protocol_version,
)
}
guard request.id.trim().to_owned() != "" else {
raise EmptyField(path="IPC request id")
}
guard request.name.trim().to_owned() != "" else {
raise EmptyField(path="IPC request name")
}
request
}
///|
fn validate_ipc_op_response(
response : IpcOpResponse,
) -> IpcOpResponse raise IpcError {
guard response.version == ipc_protocol_version else {
raise UnsupportedVersion(
scope="protocol",
actual=response.version,
supported=ipc_protocol_version,
)
}
guard response.id.trim().to_owned() != "" else {
raise EmptyField(path="IPC response id")
}
if response.status != 0 {
guard response.body is String(_) else { raise InvalidErrorResponseBody }
}
response
}
///|
fn validate_ipc_extension_event(
event : IpcExtensionEvent,
) -> IpcExtensionEvent raise IpcError {
guard event.version == ipc_protocol_version else {
raise UnsupportedVersion(
scope="event",
actual=event.version,
supported=ipc_protocol_version,
)
}
guard event.extension_namespace.trim().to_owned() != "" else {
raise EmptyField(path="IPC event extension namespace")
}
guard event.event_name.trim().to_owned() != "" else {
raise EmptyField(path="IPC event name")
}
event
}