minor warning and compilation bug fixes

This commit is contained in:
timurgordon
2025-01-07 00:41:30 -05:00
parent bc9fd08f7e
commit 7459501c8f
14 changed files with 11 additions and 246 deletions

View File

@@ -2,12 +2,9 @@ module generator
import freeflowuniverse.herolib.core.code { Param, Folder, IFile, VFile, CodeItem, File, Function, Import, Module, Struct, CustomCode } import freeflowuniverse.herolib.core.code { Param, Folder, IFile, VFile, CodeItem, File, Function, Import, Module, Struct, CustomCode }
import freeflowuniverse.herolib.core.texttools import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.schemas.openrpc
import freeflowuniverse.herolib.schemas.jsonschema.codegen as jsonschema_codegen {schemaref_to_type} import freeflowuniverse.herolib.schemas.jsonschema.codegen as jsonschema_codegen {schemaref_to_type}
import freeflowuniverse.herolib.schemas.openrpc.codegen {content_descriptor_to_parameter} import freeflowuniverse.herolib.schemas.openrpc.codegen {content_descriptor_to_parameter}
import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification} import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification}
import os
import json
pub fn generate_client_file(spec ActorSpecification) !VFile { pub fn generate_client_file(spec ActorSpecification) !VFile {
actor_name_snake := texttools.name_fix_snake(spec.name) actor_name_snake := texttools.name_fix_snake(spec.name)

View File

@@ -33,7 +33,6 @@ pub fn generate_cmd_function(spec ActorSpecification) string {
name: '${actor_name_snake}' name: '${actor_name_snake}'
usage: '' usage: ''
description: '${spec.description}' description: '${spec.description}'
execute: cmd_execute
} }
" "
@@ -72,7 +71,7 @@ pub fn generate_method_cmd_function(actor_name string, method ActorMethod) strin
'result := ${actor_name_snake}.${method_name_snake}()!' 'result := ${actor_name_snake}.${method_name_snake}()!'
} }
return ' return '
fn cmd_${method_name_snake}(cmd Command) ! { fn cmd_${method_name_snake}_execute(cmd Command) ! {
${method_call} ${method_call}
} }
' '

View File

