Files
herolib/lib/schemas/openrpcserver/openrpc_server.v
Mahmoud-Emad dd400ba6fa style: improve code formatting; refactor module imports
- Apply consistent alignment for struct fields and parameters
- Standardize string literal delimiters to single quotes
- Refactor module import strategy in `models` package
- Enhance asset formatting for precise decimal display
- Remove unused imports and redundant `+}` syntax artifacts
2025-09-03 11:36:02 +03:00

172 lines
3.9 KiB
V

module openrpcserver
import json
import x.json2
import net.unix
import os
import freeflowuniverse.herolib.ui.console
// THIS IS DEFAULT NEEDED FOR EACH OPENRPC SERVER WE MAKE
pub struct JsonRpcRequest {
pub:
jsonrpc string = '2.0'
method string
params string
id string
}
// JSON-RPC 2.0 response structure
pub struct JsonRpcResponse {
pub:
jsonrpc string = '2.0'
result string
error ?JsonRpcError
id string
}
// JSON-RPC 2.0 error structure
pub struct JsonRpcError {
pub:
code int
message string
data string
}
pub struct RPCServer {
pub mut:
listener &unix.StreamListener
socket_path string
}
@[params]
pub struct RPCServerArgs {
pub mut:
socket_path string = '/tmp/heromodels'
}
// Temporary struct for parsing incoming JSON-RPC requests using json2
struct JsonRpcRequestRaw {
jsonrpc string
method string
params json2.Any
id json2.Any
}
pub fn new_rpc_server(args RPCServerArgs) !&RPCServer {
// Remove existing socket file if it exists
if os.exists(args.socket_path) {
os.rm(args.socket_path)!
}
listener := unix.listen_stream(args.socket_path, unix.ListenOptions{})!
return &RPCServer{
listener: listener
socket_path: args.socket_path
}
}
pub fn (mut server RPCServer) start() ! {
console.print_header('Starting HeroModels OpenRPC Server on ${server.socket_path}')
for {
mut conn := server.listener.accept()!
spawn server.handle_connection(mut conn)
}
}
pub fn (mut server RPCServer) close() ! {
server.listener.close()!
if os.exists(server.socket_path) {
os.rm(server.socket_path)!
}
}
fn (mut server RPCServer) handle_connection(mut conn unix.StreamConn) {
defer {
conn.close() or { console.print_stderr('Error closing connection: ${err}') }
}
for {
// Read JSON-RPC request
mut buffer := []u8{len: 4096}
bytes_read := conn.read(mut buffer) or {
console.print_debug('Connection closed or error reading: ${err}')
break
}
if bytes_read == 0 {
break
}
request_data := buffer[..bytes_read].bytestr()
console.print_debug('Received request: ${request_data}')
// Process the JSON-RPC request
response := server.process_request(request_data) or {
server.create_error_response(-32603, 'Internal error: ${err}', 'null')
}
// Send response
conn.write_string(response) or {
console.print_stderr('Error writing response: ${err}')
break
}
}
}
fn (mut server RPCServer) process_request(request_data string) !string {
// Parse JSON-RPC request using json2 to handle Any types
request := json2.decode[JsonRpcRequestRaw](request_data)!
// Convert params to string representation
params_str := request.params.json_str()
// Convert id to string
id_str := request.id.json_str()
r := request.method.trim_space().to_lower()
// Route to appropriate method
result := server.process(r, params_str)!
return server.create_success_response(result, id_str)
}
// Default process method - should be overridden by implementations
pub fn (mut server RPCServer) process(method string, params_str string) !string {
return match method {
'rpc.discover' {
server.discover()!
}
else {
server.create_error_response(-32601, 'Method not found', method)
}
}
}
fn (mut server RPCServer) create_success_response(result string, id string) string {
response := JsonRpcResponse{
jsonrpc: '2.0'
result: result
id: id
}
return json.encode(response)
}
fn (mut server RPCServer) create_error_response(code int, message string, id string) string {
error := JsonRpcError{
code: code
message: message
data: 'null'
}
response := JsonRpcResponse{
jsonrpc: '2.0'
error: error
id: id
}
return json.encode(response)
}
// discover returns the OpenRPC specification for the service
pub fn (mut server RPCServer) discover() !string {
// Return a basic OpenRPC spec - should be overridden by implementations
return '{"openrpc": "1.2.6", "info": {"title": "OpenRPC Server", "version": "1.0.0"}, "methods": []}'
}