feat: Add CORS support to HeroServer

- Add `cors_enabled` and `allowed_origins` fields to `ServerArgs`
- Add `cors_enabled` and `allowed_origins` to `HeroServerConfig`
- Configure VEB CORS middleware when `cors_enabled` is true
- Update `new` function to accept `cors_enabled` and `allowed_origins`
- Add `cors_enabled` and `allowed_origins` to `HeroServer` struct
This commit is contained in:
Mahmoud-Emad
2025-09-18 14:23:03 +03:00
parent e59ff8b63f
commit b83aa75e9d
5 changed files with 76 additions and 38 deletions

View File

@@ -7,9 +7,14 @@ import time
fn main() {
// Start the server in a background thread with authentication disabled for testing
spawn fn () {
rpc.start(port: 8080, auth_enabled: false) or {
panic('Failed to start HeroModels server: ${err}')
}
rpc.start(
port: 8080
auth_enabled: false // Disable auth for testing
cors_enabled: true
allowed_origins: [
'http://localhost:5173',
]
) or { panic('Failed to start HeroModels server: ${err}') }
}()
// Keep the main thread alive

View File

@@ -71,14 +71,22 @@ pub fn new_heromodels_handler() !&openrpc.Handler {
@[params]
pub struct ServerArgs {
pub mut:
port int = 8080
host string = 'localhost'
auth_enabled bool = true
port int = 8080
host string = 'localhost'
auth_enabled bool = true
cors_enabled bool = true
allowed_origins []string = ['*'] // Default allows all origins
}
pub fn start(args ServerArgs) ! {
// Create a new heroserver instance
mut server := heroserver.new(port: args.port, host: args.host, auth_enabled: args.auth_enabled)!
mut server := heroserver.new(
port: args.port
host: args.host
auth_enabled: args.auth_enabled
cors_enabled: args.cors_enabled
allowed_origins: args.allowed_origins
)!
// Create and register the heromodels handler
handler := new_heromodels_handler()!

View File

@@ -8,20 +8,22 @@ import veb
// Create a new HeroServer instance
pub fn new(config HeroServerConfig) !&HeroServer {
// Initialize crypto client
mut crypto_client := if c := config.crypto_client {
crypto_client := if c := config.crypto_client {
c
} else {
herocrypt.new_default()!
}
mut server := &HeroServer{
port: config.port
host: config.host
crypto_client: crypto_client
sessions: map[string]Session{}
handlers: map[string]&openrpc.Handler{}
challenges: map[string]AuthChallenge{}
auth_enabled: config.auth_enabled
port: config.port
host: config.host
crypto_client: crypto_client
sessions: map[string]Session{}
handlers: map[string]&openrpc.Handler{}
challenges: map[string]AuthChallenge{}
auth_enabled: config.auth_enabled
cors_enabled: config.cors_enabled
allowed_origins: config.allowed_origins.clone()
}
console.print_header('HeroServer created on port ${server.port}')
@@ -36,19 +38,25 @@ pub fn (mut server HeroServer) register_handler(handler_type string, handler &op
// Start the server
pub fn (mut server HeroServer) start() ! {
// Configure CORS if enabled
if server.cors_enabled {
console.print_item('CORS enabled for origins: ${server.allowed_origins}')
server.use(veb.cors[Context](veb.CorsOptions{
origins: server.allowed_origins
allowed_methods: [.get, .head, .patch, .put, .post, .delete, .options]
allowed_headers: ['Content-Type', 'Authorization', 'X-Requested-With']
allow_credentials: true
}))
}
// Start VEB server
handler_name := server.handlers.keys()[0]
console.print_green('Server starting on http://${server.host}:${server.port}')
console.print_green('HTML Homepage: http://${server.host}:${server.port}/')
console.print_green('JSON Info: http://${server.host}:${server.port}/json/${handler_name}')
console.print_green('Documentation: http://${server.host}:${server.port}/doc/${handler_name}')
console.print_green('Markdown Docs: http://${server.host}:${server.port}/md/${handler_name}')
console.print_green('API Endpoint: http://${server.host}:${server.port}/api/${handler_name}')
console.print_item('Server starting on http://${server.host}:${server.port}')
console.print_item('HTML Homepage: http://${server.host}:${server.port}/')
console.print_item('JSON Info: http://${server.host}:${server.port}/json/${handler_name}')
console.print_item('Documentation: http://${server.host}:${server.port}/doc/${handler_name}')
console.print_item('Markdown Docs: http://${server.host}:${server.port}/md/${handler_name}')
console.print_item('API Endpoint: http://${server.host}:${server.port}/api/${handler_name}')
veb.run[HeroServer, Context](mut server, server.port)
}
// Context struct for VEB
pub struct Context {
veb.Context
}

View File

@@ -3,6 +3,7 @@ module heroserver
import freeflowuniverse.herolib.crypt.herocrypt
import freeflowuniverse.herolib.schemas.openrpc
import time
import veb
// Main server configuration
@[params]
@@ -11,19 +12,25 @@ pub mut:
port int = 9977
host string = 'localhost'
auth_enabled bool = true // Whether to enable authentication
// CORS configuration
cors_enabled bool = true // Whether to enable CORS
allowed_origins []string = ['*'] // Allowed origins for CORS, default allows all
// Optional crypto client, will create default if not provided
crypto_client ?&herocrypt.HeroCrypt
}
// Main server struct
pub struct HeroServer {
veb.Middleware[Context]
mut:
port int
host string
crypto_client &herocrypt.HeroCrypt
sessions map[string]Session // sessionkey -> Session
handlers map[string]&openrpc.Handler // handlertype -> handler
challenges map[string]AuthChallenge
port int
host string
crypto_client &herocrypt.HeroCrypt
sessions map[string]Session // sessionkey -> Session
handlers map[string]&openrpc.Handler // handlertype -> handler
challenges map[string]AuthChallenge
cors_enabled bool
allowed_origins []string
pub mut:
auth_enabled bool = true // Whether authentication is required
}
@@ -157,3 +164,8 @@ pub:
body string
description string
}
// Context struct for VEB
pub struct Context {
veb.Context
}

View File

@@ -8,6 +8,7 @@ HeroServer is a secure web server built in V, designed for public key-based auth
- **OpenRPC Integration**: Serve APIs defined with the OpenRPC specification.
- **Automatic Documentation**: Generates HTML documentation from your OpenRPC schemas.
- **Session Management**: Manages authenticated user sessions.
- **CORS Support**: Configurable Cross-Origin Resource Sharing for frontend integration.
- **Extensible**: Register multiple, independent handlers for different API groups.
## Usage
@@ -17,17 +18,21 @@ import freeflowuniverse.herolib.hero.heroserver
import freeflowuniverse.herolib.schemas.openrpc
fn main() {
// 1. Create a new server instance
mut server := heroserver.new(port: 8080)!
// 1. Create a new server instance with CORS support
mut server := heroserver.new(
port: 8080
cors_enabled: true
allowed_origins: ['http://localhost:5173'] // Frontend dev server
)!
// 2. Create and register your OpenRPC handlers
// These handlers must conform to the `openrpc.OpenRPCHandler` interface.
calendar_handler := create_calendar_handler() // Your implementation
server.register_handler('calendar', calendar_handler)!
task_handler := create_task_handler() // Your implementation
task_handler := create_task_handler() // Your implementation
server.register_handler('tasks', task_handler)!
// 3. Start the server
server.start()! // This call blocks and starts serving requests
}