174 lines
4.7 KiB
Go
174 lines
4.7 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
|
|
orpcmodels "git.ourworld.tf/herocode/heroagent/pkg/openrpc/models"
|
|
uimodels "git.ourworld.tf/herocode/heroagent/pkg/servers/ui/models"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// OpenRPCController handles requests related to OpenRPC specifications
|
|
type OpenRPCController struct {
|
|
openrpcManager uimodels.OpenRPCUIManager
|
|
}
|
|
|
|
// NewOpenRPCController creates a new instance of OpenRPCController
|
|
func NewOpenRPCController(openrpcManager uimodels.OpenRPCUIManager) *OpenRPCController {
|
|
return &OpenRPCController{
|
|
openrpcManager: openrpcManager,
|
|
}
|
|
}
|
|
|
|
// OpenRPCPageData represents the data needed for the OpenRPC UI pages
|
|
type OpenRPCPageData struct {
|
|
Title string
|
|
Specs []string
|
|
SelectedSpec string
|
|
Methods []string
|
|
SelectedMethod string
|
|
Method *orpcmodels.Method
|
|
SocketPath string
|
|
ExampleParams string
|
|
Result string
|
|
Error string
|
|
}
|
|
|
|
// ShowOpenRPCUI renders the OpenRPC UI page
|
|
func (c *OpenRPCController) ShowOpenRPCUI(ctx *fiber.Ctx) error {
|
|
// Get query parameters
|
|
selectedSpec := ctx.Query("spec", "")
|
|
selectedMethod := ctx.Query("method", "")
|
|
socketPath := ctx.Query("socketPath", "")
|
|
|
|
// Get all specs
|
|
specs := c.openrpcManager.ListSpecs()
|
|
|
|
// Initialize page data using fiber.Map instead of struct
|
|
pageData := fiber.Map{
|
|
"Title": "OpenRPC UI",
|
|
"SpecList": specs,
|
|
"SelectedSpec": selectedSpec,
|
|
"SocketPath": socketPath,
|
|
}
|
|
|
|
// If a spec is selected, get its methods
|
|
if selectedSpec != "" {
|
|
methods := c.openrpcManager.ListMethods(selectedSpec)
|
|
pageData["Methods"] = methods
|
|
pageData["SelectedMethod"] = selectedMethod
|
|
|
|
// If a method is selected, get its details
|
|
if selectedMethod != "" {
|
|
method := c.openrpcManager.GetMethod(selectedSpec, selectedMethod)
|
|
if method != nil {
|
|
pageData["Method"] = method
|
|
|
|
// Generate example parameters if available
|
|
if len(method.Examples) > 0 {
|
|
exampleParams, err := json.MarshalIndent(method.Examples[0].Params, "", " ")
|
|
if err == nil {
|
|
pageData["ExampleParams"] = string(exampleParams)
|
|
}
|
|
} else if len(method.Params) > 0 {
|
|
// Generate example from parameter schema
|
|
exampleParams := generateExampleParams(method.Params)
|
|
jsonParams, err := json.MarshalIndent(exampleParams, "", " ")
|
|
if err == nil {
|
|
pageData["ExampleParams"] = string(jsonParams)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ctx.Render("pages/rpcui", pageData)
|
|
}
|
|
|
|
// ExecuteRPC handles RPC execution requests
|
|
func (c *OpenRPCController) ExecuteRPC(ctx *fiber.Ctx) error {
|
|
// Parse request
|
|
var request struct {
|
|
Spec string `json:"spec"`
|
|
Method string `json:"method"`
|
|
SocketPath string `json:"socketPath"`
|
|
Params json.RawMessage `json:"params"`
|
|
}
|
|
|
|
if err := ctx.BodyParser(&request); err != nil {
|
|
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Invalid request: " + err.Error(),
|
|
})
|
|
}
|
|
|
|
// Validate request
|
|
if request.Spec == "" || request.Method == "" || request.SocketPath == "" {
|
|
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Missing required fields: spec, method, or socketPath",
|
|
})
|
|
}
|
|
|
|
// Parse params
|
|
var params interface{}
|
|
if len(request.Params) > 0 {
|
|
if err := json.Unmarshal(request.Params, ¶ms); err != nil {
|
|
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Invalid parameters: " + err.Error(),
|
|
})
|
|
}
|
|
}
|
|
|
|
// Execute RPC
|
|
result, err := c.openrpcManager.ExecuteRPC(request.Spec, request.Method, request.SocketPath, params)
|
|
if err != nil {
|
|
log.Printf("Error executing RPC: %v", err)
|
|
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
// Return result
|
|
return ctx.JSON(fiber.Map{
|
|
"result": result,
|
|
})
|
|
}
|
|
|
|
// generateExampleParams generates example parameters from parameter schemas
|
|
func generateExampleParams(params []orpcmodels.Parameter) map[string]interface{} {
|
|
example := make(map[string]interface{})
|
|
|
|
for _, param := range params {
|
|
example[param.Name] = generateExampleValue(param.Schema)
|
|
}
|
|
|
|
return example
|
|
}
|
|
|
|
// generateExampleValue generates an example value from a schema
|
|
func generateExampleValue(schema orpcmodels.SchemaObject) interface{} {
|
|
switch schema.Type {
|
|
case "string":
|
|
return "example"
|
|
case "number":
|
|
return 0
|
|
case "integer":
|
|
return 0
|
|
case "boolean":
|
|
return false
|
|
case "array":
|
|
if schema.Items != nil {
|
|
return []interface{}{generateExampleValue(*schema.Items)}
|
|
}
|
|
return []interface{}{}
|
|
case "object":
|
|
obj := make(map[string]interface{})
|
|
for name, propSchema := range schema.Properties {
|
|
obj[name] = generateExampleValue(propSchema)
|
|
}
|
|
return obj
|
|
default:
|
|
return nil
|
|
}
|
|
}
|