module jsonrpc import x.json2 import rand // Request represents a JSON-RPC 2.0 request object. // It contains all the required fields according to the JSON-RPC 2.0 specification. // See: https://www.jsonrpc.org/specification#request_object pub struct Request { pub mut: // The JSON-RPC protocol version, must be exactly "2.0" jsonrpc string @[required] // The name of the method to be invoked on the server method string @[required] // The parameters to the method, encoded as a JSON string // This can be omitted if the method doesn't require parameters params string // An identifier established by the client that must be included in the response // This is used to correlate requests with their corresponding responses id string @[required] } // new_request creates a new JSON-RPC request with the specified method and parameters. // It automatically sets the JSON-RPC version to the current version and generates a unique ID. // // Parameters: // - method: The name of the method to invoke on the server // - params: The parameters to the method, encoded as a JSON string // // Returns: // - A fully initialized Request object pub fn new_request(method string, params string) Request { return Request{ jsonrpc: jsonrpc.jsonrpc_version method: method params: params id: rand.uuid_v4() // Automatically generate a unique ID using UUID v4 } } // decode_request parses a JSON string into a Request object. // // Parameters: // - data: A JSON string representing a JSON-RPC request // // Returns: // - A Request object or an error if parsing fails pub fn decode_request(data string) !Request { return json2.decode[Request](data)! } // encode serializes the Request object into a JSON string. // // Returns: // - A JSON string representation of the Request pub fn (req Request) encode() string { return json2.encode(req) } // validate checks if the Request object contains all required fields // according to the JSON-RPC 2.0 specification. // // Returns: // - An error if validation fails, otherwise nothing pub fn (req Request) validate() ! { if req.jsonrpc == '' { return error('request jsonrpc version not specified') } else if req.id == '' { return error('request id is empty') } else if req.method == '' { return error('request method is empty') } } // RequestGeneric is a type-safe version of the Request struct that allows // for strongly-typed parameters using generics. // This provides compile-time type safety for request parameters. pub struct RequestGeneric[T] { pub mut: // The JSON-RPC protocol version, must be exactly "2.0" jsonrpc string @[required] // The name of the method to be invoked on the server method string @[required] // The parameters to the method, with a specific type T params T // An identifier established by the client id string @[required] } // new_request_generic creates a new generic JSON-RPC request with strongly-typed parameters. // It automatically sets the JSON-RPC version and generates a unique ID. // // Parameters: // - method: The name of the method to invoke on the server // - params: The parameters to the method, of type T // // Returns: // - A fully initialized RequestGeneric object with parameters of type T pub fn new_request_generic[T](method string, params T) RequestGeneric[T] { return RequestGeneric[T]{ jsonrpc: jsonrpc.jsonrpc_version method: method params: params id: rand.uuid_v4() } } // decode_request_id extracts just the ID field from a JSON-RPC request string. // This is useful when you only need the ID without parsing the entire request. // // Parameters: // - data: A JSON string representing a JSON-RPC request // // Returns: // - The ID as a string, or an error if the ID field is missing pub fn decode_request_id(data string) !string { data_any := json2.raw_decode(data)! data_map := data_any.as_map() id_any := data_map['id'] or { return error('ID field not found') } return id_any.str() } // decode_request_method extracts just the method field from a JSON-RPC request string. // This is useful when you need to determine the method without parsing the entire request. // // Parameters: // - data: A JSON string representing a JSON-RPC request // // Returns: // - The method name as a string, or an error if the method field is missing pub fn decode_request_method(data string) !string { data_any := json2.raw_decode(data)! data_map := data_any.as_map() method_any := data_map['method'] or { return error('Method field not found') } return method_any.str() } // decode_request_generic parses a JSON string into a RequestGeneric object with parameters of type T. // // Parameters: // - data: A JSON string representing a JSON-RPC request // // Returns: // - A RequestGeneric object with parameters of type T, or an error if parsing fails pub fn decode_request_generic[T](data string) !RequestGeneric[T] { return json2.decode[RequestGeneric[T]](data)! } // encode serializes the RequestGeneric object into a JSON string. // // Returns: // - A JSON string representation of the RequestGeneric object pub fn (req RequestGeneric[T]) encode[T]() string { return json2.encode(req) }