-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
vweb2 #19997
vweb2 #19997
Conversation
Great!!! One question. How will a Middleware work with redirect now? |
The same as before, the only difference is when the redirect occurs: before the request is processed or after. Example: module main
import x.vweb
pub struct Context {
vweb.Context
}
pub struct App {
vweb.Middleware[Context]
}
@['/to-redirect']
pub fn (app &App) to_redirect(mut ctx Context) vweb.Result {
println('from redirect')
return ctx.text('from redirect')
}
pub fn (app &App) other(mut ctx Context) vweb.Result {
return ctx.text('from other')
}
fn redirect(mut ctx Context) bool {
ctx.redirect('/other')
// return false to indicate we sent another response
return false
}
fn main() {
mut app := &App{}
app.Middleware.route_use('/to-redirect', handler: redirect, after: true)
vweb.run[App, Context](mut app, 8080)
} This code will print "from redirect", but in the browser you will see the text "from other". If The response is not sent directly when you call |
Will add the other TODO鈥檚 in separate pull requests. This one is already quite big |
Co-authored-by: JalonSolov <JalonSolov@gmail.com>
Hi, @Casper64. Will something like this works in vweb2? Note that sse function cannot have a return. module main
import vweb
import vweb.sse
import rand
struct App {
vweb.Context
mut:
sse_connections shared []sse.SSEConnection
}
pub fn (mut app App) before_request() {
app.add_header('Access-Control-Allow-Origin', '*')
}
@['/sse'; get]
fn (mut app App) sse() {
println('sse')
mut conn := sse.new_connection(app.conn)
conn.headers['Access-Control-Allow-Origin'] = '*'
conn.start() or {
println('err: ${err}')
// return app.server_error(501) // REVIEW
}
lock app.sse_connections {
app.sse_connections << conn
}
// for {
// }
}
// This not work (there are not connection)
@['/notification'; post]
fn (mut app App) notification() vweb.Result {
lock app.sse_connections {
for mut conn in app.sse_connections {
conn.send_message(sse.SSEMessage{
id: rand.uuid_v4()
event: 'statusUpdate'
data: app.req.data
retry: 3000
}) or { eprintln(err) }
conn.send_message(sse.SSEMessage{
id: rand.uuid_v4()
event: 'ping'
data: app.req.data
retry: 3000
}) or { eprintln(err) }
}
}
return app.text('Notification received')
}
fn main() {
shared sse_connections := []sse.SSEConnection{}
vweb.run(&App{
sse_connections: sse_connections
}, 3001)
} |
@enghitalo yes!
And the advanced usage section of the readme for an example. Or in your case you can change the @['/sse'; get]
fn (mut app App) sse(mut ctx Context) vweb.Result {
println('sse')
mut conn := sse.new_connection(app.conn)
conn.headers['Access-Control-Allow-Origin'] = '*'
conn.start() or {
println('err: ${err}')
// return app.server_error(501) // REVIEW
}
lock app.sse_connections {
app.sse_connections << conn
}
return ctx.takeover_conn()
} |
'vlib/vweb/x/tests/vweb_test.v', | ||
'vlib/vweb/x/tests/vweb_app_test.v', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'vlib/vweb/x/tests/vweb_test.v', | |
'vlib/vweb/x/tests/vweb_app_test.v', | |
'vlib/x/vweb/tests/vweb_test.v', | |
'vlib/x/vweb/tests/vweb_app_test.v', |
This pr adds a new version of vweb in
x.vweb
.Documentation and the intergration of the other vweb modules are coming later.
Breaking changes
x.vweb
raw_callback
mode. Requires adding 1 extra parameter.Biggest changes
picoev
module. This makes vweb2 single threaded and non-blocking instead of multithreaded and blocking.vweb.Context
.vweb.StaticHandler
App & Context
Splitting the App from the request context has the advantage that the attribute
@[vweb_global]
is no longer required! This is because not a newApp
struct is created for each request, but only theContext
struct.You can use the
App
struct for state that you want to share amongst routes and theContext
struct for state that you want to keep request specific.before:
after:
You can also see that we need to pass the type of the App struct and our Context struct to
vweb.run
and we have to make our appmut
. This also applies for Controllers.Middleware
The middleware is changed to make it more powerful and similair to other big web frameworks:
use
functionAdd the
Middleware
struct to youApp
struct and specify the type of the Context struct:Static files
The methods for adding and handling static files are the same, but they are moved from
vweb.Context
tovweb.StaticHandler
.Pros & cons of a single threaded design
pros:
mut
fields on theApp
struct without having to worry about race conditions instead of having to useshared
, assuming you won't use that field in another thread.cons:
App
struct or on theContext
struct is executed the rest of the code will block until those functions are done. For example when a method needs to fetch data from an external source and that request takes 1 second all vweb will essentially wait for your work to be done. This could be mittigated by making the request in a seperate thread. (SeeContext.takeover_conn()
)Benchmarks
These benchmarks are only to provide an insight on the difference in performance, please don't extract too much meaning from the numbers.
All apps are tested in
-prod
mode on the apps showed in the example from " App & Context".old: 24 threads:
new:
Keep in mind that for a multithreaded application this is the worst-case scenario in terms of load and for the single threaded version the best-case scenario.
Sending bigger responses
Every request returns a 4328KB file. It is clear that this new structure can handle bigger responses in an efficient manner.
TODO
馃[deprecated] Generated by Copilot at 28eb046
This pull request adds several new features and improvements to the
vweb
module, such as nested and host-specific controllers, middleware functions and options, static file handling, large payload handling, and more parsing and routing functions. It also refactors thevweb
module by separating some structs and functions into different files and adds more test functions and test data to increase the test coverage of the module.馃[deprecated] Generated by Copilot at 28eb046
vweb
module by separating theContext
,Controller
,Middleware
,StaticHandler
, and parsing functions into their own files (vlib/x/vweb/context.v
,vlib/x/vweb/controller.v
,vlib/x/vweb/middleware.v
,vlib/x/vweb/static_handler.v
, andvlib/x/vweb/parse.v
) (link, link, link, link, link)vweb
module by allowing nested controllers and host-specific controllers, and provide methods for registering and generating controllers (link)vweb
module by allowing middleware functions and options, and provide methods for adding global or route-specific middleware (link)total_read
to theBufferedReader
struct to keep track of the total number of bytes read from the underlying reader, and increment it in theread
andread_byte
methods (link, link, link)events
to theraw_cb
fields of thePicoev
andPicoevConfig
structs, and pass it to the raw callback function in thehandle_read
andhandle_write
methods (link, link, link, link)Picoev.del
method public and accessible from other modules (link)vlib/picoev/picoev.v
file for readability (link)./examples/pico/raw_callback.v
file for readability (link)events
to thehandle_conn
function in./examples/pico/raw_callback.v
(link)vweb
module by adding test functions for theroute_matches
, controller, middleware, static handler, large payload, and vweb app features, and provide test data and a test server (vlib/x/vweb/route_test.v
,vlib/x/vweb/tests/controller_test.v
,vlib/x/vweb/tests/middleware_test.v
,vlib/x/vweb/tests/static_handler_test.v
,vlib/x/vweb/tests/large_payload_test.v
,vlib/x/vweb/tests/vweb_app_test.v
,vlib/x/vweb/tests/testdata/
, andvlib/x/vweb/tests/vweb_test_server.v
) (link, link, link, link, link, link, link, link, link, link)BufferedReader
struct by adding test functions for thetotal_read
field after calling theread
andread_line
methods (vlib/io/reader_test.v
) (link)