mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
veb: implicit context
This commit is contained in:
parent
cc7665ff32
commit
26ab7d4fe1
13 changed files with 65 additions and 86 deletions
|
@ -24,9 +24,8 @@ pub struct App {
|
|||
// time is a simple POST request handler, that returns the current time. It should be available
|
||||
// to JS scripts, running on arbitrary other origins/domains.
|
||||
|
||||
// pub fn (app &App) time() veb.Result {
|
||||
@[post]
|
||||
pub fn (app &App) time(mut ctx Context) veb.Result {
|
||||
pub fn (app &App) time() veb.Result {
|
||||
return ctx.json({
|
||||
'time': time.now().format_ss_milli()
|
||||
})
|
||||
|
@ -34,7 +33,7 @@ pub fn (app &App) time(mut ctx Context) veb.Result {
|
|||
|
||||
fn main() {
|
||||
println("
|
||||
To test, if CORS works, copy this JS snippet, then go to for example https://stackoverflow.com/ ,
|
||||
To test if CORS works, copy this JS snippet, then go to for example https://stackoverflow.com/ ,
|
||||
press F12, then paste the snippet in the opened JS console. You should see the veb server's time:
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onload = function(data) {
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn (mut app App) user_endpoint(mut ctx Context, user string) veb.Result {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn (mut app App) index(mut ctx Context) veb.Result {
|
||||
pub fn (mut app App) index() veb.Result {
|
||||
mut c := 0
|
||||
lock app.state {
|
||||
app.state.cnt++
|
|
@ -1,70 +0,0 @@
|
|||
module main
|
||||
|
||||
import vweb
|
||||
import rand
|
||||
|
||||
const port = 8082
|
||||
|
||||
struct State {
|
||||
mut:
|
||||
cnt int
|
||||
}
|
||||
|
||||
struct App {
|
||||
vweb.Context
|
||||
mut:
|
||||
state shared State
|
||||
}
|
||||
|
||||
pub fn (app &App) before_request() {
|
||||
$if trace_before_request ? {
|
||||
eprintln('[vweb] before_request: ${app.req.method} ${app.req.url}')
|
||||
}
|
||||
}
|
||||
|
||||
@['/users/:user']
|
||||
pub fn (mut app App) user_endpoint(user string) vweb.Result {
|
||||
id := rand.intn(100) or { 0 }
|
||||
return app.json({
|
||||
user: id
|
||||
})
|
||||
}
|
||||
|
||||
pub fn (mut app App) index() vweb.Result {
|
||||
mut c := 0
|
||||
lock app.state {
|
||||
app.state.cnt++
|
||||
c = app.state.cnt
|
||||
//
|
||||
$if trace_address_of_app_state_cnt ? {
|
||||
dump(ptr_str(app.state.cnt))
|
||||
}
|
||||
}
|
||||
show := true
|
||||
hello := 'Hello world from vweb, request number: ${c}'
|
||||
numbers := [1, 2, 3]
|
||||
return $vweb.html()
|
||||
}
|
||||
|
||||
pub fn (mut app App) custom_template() vweb.Result {
|
||||
return $vweb.html('custom.html')
|
||||
}
|
||||
|
||||
pub fn (mut app App) show_text() vweb.Result {
|
||||
return app.text('Hello world from vweb')
|
||||
}
|
||||
|
||||
pub fn (mut app App) cookie() vweb.Result {
|
||||
app.set_cookie(name: 'cookie', value: 'test')
|
||||
return app.text('Response Headers\n${app.header}')
|
||||
}
|
||||
|
||||
@[post]
|
||||
pub fn (mut app App) post() vweb.Result {
|
||||
return app.text('Post body: ${app.req.data}')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println('vweb example')
|
||||
vweb.run(&App{}, port)
|
||||
}
|
|
@ -30,7 +30,9 @@ pub mut:
|
|||
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
used_globals map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
used_vweb_types []Type // vweb context types, filled in by checker, when pref.skip_unused = true;
|
||||
used_veb_types []Type // veb context types, filled in by checker, when pref.skip_unused = true;
|
||||
veb_res_idx_cache int // Cache of `veb.Result` type
|
||||
veb_ctx_idx_cache int // Cache of `veb.Context` type
|
||||
used_maps int // how many times maps were used, filled in by checker, when pref.skip_unused = true;
|
||||
panic_handler FnPanicHandler = default_table_panic_handler
|
||||
panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler;
|
||||
|
@ -72,7 +74,7 @@ pub fn (mut t Table) free() {
|
|||
t.used_fns.free()
|
||||
t.used_consts.free()
|
||||
t.used_globals.free()
|
||||
t.used_vweb_types.free()
|
||||
t.used_veb_types.free()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,6 +235,16 @@ pub fn (mut t TypeSymbol) register_method(new_fn Fn) int {
|
|||
return t.methods.len - 1
|
||||
}
|
||||
|
||||
pub fn (mut t TypeSymbol) update_method(f Fn) int {
|
||||
for i, m in t.methods {
|
||||
if m.name == f.name {
|
||||
t.methods[i] = f
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
pub fn (t &Table) register_aggregate_method(mut sym TypeSymbol, name string) !Fn {
|
||||
if sym.kind != .aggregate {
|
||||
t.panic('table.register_aggregate_method: sym.name: ${sym.name}, sym.kind: ${sym.kind} is not an aggregate, name: ${name}')
|
||||
|
@ -2550,3 +2562,12 @@ pub fn (t &Table) get_attrs(sym TypeSymbol) []Attr {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut t Table) get_veb_result_type_idx() int {
|
||||
if t.veb_res_idx_cache > 0 {
|
||||
return t.veb_res_idx_cache
|
||||
}
|
||||
|
||||
t.veb_res_idx_cache = t.find_type_idx('veb.Result')
|
||||
return t.veb_res_idx_cache
|
||||
}
|
||||
|
|
|
@ -616,7 +616,7 @@ fn (mut c Checker) verify_all_vweb_routes() {
|
|||
if c.vweb_gen_types.len == 0 {
|
||||
return
|
||||
}
|
||||
c.table.used_vweb_types = c.vweb_gen_types
|
||||
c.table.used_veb_types = c.vweb_gen_types
|
||||
typ_vweb_result := c.table.find_type_idx('vweb.Result')
|
||||
old_file := c.file
|
||||
for vgt in c.vweb_gen_types {
|
||||
|
|
|
@ -434,11 +434,11 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||
}
|
||||
c.fn_scope = node.scope
|
||||
// Register implicit context var
|
||||
typ_veb_result := c.table.find_type_idx('veb.Result')
|
||||
typ_veb_result := c.table.get_veb_result_type_idx() // c.table.find_type_idx('veb.Result')
|
||||
if node.return_type == typ_veb_result {
|
||||
typ_veb_context := c.table.find_type_idx('veb.Context')
|
||||
typ_veb_context := ast.Type(u32(c.table.find_type_idx('veb.Context'))).set_nr_muls(1)
|
||||
// No `ctx` param? Add it
|
||||
if !node.params.any(it.name == 'ctx') && node.params.len > 1 {
|
||||
if !node.params.any(it.name == 'ctx') && node.params.len >= 1 {
|
||||
params := node.params.clone()
|
||||
ctx_param := ast.Param{
|
||||
name: 'ctx'
|
||||
|
@ -449,11 +449,19 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||
node.params << params[1..]
|
||||
// println('new params ${node.name}')
|
||||
// println(node.params)
|
||||
// We've added ctx to the FnDecl node.
|
||||
// Now update the existing method, already registered in Table.
|
||||
mut rec_sym := c.table.sym(node.receiver.typ)
|
||||
if mut m := c.table.find_method(rec_sym, node.name) {
|
||||
m.params << ctx_param
|
||||
rec_sym.update_method(m)
|
||||
}
|
||||
}
|
||||
// sym := c.table.sym(typ_veb_context)
|
||||
// println('reging ${typ_veb_context} ${sym}')
|
||||
// println(c.fn_scope)
|
||||
// println(node.params)
|
||||
// Finally add ctx to the scope
|
||||
c.fn_scope.register(ast.Var{
|
||||
name: 'ctx'
|
||||
typ: typ_veb_context
|
||||
|
|
|
@ -169,10 +169,27 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
|
|||
if !has_decompose {
|
||||
// do not generate anything if the argument lengths don't match
|
||||
g.writeln('/* skipping ${sym.name}.${m.name} due to mismatched arguments list: node.args=${node.args.len} m.params=${m.params.len} */')
|
||||
// g.writeln('println(_SLIT("skipping ${node.sym.name}.$m.name due to mismatched arguments list"));')
|
||||
// eprintln('info: skipping ${node.sym.name}.$m.name due to mismatched arguments list\n' +
|
||||
//'method.params: $m.params, args: $node.args\n\n')
|
||||
// verror('expected ${m.params.len - 1} arguments to method ${node.sym.name}.${m.name}, but got ${node.args.len}')
|
||||
// Adding a println(_SLIT(...)) like this breaks options
|
||||
/*
|
||||
g.writeln(
|
||||
'println(_SLIT("comptime: ${sym.name}.${m.name} has a mismatched arguments list.' +
|
||||
' The method has ${m.params.len - 1} parameters, but ${node.args.len} arguments were ' +
|
||||
'provided. \\nargs: ${node.args}\\n${g.file.path}:${node.pos.line_nr}"));')
|
||||
*/
|
||||
/*
|
||||
if true {
|
||||
println(node.args)
|
||||
verror('comptime: ${sym.name}.${m.name} has a mismatched arguments list.' +
|
||||
' The method has ${m.params.len - 1} parameters, but ${node.args.len} arguments were ' +
|
||||
'provided. ${g.file.path}:${node.pos.line_nr}\n')
|
||||
}
|
||||
if true {
|
||||
eprintln(
|
||||
'comptime: skipping ${sym.name}.${m.name} due to mismatched arguments list\n' +
|
||||
'method.params: ${m.params}, args: ${node.args}\n\n')
|
||||
// verror('expected ${m.params.len - 1} arguments to method ${node.sym.name}.${m.name}, but got ${node.args.len}')
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -449,7 +449,7 @@ fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name
|
|||
all_fn_root_names << filter_name
|
||||
typ_vweb_context := ast.idx_to_type(table.find_type_idx(context_name)).set_nr_muls(1)
|
||||
all_fn_root_names << '${int(typ_vweb_context)}.html'
|
||||
for vgt in table.used_vweb_types {
|
||||
for vgt in table.used_veb_types {
|
||||
sym_app := table.sym(vgt)
|
||||
for m in sym_app.methods {
|
||||
mut skip := true
|
||||
|
|
|
@ -223,6 +223,8 @@ fn ev_callback[A, X](mut pv picoev.Picoev, fd int, events int) {
|
|||
$if trace_picoev_callback ? {
|
||||
eprintln('> read event on file descriptor ${fd}')
|
||||
}
|
||||
// TODO figure out the POST repeat in ev_callback
|
||||
// println('ev_callback fd=${fd} params.routes=${params.routes.len}')
|
||||
handle_read[A, X](mut pv, mut params, fd)
|
||||
} else {
|
||||
// should never happen
|
||||
|
@ -323,7 +325,7 @@ fn handle_write_string(mut pv picoev.Picoev, mut params RequestParams, fd int) {
|
|||
|
||||
// handle_read reads data from the connection and if the request is complete
|
||||
// it calls `handle_route` and closes the connection.
|
||||
// If the request is not complete it stores the incomplete request in `params`
|
||||
// If the request is not complete, it stores the incomplete request in `params`
|
||||
// and the connection stays open until it is ready to read again
|
||||
@[direct_array_access; manualfree]
|
||||
fn handle_read[A, X](mut pv picoev.Picoev, mut params RequestParams, fd int) {
|
||||
|
@ -592,6 +594,7 @@ fn handle_request[A, X](mut conn net.TcpConn, req http.Request, params &RequestP
|
|||
}
|
||||
|
||||
fn handle_route[A, X](mut app A, mut user_context X, url urllib.URL, host string, routes &map[string]Route) {
|
||||
// println('\n\nHANDLE ROUTE')
|
||||
mut route := Route{}
|
||||
mut middleware_has_sent_response := false
|
||||
mut not_found := false
|
||||
|
@ -771,6 +774,7 @@ fn handle_route[A, X](mut app A, mut user_context X, url urllib.URL, host string
|
|||
}
|
||||
|
||||
fn route_matches(url_words []string, route_words []string) ?[]string {
|
||||
// println('route_matches(url_words:${url_words} route_words:${route_words}')
|
||||
// URL path should be at least as long as the route path
|
||||
// except for the catchall route (`/:path...`)
|
||||
if route_words.len == 1 && route_words[0].starts_with(':') && route_words[0].ends_with('...') {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue