heroagent/openrpc_manager_plan.md
2025-05-24 09:52:43 +04:00

6.4 KiB

OpenRPC Manager Implementation Plan

1. Understanding the Requirements

The task requires us to:

  • Create an OpenRPC Manager (ORPCManager)
  • Read JSON files from services in pkg/openrpc
  • Create a model for OpenRPC spec in a separate file
  • Read the OpenRPC specs into the model
  • Keep these models in memory in the ORPCManager
  • Create supporting methods like list_methods
  • Create a command in @cmd/ to test this behavior

2. Project Structure

Here's the proposed file structure for our implementation:

pkg/
  openrpc/
    models/
      spec.go       # OpenRPC specification model
    manager.go      # ORPCManager implementation
cmd/
  orpctest/
    main.go         # Test command for the ORPCManager

3. Implementation Details

3.1 OpenRPC Specification Model (pkg/openrpc/models/spec.go)

We'll create a Go struct model that represents the OpenRPC specification based on the structure observed in zinit.json:

classDiagram
    class OpenRPCSpec {
        +string OpenRPC
        +InfoObject Info
        +Server[] Servers
        +Method[] Methods
    }
    
    class InfoObject {
        +string Version
        +string Title
        +string Description
        +LicenseObject License
    }
    
    class LicenseObject {
        +string Name
    }
    
    class Server {
        +string Name
        +string URL
    }
    
    class Method {
        +string Name
        +string Description
        +Parameter[] Params
        +ResultObject Result
        +Example[] Examples
        +ErrorObject[] Errors
    }
    
    class Parameter {
        +string Name
        +string Description
        +bool Required
        +SchemaObject Schema
    }
    
    class ResultObject {
        +string Name
        +string Description
        +SchemaObject Schema
    }
    
    class SchemaObject {
        +string Type
        +map[string]interface{} Properties
        +SchemaObject Items
        +map[string]SchemaObject AdditionalProperties
    }
    
    class Example {
        +string Name
        +map[string]interface{}[] Params
        +ExampleResultObject Result
    }
    
    class ExampleResultObject {
        +string Name
        +interface{} Value
    }
    
    class ErrorObject {
        +int Code
        +string Message
        +string Data
    }
    
    OpenRPCSpec --> InfoObject
    OpenRPCSpec --> Server
    OpenRPCSpec --> Method
    Method --> Parameter
    Method --> ResultObject
    Method --> Example
    Method --> ErrorObject
    Parameter --> SchemaObject
    ResultObject --> SchemaObject
    Example --> ExampleResultObject

3.2 OpenRPC Manager (pkg/openrpc/manager.go)

The ORPCManager will be responsible for:

  • Loading OpenRPC specifications from JSON files
  • Storing and managing these specifications in memory
  • Providing methods to access and manipulate the specifications
classDiagram
    class ORPCManager {
        -map[string]*OpenRPCSpec specs
        +NewORPCManager() *ORPCManager
        +LoadSpecs(dir string) error
        +LoadSpec(path string) error
        +GetSpec(name string) *OpenRPCSpec
        +ListSpecs() []string
        +ListMethods(specName string) []string
        +GetMethod(specName string, methodName string) *Method
    }
    
    ORPCManager --> OpenRPCSpec

3.3 Test Command (cmd/orpctest/main.go)

We'll create a command-line tool to test the ORPCManager functionality:

  • Initialize the ORPCManager
  • Load specifications from the pkg/openrpc/services directory
  • List available specifications
  • List methods for each specification
  • Display details for specific methods

4. Implementation Steps

  1. Create the OpenRPC Specification Model:

    • Define the Go structs for the OpenRPC specification
    • Implement JSON marshaling/unmarshaling
    • Add validation functions
  2. Implement the ORPCManager:

    • Create the manager struct with a map to store specifications
    • Implement methods to load specifications from files
    • Implement methods to access and manipulate specifications
  3. Create the Test Command:

    • Implement a command-line interface to test the ORPCManager
    • Add options to list specifications, methods, and display details
  4. Write Tests:

    • Write unit tests for the OpenRPC model
    • Write unit tests for the ORPCManager
    • Write integration tests for the entire system

5. Detailed Method Specifications

5.1 ORPCManager Methods

NewORPCManager()

  • Creates a new instance of the ORPCManager
  • Initializes the specs map

LoadSpecs(dir string) error

  • Reads all JSON files in the specified directory
  • For each file, calls LoadSpec()
  • Returns an error if any file fails to load

LoadSpec(path string) error

  • Reads the JSON file at the specified path
  • Parses the JSON into an OpenRPCSpec struct
  • Validates the specification
  • Stores the specification in the specs map using the filename (without extension) as the key
  • Returns an error if any step fails

GetSpec(name string) *OpenRPCSpec

  • Returns the OpenRPCSpec with the specified name
  • Returns nil if the specification doesn't exist

ListSpecs() []string

  • Returns a list of all loaded specification names

ListMethods(specName string) []string

  • Returns a list of all method names in the specified specification
  • Returns an empty list if the specification doesn't exist

GetMethod(specName string, methodName string) *Method

  • Returns the Method with the specified name from the specified specification
  • Returns nil if the specification or method doesn't exist

6. Example Usage

// Initialize the ORPCManager
manager := openrpc.NewORPCManager()

// Load all specifications from the services directory
err := manager.LoadSpecs("pkg/openrpc/services")
if err != nil {
    log.Fatalf("Failed to load specifications: %v", err)
}

// List all loaded specifications
specs := manager.ListSpecs()
fmt.Println("Loaded specifications:")
for _, spec := range specs {
    fmt.Printf("- %s\n", spec)
}

// List all methods in the zinit specification
methods := manager.ListMethods("zinit")
fmt.Println("\nMethods in zinit specification:")
for _, method := range methods {
    fmt.Printf("- %s\n", method)
}

// Get details for a specific method
method := manager.GetMethod("zinit", "service_list")
if method != nil {
    fmt.Printf("\nDetails for method 'service_list':\n")
    fmt.Printf("Description: %s\n", method.Description)
    fmt.Printf("Parameters: %d\n", len(method.Params))
    fmt.Printf("Examples: %d\n", len(method.Examples))
}