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:
@@ -7,9 +7,14 @@ import time
|
|||||||
fn main() {
|
fn main() {
|
||||||
// Start the server in a background thread with authentication disabled for testing
|
// Start the server in a background thread with authentication disabled for testing
|
||||||
spawn fn () {
|
spawn fn () {
|
||||||
rpc.start(port: 8080, auth_enabled: false) or {
|
rpc.start(
|
||||||
panic('Failed to start HeroModels server: ${err}')
|
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
|
// Keep the main thread alive
|
||||||
|
|||||||
@@ -71,14 +71,22 @@ pub fn new_heromodels_handler() !&openrpc.Handler {
|
|||||||
@[params]
|
@[params]
|
||||||
pub struct ServerArgs {
|
pub struct ServerArgs {
|
||||||
pub mut:
|
pub mut:
|
||||||
port int = 8080
|
port int = 8080
|
||||||
host string = 'localhost'
|
host string = 'localhost'
|
||||||
auth_enabled bool = true
|
auth_enabled bool = true
|
||||||
|
cors_enabled bool = true
|
||||||
|
allowed_origins []string = ['*'] // Default allows all origins
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(args ServerArgs) ! {
|
pub fn start(args ServerArgs) ! {
|
||||||
// Create a new heroserver instance
|
// 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
|
// Create and register the heromodels handler
|
||||||
handler := new_heromodels_handler()!
|
handler := new_heromodels_handler()!
|
||||||
|
|||||||
@@ -8,20 +8,22 @@ import veb
|
|||||||
// Create a new HeroServer instance
|
// Create a new HeroServer instance
|
||||||
pub fn new(config HeroServerConfig) !&HeroServer {
|
pub fn new(config HeroServerConfig) !&HeroServer {
|
||||||
// Initialize crypto client
|
// Initialize crypto client
|
||||||
mut crypto_client := if c := config.crypto_client {
|
crypto_client := if c := config.crypto_client {
|
||||||
c
|
c
|
||||||
} else {
|
} else {
|
||||||
herocrypt.new_default()!
|
herocrypt.new_default()!
|
||||||
}
|
}
|
||||||
|
|
||||||
mut server := &HeroServer{
|
mut server := &HeroServer{
|
||||||
port: config.port
|
port: config.port
|
||||||
host: config.host
|
host: config.host
|
||||||
crypto_client: crypto_client
|
crypto_client: crypto_client
|
||||||
sessions: map[string]Session{}
|
sessions: map[string]Session{}
|
||||||
handlers: map[string]&openrpc.Handler{}
|
handlers: map[string]&openrpc.Handler{}
|
||||||
challenges: map[string]AuthChallenge{}
|
challenges: map[string]AuthChallenge{}
|
||||||
auth_enabled: config.auth_enabled
|
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}')
|
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
|
// Start the server
|
||||||
pub fn (mut server HeroServer) start() ! {
|
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
|
// Start VEB server
|
||||||
handler_name := server.handlers.keys()[0]
|
handler_name := server.handlers.keys()[0]
|
||||||
console.print_green('Server starting on http://${server.host}:${server.port}')
|
console.print_item('Server starting on http://${server.host}:${server.port}')
|
||||||
console.print_green('HTML Homepage: http://${server.host}:${server.port}/')
|
console.print_item('HTML Homepage: http://${server.host}:${server.port}/')
|
||||||
console.print_green('JSON Info: http://${server.host}:${server.port}/json/${handler_name}')
|
console.print_item('JSON Info: http://${server.host}:${server.port}/json/${handler_name}')
|
||||||
console.print_green('Documentation: http://${server.host}:${server.port}/doc/${handler_name}')
|
console.print_item('Documentation: http://${server.host}:${server.port}/doc/${handler_name}')
|
||||||
console.print_green('Markdown Docs: http://${server.host}:${server.port}/md/${handler_name}')
|
console.print_item('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('API Endpoint: http://${server.host}:${server.port}/api/${handler_name}')
|
||||||
|
|
||||||
veb.run[HeroServer, Context](mut server, server.port)
|
veb.run[HeroServer, Context](mut server, server.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context struct for VEB
|
|
||||||
pub struct Context {
|
|
||||||
veb.Context
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module heroserver
|
|||||||
import freeflowuniverse.herolib.crypt.herocrypt
|
import freeflowuniverse.herolib.crypt.herocrypt
|
||||||
import freeflowuniverse.herolib.schemas.openrpc
|
import freeflowuniverse.herolib.schemas.openrpc
|
||||||
import time
|
import time
|
||||||
|
import veb
|
||||||
|
|
||||||
// Main server configuration
|
// Main server configuration
|
||||||
@[params]
|
@[params]
|
||||||
@@ -11,19 +12,25 @@ pub mut:
|
|||||||
port int = 9977
|
port int = 9977
|
||||||
host string = 'localhost'
|
host string = 'localhost'
|
||||||
auth_enabled bool = true // Whether to enable authentication
|
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
|
// Optional crypto client, will create default if not provided
|
||||||
crypto_client ?&herocrypt.HeroCrypt
|
crypto_client ?&herocrypt.HeroCrypt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main server struct
|
// Main server struct
|
||||||
pub struct HeroServer {
|
pub struct HeroServer {
|
||||||
|
veb.Middleware[Context]
|
||||||
mut:
|
mut:
|
||||||
port int
|
port int
|
||||||
host string
|
host string
|
||||||
crypto_client &herocrypt.HeroCrypt
|
crypto_client &herocrypt.HeroCrypt
|
||||||
sessions map[string]Session // sessionkey -> Session
|
sessions map[string]Session // sessionkey -> Session
|
||||||
handlers map[string]&openrpc.Handler // handlertype -> handler
|
handlers map[string]&openrpc.Handler // handlertype -> handler
|
||||||
challenges map[string]AuthChallenge
|
challenges map[string]AuthChallenge
|
||||||
|
cors_enabled bool
|
||||||
|
allowed_origins []string
|
||||||
pub mut:
|
pub mut:
|
||||||
auth_enabled bool = true // Whether authentication is required
|
auth_enabled bool = true // Whether authentication is required
|
||||||
}
|
}
|
||||||
@@ -157,3 +164,8 @@ pub:
|
|||||||
body string
|
body string
|
||||||
description string
|
description string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Context struct for VEB
|
||||||
|
pub struct Context {
|
||||||
|
veb.Context
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
- **OpenRPC Integration**: Serve APIs defined with the OpenRPC specification.
|
||||||
- **Automatic Documentation**: Generates HTML documentation from your OpenRPC schemas.
|
- **Automatic Documentation**: Generates HTML documentation from your OpenRPC schemas.
|
||||||
- **Session Management**: Manages authenticated user sessions.
|
- **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.
|
- **Extensible**: Register multiple, independent handlers for different API groups.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -17,17 +18,21 @@ import freeflowuniverse.herolib.hero.heroserver
|
|||||||
import freeflowuniverse.herolib.schemas.openrpc
|
import freeflowuniverse.herolib.schemas.openrpc
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// 1. Create a new server instance
|
// 1. Create a new server instance with CORS support
|
||||||
mut server := heroserver.new(port: 8080)!
|
mut server := heroserver.new(
|
||||||
|
port: 8080
|
||||||
|
cors_enabled: true
|
||||||
|
allowed_origins: ['http://localhost:5173'] // Frontend dev server
|
||||||
|
)!
|
||||||
|
|
||||||
// 2. Create and register your OpenRPC handlers
|
// 2. Create and register your OpenRPC handlers
|
||||||
// These handlers must conform to the `openrpc.OpenRPCHandler` interface.
|
// These handlers must conform to the `openrpc.OpenRPCHandler` interface.
|
||||||
calendar_handler := create_calendar_handler() // Your implementation
|
calendar_handler := create_calendar_handler() // Your implementation
|
||||||
server.register_handler('calendar', calendar_handler)!
|
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)!
|
server.register_handler('tasks', task_handler)!
|
||||||
|
|
||||||
// 3. Start the server
|
// 3. Start the server
|
||||||
server.start()! // This call blocks and starts serving requests
|
server.start()! // This call blocks and starts serving requests
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user