@@ -2,11 +2,7 @@ module generator
import freeflowuniverse.herolib.core.code { Folder, IFile, VFile, CodeItem, File, Function, Param, Import, Module, Struct, CustomCode } import freeflowuniverse.herolib.core.code { Folder, IFile, VFile, CodeItem, File, Function, Param, Import, Module, Struct, CustomCode }
import freeflowuniverse.herolib.core.texttools import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.schemas.openrpc
import freeflowuniverse.herolib.schemas.openrpc.codegen {content_descriptor_to_parameter}
import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification} import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification}
import os
import json
pub fn generate_model_file(spec ActorSpecification) !VFile { pub fn generate_model_file(spec ActorSpecification) !VFile {
actor_name_snake := texttools.name_fix_snake(spec.name) actor_name_snake := texttools.name_fix_snake(spec.name)

View File

@@ -2,12 +2,8 @@ module generator
import json import json
import freeflowuniverse.herolib.core.code { VFile, File, Function, Module, Struct } import freeflowuniverse.herolib.core.code { VFile, File, Function, Module, Struct }
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.baobab.specification {ActorSpecification}
import freeflowuniverse.herolib.schemas.openrpc { Components, OpenRPC } import freeflowuniverse.herolib.schemas.openrpc { Components, OpenRPC }
import freeflowuniverse.herolib.schemas.openrpc.codegen { generate_client_file, generate_client_test_file } import freeflowuniverse.herolib.schemas.openrpc.codegen { generate_client_file, generate_client_test_file }
import freeflowuniverse.herolib.schemas.jsonschema { SchemaRef }
pub fn generate_openrpc_file(spec OpenRPC) !File { pub fn generate_openrpc_file(spec OpenRPC) !File {
return File { return File {

View File

@@ -4,9 +4,6 @@ import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.schemas.openapi import freeflowuniverse.herolib.schemas.openapi
const name = '@{actor_name_snake}' const name = '@{actor_name_snake}'
const openapi_spec_path = '@{dollar}{os.dir(@@FILE)}/specs/openapi.json'
const openapi_spec_json = os.read_file(openapi_spec_path) or { panic(err) }
const openapi_specification = openapi.json_decode(openapi_spec_json)!
@@[heap] @@[heap]
struct @{actor_name_pascal}Actor { struct @{actor_name_pascal}Actor {

View File

@@ -4,7 +4,6 @@ import freeflowuniverse.herolib.core.code { VFile, CustomCode, Function, Import,
import freeflowuniverse.herolib.baobab.specification {BaseObject} import freeflowuniverse.herolib.baobab.specification {BaseObject}
import rand import rand
import freeflowuniverse.herolib.core.texttools import freeflowuniverse.herolib.core.texttools
import os
// generate_object_methods generates CRUD actor methods for a provided structure // generate_object_methods generates CRUD actor methods for a provided structure
pub fn generate_object_test_code(actor Struct, object BaseObject) !VFile { pub fn generate_object_test_code(actor Struct, object BaseObject) !VFile {

View File

@@ -3,7 +3,6 @@ module specification
import freeflowuniverse.herolib.schemas.openrpc {OpenRPC, Components} import freeflowuniverse.herolib.schemas.openrpc {OpenRPC, Components}
import freeflowuniverse.herolib.schemas.jsonschema {SchemaRef} import freeflowuniverse.herolib.schemas.jsonschema {SchemaRef}
import freeflowuniverse.herolib.schemas.jsonschema.codegen { struct_to_schema } import freeflowuniverse.herolib.schemas.jsonschema.codegen { struct_to_schema }
import freeflowuniverse.herolib.schemas.openapi {OpenAPI}
// pub fn from_openrpc(spec openrpc.OpenRPC) !ActorSpecification { // pub fn from_openrpc(spec openrpc.OpenRPC) !ActorSpecification {
// // Extract Actor metadata from OpenRPC info // // Extract Actor metadata from OpenRPC info

View File

@@ -7,7 +7,7 @@ pub mut:
id string id string
name string name string
priority int = 10 // 0 is highest, do 10 as default priority int = 10 // 0 is highest, do 10 as default
params string params string // json encoded params
result string // can be used to remember outputs result string // can be used to remember outputs
// run bool = true // certain actions can be defined but meant to be executed directly // run bool = true // certain actions can be defined but meant to be executed directly
comments string comments string

View File

@@ -199,6 +199,6 @@ fn json_decode_content(content_ map[string]MediaType, content_map map[string]Any
// return arr // return arr
// } // }
fn (o OpenAPI) json_encode() string { pub fn (o OpenAPI) encode_json() string {
return json.encode(o).replace('ref', '\$ref') return json.encode(o).replace('ref', '\$ref')
} }

View File

@@ -1,214 +0,0 @@
module openapi
import veb
import freeflowuniverse.herolib.schemas.jsonschema {Schema}
import x.json2 {Any}
import net.http
pub struct Controller {
pub:
specification OpenAPI
pub mut:
handler IHandler
}
pub struct Context {
veb.Context
}
// Matches a request path against OpenAPI path templates in the parsed structs
// Returns the matching path key and corresponding PathItem if found
fn match_path(req_path string, spec OpenAPI) !PathItem {
// Iterate through all paths in the OpenAPI specification
for template, path_item in spec.paths {
if is_path_match(req_path, template) {
// Return the matching path template and its PathItem
return path_item
}
}
// If no match is found, return an error
return error('Path not found')
}
// Checks if a request path matches a given OpenAPI path template
// Allows for dynamic path segments like `{petId}` in templates
fn is_path_match(req_path string, template string) bool {
// Split the request path and template into segments
req_segments := req_path.split('/')
template_segments := template.split('/')
// If the number of segments doesn't match, the paths can't match
if req_segments.len != template_segments.len {
return false
}
// Compare each segment in the template and request path
for i, segment in template_segments {
// If the segment is not dynamic (doesn't start with `{`), ensure it matches exactly
if !segment.starts_with('{') && segment != req_segments[i] {
return false
}
}
// If all segments match or dynamic segments are valid, return true
return true
}
@['/:path...'; get; post; put; delete; patch]
pub fn (mut server Controller) index(mut ctx Context, path string) veb.Result {
println('Requested path: $path')
// Extract the HTTP method
method := ctx.req.method.str().to_lower()
// Matches the request path against the OpenAPI specification and retrieves the corresponding PathItem
path_item := match_path(path, server.specification) or {
// Return a 404 error if no matching path is found
return ctx.not_found()
}
// // Check if the path exists in the OpenAPI specification
// path_item := server.specification.paths[path] or {
// // Return a 404 error if the path is not defined
// return ctx.not_found()
// }
// Match the HTTP method with the OpenAPI specification
operation := match method {
'get' { path_item.get }
'post' { path_item.post }
'put' { path_item.put }
'delete' { path_item.delete }
'patch' { path_item.patch }
else {
// Return 405 Method Not Allowed if the method is not supported
return ctx.method_not_allowed()
}
}
mut arg_map := map[string]Any
path_arg := path.all_after_last('/')
// the OpenAPI Parameter specification belonging to the path argument
arg_params := operation.parameters.filter(it.in_ == 'path')
if arg_params.len > 1 {
// TODO: use path template to support multiple arguments (right now just last arg supported)
panic('implement')
} else if arg_params.len == 1 {
arg_map[arg_params[0].name] = arg_params[0].typed(path_arg)
}
mut parameters := ctx.query.clone()
// Build the Request object
request := Request{
path: path
operation: operation
method: method
arguments: arg_map
parameters: parameters
body: ctx.req.data
header: ctx.req.header
}
// Use the handler to process the request
response := server.handler.handle(request) or {
// Use OpenAPI spec to determine the response status for the error
return ctx.handle_error(operation.responses, err)
}
// Return the response to the client
ctx.res.set_status(response.status)
// ctx.res.header = response.header
// ctx.set_content_type('application/json')
// return ctx.ok('[]')
return ctx.send_response_to_client('application/json', response.body)
}
// Handles errors and maps them to OpenAPI-defined response statuses
fn (mut ctx Context) handle_error(possible_responses map[string]ResponseSpec, err IError) veb.Result {
// Match the error with the defined responses
for code, _ in possible_responses {
if matches_error_to_status(err, code.int()) {
ctx.res.set_status(http.status_from_int(code.int()))
ctx.set_content_type('application/json')
return ctx.send_response_to_client(
'application/json',
'{"error": "$err.msg()", "status": $code}'
)
}
}
// Default to 500 Internal Controller Error if no match is found
ctx.res.set_status(.internal_server_error)
ctx.set_content_type('application/json')
return ctx.send_response_to_client(
'application/json',
'{"error": "Internal Controller Error", "status": 500}'
)
}
// Helper to match an error to a specific response status
fn matches_error_to_status(err IError, status int) bool {
// This can be customized to map specific errors to statuses
// For simplicity, we'll use a direct comparison here.
return err.code() == status
}
// Helper for 405 Method Not Allowed response
fn (mut ctx Context) method_not_allowed() veb.Result {
ctx.res.set_status(.method_not_allowed)
ctx.set_content_type('application/json')
return ctx.send_response_to_client(
'application/json',
'{"error": "Method Not Allowed", "status": 405}'
)
}
pub fn (param Parameter) typed(value string) Any {
param_schema := param.schema as Schema
param_type := param_schema.typ
param_format := param_schema.format
// Convert parameter value to corresponding type
typ := match param_type {
'integer' {
param_format
}
'number' {
param_format
}
else {
param_type // Leave as param type for unknown types
}
}
return typed(value, typ)
}
// typed gets a value that is string and a desired type, and returns the typed string in Any Type.
pub fn typed(value string, typ string) Any {
match typ {
'int32' {
return value.int() // Convert to int
}
'int64' {
return value.i64() // Convert to i64
}
'string' {
return value // Already a string
}
'boolean' {
return value.bool() // Convert to bool
}
'float' {
return value.f32() // Convert to float
}
'double' {
return value.f64() // Convert to double
}
else {
return value.f64() // Leave as string for unknown types
}
}
}

View File

@@ -16,12 +16,12 @@ import freeflowuniverse.herolib.schemas.openrpc {OpenRPC}
pub fn generate_module(o OpenRPC, receiver Struct, methods_map map[string]Function, objects_map map[string]Struct) !Module { pub fn generate_module(o OpenRPC, receiver Struct, methods_map map[string]Function, objects_map map[string]Struct) !Module {
openrpc_json := o.encode()! // openrpc_json := o.encode()!
openrpc_file := File{ // openrpc_file := File{
name: 'openrpc' // name: 'openrpc'
extension: 'json' // extension: 'json'
content: openrpc_json // content: openrpc_json
} // }
client_file := generate_client_file(o, objects_map)! client_file := generate_client_file(o, objects_map)!
client_test_file := generate_client_test_file(o, methods_map, objects_map)! client_test_file := generate_client_test_file(o, methods_map, objects_map)!

View File

@@ -39,12 +39,12 @@ pub fn (mut c HTTPController) run(params RunParams) {
pub fn (mut c HTTPController) index(mut ctx Context) veb.Result { pub fn (mut c HTTPController) index(mut ctx Context) veb.Result {
// Decode JSONRPC Request from POST data // Decode JSONRPC Request from POST data
request := jsonrpc.decode_request(ctx.req.data) or { request := jsonrpc.decode_request(ctx.req.data) or {
return ctx.server_error('Failed to decode JSONRPC Request ${err.msg}') return ctx.server_error('Failed to decode JSONRPC Request ${err.msg()}')
} }
// Process the JSONRPC request with the OpenRPC handler // Process the JSONRPC request with the OpenRPC handler
response := c.handler.handle(request) or { response := c.handler.handle(request) or {
return ctx.server_error('Handler error: ${err.msg}') return ctx.server_error('Handler error: ${err.msg()}')
} }
// Encode and return the handler's JSONRPC Response // Encode and return the handler's JSONRPC Response

View File

@@ -1,8 +1,5 @@
module openrpc module openrpc
import veb
import freeflowuniverse.herolib.schemas.jsonrpc
// Main controller for handling RPC requests // Main controller for handling RPC requests
pub struct WebSocketController { pub struct WebSocketController {
pub mut: pub mut:

View File

@@ -1,6 +1,5 @@
module openrpc module openrpc
import x.json2
import freeflowuniverse.herolib.schemas.jsonrpc import freeflowuniverse.herolib.schemas.jsonrpc
pub struct Handler { pub struct Handler {