Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,120 @@
|
||||
module veb
|
||||
|
||||
import net.urllib
|
||||
|
||||
type ControllerHandler = fn (ctx &Context, mut url urllib.URL, host string) &Context
|
||||
|
||||
pub struct ControllerPath {
|
||||
pub:
|
||||
path string
|
||||
handler ControllerHandler = unsafe { nil }
|
||||
pub mut:
|
||||
host string
|
||||
}
|
||||
|
||||
interface ControllerInterface {
|
||||
controllers []&ControllerPath
|
||||
}
|
||||
|
||||
pub struct Controller {
|
||||
pub mut:
|
||||
controllers []&ControllerPath
|
||||
}
|
||||
|
||||
// register_controller adds a new Controller to your app
|
||||
pub fn (mut c Controller) register_controller[A, X](path string, mut global_app A) ! {
|
||||
c.controllers << controller[A, X](path, mut global_app)!
|
||||
}
|
||||
|
||||
// controller generates a new Controller for the main app
|
||||
pub fn controller[A, X](path string, mut global_app A) !&ControllerPath {
|
||||
routes := generate_routes[A, X](global_app) or { panic(err.msg()) }
|
||||
controllers_sorted := check_duplicate_routes_in_controllers[A](global_app, routes) or {
|
||||
panic(err.msg())
|
||||
}
|
||||
|
||||
// generate struct with closure so the generic type is encapsulated in the closure
|
||||
// no need to type `ControllerHandler` as generic since it's not needed for closures
|
||||
return &ControllerPath{
|
||||
path: path
|
||||
handler: fn [mut global_app, path, routes, controllers_sorted] [A, X](ctx &Context, mut url urllib.URL, host string) &Context {
|
||||
// transform the url
|
||||
url.path = url.path.all_after_first(path)
|
||||
if url.path != '' && !url.path.starts_with('/') {
|
||||
url.path = '/' + url.path
|
||||
}
|
||||
|
||||
// match controller paths
|
||||
$if A is ControllerInterface {
|
||||
if completed_context := handle_controllers[X](controllers_sorted, ctx, mut url,
|
||||
host)
|
||||
{
|
||||
return completed_context
|
||||
}
|
||||
}
|
||||
|
||||
// create a new user context and pass the veb's context
|
||||
mut user_context := X{}
|
||||
user_context.Context = ctx
|
||||
|
||||
handle_route[A, X](mut global_app, mut user_context, url, host, &routes)
|
||||
// Preserve the handled context on the heap before the stack-local user context goes away.
|
||||
unsafe {
|
||||
*ctx = user_context.Context
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register_controller adds a new Controller to your app
|
||||
pub fn (mut c Controller) register_host_controller[A, X](host string, path string, mut global_app A) ! {
|
||||
c.controllers << controller_host[A, X](host, path, mut global_app)!
|
||||
}
|
||||
|
||||
// controller_host generates a controller which only handles incoming requests from the `host` domain
|
||||
pub fn controller_host[A, X](host string, path string, mut global_app A) &ControllerPath {
|
||||
mut ctrl := controller[A, X](path, mut global_app)
|
||||
ctrl.host = host
|
||||
return ctrl
|
||||
}
|
||||
|
||||
fn check_duplicate_routes_in_controllers[T](global_app &T, routes map[string]Route) ![]&ControllerPath {
|
||||
mut controllers_sorted := []&ControllerPath{}
|
||||
$if T is ControllerInterface {
|
||||
mut paths := []string{}
|
||||
controllers_sorted = global_app.controllers.clone()
|
||||
controllers_sorted.sort(a.path.len > b.path.len)
|
||||
for controller in controllers_sorted {
|
||||
if controller.host == '' {
|
||||
if controller.path in paths {
|
||||
return error('conflicting paths: duplicate controller handling the route "${controller.path}"')
|
||||
}
|
||||
paths << controller.path
|
||||
}
|
||||
}
|
||||
for method_name, route in routes {
|
||||
for controller_path in paths {
|
||||
if route.path.starts_with(controller_path) {
|
||||
return error('conflicting paths: method "${method_name}" with route "${route.path}" should be handled by the Controller of path "${controller_path}"')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return controllers_sorted
|
||||
}
|
||||
|
||||
fn handle_controllers[X](controllers []&ControllerPath, ctx &Context, mut url urllib.URL, host string) ?&Context {
|
||||
for controller in controllers {
|
||||
// skip controller if the hosts don't match
|
||||
if controller.host != '' && host != controller.host {
|
||||
continue
|
||||
}
|
||||
if url.path.len >= controller.path.len && url.path.starts_with(controller.path) {
|
||||
// pass route handling to the controller
|
||||
return controller.handler(ctx, mut url, host)
|
||||
}
|
||||
}
|
||||
|
||||
return none
|
||||
}
|
||||
Reference in new issue
Block a user