...
This commit is contained in:
190
pkg/servers/ui/models/openrpc_manager.go
Normal file
190
pkg/servers/ui/models/openrpc_manager.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/openrpc"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/openrpc/models"
|
||||
)
|
||||
|
||||
// OpenRPCUIManager is the interface for managing OpenRPC specifications in the UI
|
||||
type OpenRPCUIManager interface {
|
||||
// ListSpecs returns a list of all loaded specification names
|
||||
ListSpecs() []string
|
||||
|
||||
// GetSpec returns an OpenRPC specification by name
|
||||
GetSpec(name string) *models.OpenRPCSpec
|
||||
|
||||
// ListMethods returns a list of all method names in a specification
|
||||
ListMethods(specName string) []string
|
||||
|
||||
// GetMethod returns a method from a specification
|
||||
GetMethod(specName, methodName string) *models.Method
|
||||
|
||||
// ExecuteRPC executes an RPC call
|
||||
ExecuteRPC(specName, methodName, socketPath string, params interface{}) (interface{}, error)
|
||||
}
|
||||
|
||||
// OpenRPCManager implements the OpenRPCUIManager interface
|
||||
type OpenRPCManager struct {
|
||||
manager *openrpc.ORPCManager
|
||||
}
|
||||
|
||||
// NewOpenRPCManager creates a new OpenRPCUIManager
|
||||
func NewOpenRPCManager() OpenRPCUIManager {
|
||||
manager := openrpc.NewORPCManager()
|
||||
|
||||
// Try to load specs from the default directory
|
||||
specDirs := []string{
|
||||
"./pkg/openrpc/services",
|
||||
"./pkg/openrpc/specs",
|
||||
"./specs/openrpc",
|
||||
}
|
||||
|
||||
for _, dir := range specDirs {
|
||||
err := manager.LoadSpecs(dir)
|
||||
if err == nil {
|
||||
// Successfully loaded specs from this directory
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &OpenRPCManager{
|
||||
manager: manager,
|
||||
}
|
||||
}
|
||||
|
||||
// ListSpecs returns a list of all loaded specification names
|
||||
func (m *OpenRPCManager) ListSpecs() []string {
|
||||
return m.manager.ListSpecs()
|
||||
}
|
||||
|
||||
// GetSpec returns an OpenRPC specification by name
|
||||
func (m *OpenRPCManager) GetSpec(name string) *models.OpenRPCSpec {
|
||||
return m.manager.GetSpec(name)
|
||||
}
|
||||
|
||||
// ListMethods returns a list of all method names in a specification
|
||||
func (m *OpenRPCManager) ListMethods(specName string) []string {
|
||||
return m.manager.ListMethods(specName)
|
||||
}
|
||||
|
||||
// GetMethod returns a method from a specification
|
||||
func (m *OpenRPCManager) GetMethod(specName, methodName string) *models.Method {
|
||||
return m.manager.GetMethod(specName, methodName)
|
||||
}
|
||||
|
||||
// ExecuteRPC executes an RPC call
|
||||
func (m *OpenRPCManager) ExecuteRPC(specName, methodName, socketPath string, params interface{}) (interface{}, error) {
|
||||
// Create JSON-RPC request
|
||||
request := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"method": methodName,
|
||||
"params": params,
|
||||
"id": 1,
|
||||
}
|
||||
|
||||
// Marshal request to JSON
|
||||
requestJSON, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
|
||||
// Check if socket path is a Unix socket or HTTP endpoint
|
||||
if socketPath[:1] == "/" {
|
||||
// Unix socket
|
||||
return executeUnixSocketRPC(socketPath, requestJSON)
|
||||
} else {
|
||||
// HTTP endpoint
|
||||
return executeHTTPRPC(socketPath, requestJSON)
|
||||
}
|
||||
}
|
||||
|
||||
// executeUnixSocketRPC executes an RPC call over a Unix socket
|
||||
func executeUnixSocketRPC(socketPath string, requestJSON []byte) (interface{}, error) {
|
||||
// Connect to Unix socket
|
||||
conn, err := net.Dial("unix", socketPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to socket %s: %w", socketPath, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Set timeout
|
||||
deadline := time.Now().Add(10 * time.Second)
|
||||
if err := conn.SetDeadline(deadline); err != nil {
|
||||
return nil, fmt.Errorf("failed to set deadline: %w", err)
|
||||
}
|
||||
|
||||
// Send request
|
||||
if _, err := conn.Write(requestJSON); err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
// Read response
|
||||
var buf bytes.Buffer
|
||||
if _, err := buf.ReadFrom(conn); err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
// Parse response
|
||||
var response map[string]interface{}
|
||||
if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse response: %w", err)
|
||||
}
|
||||
|
||||
// Check for error
|
||||
if errObj, ok := response["error"]; ok {
|
||||
return nil, fmt.Errorf("RPC error: %v", errObj)
|
||||
}
|
||||
|
||||
// Return result
|
||||
return response["result"], nil
|
||||
}
|
||||
|
||||
// executeHTTPRPC executes an RPC call over HTTP
|
||||
func executeHTTPRPC(endpoint string, requestJSON []byte) (interface{}, error) {
|
||||
// Create HTTP request
|
||||
req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestJSON))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
|
||||
}
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Create HTTP client with timeout
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Send request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send HTTP request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check status code
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP error: %s", resp.Status)
|
||||
}
|
||||
|
||||
// Parse response
|
||||
var response map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse response: %w", err)
|
||||
}
|
||||
|
||||
// Check for error
|
||||
if errObj, ok := response["error"]; ok {
|
||||
return nil, fmt.Errorf("RPC error: %v", errObj)
|
||||
}
|
||||
|
||||
// Return result
|
||||
return response["result"], nil
|
||||
}
|
Reference in New Issue
Block a user