rpc example
This commit is contained in:
Binary file not shown.
@@ -2,40 +2,73 @@
|
|||||||
|
|
||||||
import freeflowuniverse.herolib.schemas.jsonrpc
|
import freeflowuniverse.herolib.schemas.jsonrpc
|
||||||
|
|
||||||
mut cl:=jsonrpc.new_unix_socket_client("/tmp/zinit.sock")
|
// Define the service status response structure based on the OpenRPC schema
|
||||||
|
struct ServiceStatus {
|
||||||
|
name string
|
||||||
send_params := jsonrpc.SendParams{
|
pid int
|
||||||
timeout: 30
|
state string
|
||||||
retry: 1
|
target string
|
||||||
|
after map[string]string
|
||||||
}
|
}
|
||||||
//[]string{} = T is the generic type for the request, which can be any type
|
|
||||||
request := jsonrpc.new_request_generic('service_list', []string{})
|
|
||||||
|
|
||||||
// send sends a JSON-RPC request with parameters of type T and expects a response with result of type D.
|
// Create a client using the Unix socket transport
|
||||||
// This method handles the full request-response cycle including validation and error handling.
|
mut cl := jsonrpc.new_unix_socket_client("/tmp/zinit.sock")
|
||||||
//
|
|
||||||
// Type Parameters:
|
|
||||||
// - T: The type of the request parameters
|
|
||||||
// - D: The expected type of the response result
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - request: The JSON-RPC request object with parameters of type T
|
|
||||||
// - params: Configuration parameters for the send operation
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - The response result of type D or an error if any step in the process fails
|
|
||||||
// pub fn (mut c Client) send[T, D](request RequestGeneric[T], params SendParams) !D {
|
|
||||||
result := cl.send[[]string, map[string]string](request, send_params)!
|
|
||||||
|
|
||||||
// println('Service List:')
|
// Example 1: List all services
|
||||||
// for service in result {
|
// Create a request for service_list method with empty parameters
|
||||||
// println(service)
|
list_request := jsonrpc.new_request_generic('service_list', []string{})
|
||||||
// }
|
|
||||||
|
// Send the request and receive a map of service names to states
|
||||||
|
println('Sending service_list request...')
|
||||||
|
service_list := cl.send[[]string, map[string]string](list_request)!
|
||||||
// user := client.send[UserParams, UserResult](request, send_params) or {
|
|
||||||
// eprintln('Error sending request: $err')
|
// Display the service list
|
||||||
// return
|
println('Service List:')
|
||||||
|
println(service_list)
|
||||||
|
|
||||||
|
// Example 2: Get status of a specific service
|
||||||
|
// First, check if we have any services to query
|
||||||
|
if service_list.len > 0 {
|
||||||
|
// Get the first service name from the list
|
||||||
|
service_name := service_list.keys()[0]
|
||||||
|
|
||||||
|
// Create a request for service_status method with the service name as parameter
|
||||||
|
// The parameter for service_status is a single string (service name)
|
||||||
|
status_request := jsonrpc.new_request_generic('service_status', {"name": service_name})
|
||||||
|
|
||||||
|
// Send the request and receive a ServiceStatus object
|
||||||
|
println('\nSending service_status request for service: $service_name')
|
||||||
|
service_status := cl.send[ map[string]string, ServiceStatus](status_request)!
|
||||||
|
|
||||||
|
// Display the service status details
|
||||||
|
println('Service Status:')
|
||||||
|
println('- Name: ${service_status.name}')
|
||||||
|
println('- PID: ${service_status.pid}')
|
||||||
|
println('- State: ${service_status.state}')
|
||||||
|
println('- Target: ${service_status.target}')
|
||||||
|
println('- Dependencies:')
|
||||||
|
for dep_name, dep_state in service_status.after {
|
||||||
|
println(' - $dep_name: $dep_state')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println('\nNo services found to query status')
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Example 3: Alternative approach using a string array for the parameter
|
||||||
|
// // Some JSON-RPC servers expect parameters as an array, even for a single parameter
|
||||||
|
// println('\nAlternative approach using array parameter:')
|
||||||
|
// if service_list.len > 0 {
|
||||||
|
// service_name := service_list.keys()[0]
|
||||||
|
|
||||||
|
// // Create a request with the service name in an array
|
||||||
|
// status_request_alt := jsonrpc.new_request_generic('service_status', service_name)
|
||||||
|
|
||||||
|
// // Send the request and receive a ServiceStatus object
|
||||||
|
// println('Sending service_status request for service: $service_name (array parameter)')
|
||||||
|
// service_status_alt := cl.send[[]string, ServiceStatus](status_request_alt)!
|
||||||
|
|
||||||
|
// // Display the service status details
|
||||||
|
// println('Service Status (alternative):')
|
||||||
|
// println('- Name: ${service_status_alt.name}')
|
||||||
|
// println('- State: ${service_status_alt.state}')
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ mut:
|
|||||||
@[params]
|
@[params]
|
||||||
pub struct SendParams {
|
pub struct SendParams {
|
||||||
pub:
|
pub:
|
||||||
// Maximum time in seconds to wait for a response (default: 60)
|
// Maximum time in seconds to wait for a response (default: 2)
|
||||||
timeout int = 60
|
timeout int = 2
|
||||||
|
|
||||||
// Number of times to retry the request if it fails
|
// Number of times to retry the request if it fails
|
||||||
retry int
|
retry int
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ pub fn new_request(method string, params string) Request {
|
|||||||
jsonrpc: jsonrpc_version
|
jsonrpc: jsonrpc_version
|
||||||
method: method
|
method: method
|
||||||
params: params
|
params: params
|
||||||
id: rand.i32() // Automatically generate a unique ID using UUID v4
|
id: rand.int_in_range(1, 1000000) or {panic("Failed to generate unique ID")}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ pub fn new_request_generic[T](method string, params T) RequestGeneric[T] {
|
|||||||
jsonrpc: jsonrpc_version
|
jsonrpc: jsonrpc_version
|
||||||
method: method
|
method: method
|
||||||
params: params
|
params: params
|
||||||
id: rand.i32()
|
id: rand.int_in_range(1, 1000000000) or { panic("Failed to generate unique ID") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
lib/schemas/jsonrpc/troubleshoot_unix_socket.md
Normal file
12
lib/schemas/jsonrpc/troubleshoot_unix_socket.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use netcat:
|
||||||
|
|
||||||
|
nc -U /tmp/zinit.sock
|
||||||
|
|
||||||
|
now copy following
|
||||||
|
{"jsonrpc":"2.0","method":"service_list","params":[],"id":286703868}
|
||||||
|
|
||||||
|
should return something like this:
|
||||||
|
{"jsonrpc":"2.0","id":286703868,"result":{"test_service":"Running"}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ module jsonrpc
|
|||||||
|
|
||||||
import net.unix
|
import net.unix
|
||||||
import time
|
import time
|
||||||
import json
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
// UnixSocketTransport implements the IRPCTransportClient interface for Unix domain sockets
|
// UnixSocketTransport implements the IRPCTransportClient interface for Unix domain sockets
|
||||||
struct UnixSocketTransport {
|
struct UnixSocketTransport {
|
||||||
@@ -20,56 +20,51 @@ pub fn new_unix_socket_transport(socket_path string) &UnixSocketTransport {
|
|||||||
// send implements the IRPCTransportClient interface
|
// send implements the IRPCTransportClient interface
|
||||||
pub fn (mut t UnixSocketTransport) send(request string, params SendParams) !string {
|
pub fn (mut t UnixSocketTransport) send(request string, params SendParams) !string {
|
||||||
// Create a Unix domain socket client
|
// Create a Unix domain socket client
|
||||||
|
// console.print_debug('Connecting to Unix socket at: $t.socket_path')
|
||||||
mut socket := unix.connect_stream(t.socket_path)!
|
mut socket := unix.connect_stream(t.socket_path)!
|
||||||
defer { socket.close() or {} }
|
|
||||||
|
// Ensure socket is always closed, even if there's an error
|
||||||
|
defer {
|
||||||
|
// Close the socket explicitly
|
||||||
|
unix.shutdown(socket.sock.handle)
|
||||||
|
socket.close() or {}
|
||||||
|
// console.print_debug('Socket closed')
|
||||||
|
}
|
||||||
|
|
||||||
// Set timeout if specified
|
// Set timeout if specified
|
||||||
if params.timeout > 0 {
|
if params.timeout > 0 {
|
||||||
socket.set_read_timeout(params.timeout * time.second)
|
socket.set_read_timeout(params.timeout * time.second)
|
||||||
socket.set_write_timeout(params.timeout * time.second)
|
socket.set_write_timeout(params.timeout * time.second)
|
||||||
|
// console.print_debug('Set socket timeout to ${params.timeout} seconds')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
|
// console.print_debug('Sending request: $request')
|
||||||
socket.write_string(request + '\n')!
|
socket.write_string(request + '\n')!
|
||||||
|
// println(18)
|
||||||
|
|
||||||
// Read the response
|
// Read the response in a single call with a larger buffer
|
||||||
mut response := ''
|
mut res := []u8{len: 8192, cap: 8192}
|
||||||
mut buf := []u8{len: 4096}
|
n := socket.read(mut res)!
|
||||||
|
// println(19)
|
||||||
|
|
||||||
for {
|
// Convert response to string and trim whitespace
|
||||||
bytes_read := socket.read(mut buf)!
|
mut response := res[..n].bytestr().trim_space()
|
||||||
if bytes_read <= 0 {
|
// console.print_debug('Received ${n} bytes')
|
||||||
break
|
|
||||||
}
|
|
||||||
response += buf[..bytes_read].bytestr()
|
|
||||||
|
|
||||||
// Check if we've received a complete JSON response
|
// Basic validation
|
||||||
if response.ends_with('}') {
|
if response.len == 0 {
|
||||||
break
|
return error('Empty response received from server')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.print_debug('Response: $response')
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client provides a client interface to the zinit JSON-RPC API over Unix socket
|
|
||||||
// @[heap]
|
|
||||||
// pub struct UnixSocketClient {
|
|
||||||
// mut:
|
|
||||||
// socket_path string
|
|
||||||
// rpc_client &Client
|
|
||||||
// request_id int
|
|
||||||
// }
|
|
||||||
|
|
||||||
// new_client creates a new zinit client instance
|
// new_client creates a new zinit client instance
|
||||||
// socket_path: path to the Unix socket (default: /tmp/zinit.sock)
|
// socket_path: path to the Unix socket (default: /tmp/zinit.sock)
|
||||||
pub fn new_unix_socket_client(socket_path string) &Client {
|
pub fn new_unix_socket_client(socket_path string) &Client {
|
||||||
mut transport := new_unix_socket_transport(socket_path)
|
mut transport := new_unix_socket_transport(socket_path)
|
||||||
mut rpc_client := new_client(transport)
|
mut rpc_client := new_client(transport)
|
||||||
// return &UnixSocketClient{
|
|
||||||
// socket_path: socket_path
|
|
||||||
// rpc_client: rpc_client
|
|
||||||
// request_id: 0
|
|
||||||
// }
|
|
||||||
return rpc_client
|
return rpc_client
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user