refactor: Simplify handler signatures and add server runner

- Pass URL params as direct arguments to handlers
- Use `ctx.get_custom_header` to retrieve session key
- Add a runnable script to start the heroserver
- Clean up formatting in documentation and code
- Remove unused redisclient import
This commit is contained in:
Mahmoud-Emad
2025-09-14 18:24:30 +03:00
parent 92c8a3b955
commit ad906b5894
5 changed files with 30 additions and 37 deletions

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.hero.heroserver
mut server := heroserver.new_server(port: 8080)!
server.start()!

View File

@@ -1,6 +1,5 @@
module crypt
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.data.resp
// Stateless AGE operations

View File

@@ -6,29 +6,27 @@ and the implementation of the example of how webserver is see lib/schemas/openrp
specs for the heroserver
- a factory (without globals) creates a server, based on chosen port
- the server does basic authentication and has
- register method: pubkey
- authreq: pubkey, it returns a unique key (hashed md5 of pubkey + something random). (is a request for authentication)
- auth: the user who wants access signs the unique key from authreq with , and sends the signature to the server, who then knows for sure I know this user, we return as sessionkey
- the server does basic authentication and has
- register method: pubkey
- authreq: pubkey, it returns a unique key (hashed md5 of pubkey + something random). (is a request for authentication)
- auth: the user who wants access signs the unique key from authreq with , and sends the signature to the server, who then knows for sure I know this user, we return as sessionkey
- all consequent requests need to use this sessionkey, so the server knows who is doing the requests
- the server serves the openrpc api behind api/$handlertype/... the $handlertype is per handler type, so we can register more than 1 openrpc hander
- the server serves an html endpoint for doc/$handlertype/
for the doc (html endpoint)
- use bootstrap from cdn
- https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css
- https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js
- https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js
- <https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css>
- <https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js>
- <https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js>
- create an html template in lib/hero/heroserver/template/doc.md (template for v language)
- the template uses the openrpc spec obj comes from lib/schemas/openrpc and lib/schemas/jsonrpc for the schema's
- so first fo the spec decode to the object from schemas/openrpc then use this obj to populate the template
- in the template make a header 1 for each rootobject e.g. calendar, then dense show the methods with directly in the method a dense representation of the params and return
- each object e.g. pub fn (self Comment) description(methodname string) string { has a description and pub fn (self Comment) example(methodname string) (string, string) wich returns description per method, if not filled in then its for the full rootobject, and also example, make sure to use those in the template for the documentation
- the template is markdown, we will have to use a .md to .html conversion (best to do in browser itself) and get .md from the webserver directly and convert
- the purpose is to have a very nice documentation done per object so we know what the object does, and how to use it
- the template uses the openrpc spec obj comes from lib/schemas/openrpc and lib/schemas/jsonrpc for the schema's
- so first fo the spec decode to the object from schemas/openrpc then use this obj to populate the template
- in the template make a header 1 for each rootobject e.g. calendar, then dense show the methods with directly in the method a dense representation of the params and return
- each object e.g. pub fn (self Comment) description(methodname string) string { has a description and pub fn (self Comment) example(methodname string) (string, string) wich returns description per method, if not filled in then its for the full rootobject, and also example, make sure to use those in the template for the documentation
- the template is markdown, we will have to use a .md to .html conversion (best to do in browser itself) and get .md from the webserver directly and convert
- the purpose is to have a very nice documentation done per object so we know what the object does, and how to use it
make clear instructions what code needs to be written and which steps are needed
we are in architecture mode

View File

@@ -1,19 +1,17 @@
module heroserver
@[params]
pub struct ServerConfig {
pub:
port int = 8080
host string = 'localhost'
port int = 8080
host string = 'localhost'
}
// Factory function to create new server instance
pub fn new_server(config ServerConfig) !&HeroServer {
mut server := &HeroServer{
config: config
auth_manager: new_auth_manager()
handler_registry: new_handler_registry()
}
return server
}
return &HeroServer{
config: config
auth_manager: new_auth_manager()
handler_registry: new_handler_registry()
}
}

View File

@@ -40,13 +40,9 @@ pub fn (mut s HeroServer) auth(mut ctx Context) veb.Result {
// API endpoints
@['/api/:handler_type'; post]
pub fn (mut s HeroServer) api(mut ctx Context) veb.Result {
handler_type := ctx.params['handler_type'] or {
return ctx.request_error('handler_type not found in params')
}
pub fn (mut s HeroServer) api(mut ctx Context, handler_type string) veb.Result {
// Validate session
session_key := ctx.req.header.get('Authorization') or { '' }
session_key := ctx.get_custom_header('Authorization') or { '' }
if !s.auth_manager.validate_session(session_key) {
return ctx.request_error('Invalid session')
}
@@ -65,11 +61,7 @@ pub fn (mut s HeroServer) api(mut ctx Context) veb.Result {
// Documentation endpoints
@['/doc/:handler_type'; get]
pub fn (mut s HeroServer) doc(mut ctx Context) veb.Result {
handler_type := ctx.params['handler_type'] or {
return ctx.request_error('handler_type not found in params')
}
pub fn (mut s HeroServer) doc(mut ctx Context, handler_type string) veb.Result {
handler := s.handler_registry.get(handler_type) or { return ctx.not_found() }
doc_html := s.generate_documentation(handler_type, handler) or {