mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
examples: add examples/vweb/server_sent_events; implement vweb.sse
This commit is contained in:
77
vlib/vweb/sse/sse.v
Normal file
77
vlib/vweb/sse/sse.v
Normal file
@ -0,0 +1,77 @@
|
||||
module sse
|
||||
|
||||
import net
|
||||
import time
|
||||
import strings
|
||||
|
||||
// This module implements the server side of `Server Sent Events`.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format
|
||||
// as well as https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events
|
||||
// for detailed description of the protocol, and a simple web browser client example.
|
||||
//
|
||||
// > Event stream format
|
||||
// > The event stream is a simple stream of text data which must be encoded using UTF-8.
|
||||
// > Messages in the event stream are separated by a pair of newline characters.
|
||||
// > A colon as the first character of a line is in essence a comment, and is ignored.
|
||||
// > Note: The comment line can be used to prevent connections from timing out;
|
||||
// > a server can send a comment periodically to keep the connection alive.
|
||||
// >
|
||||
// > Each message consists of one or more lines of text listing the fields for that message.
|
||||
// > Each field is represented by the field name, followed by a colon, followed by the text
|
||||
// > data for that field's value.
|
||||
|
||||
[ref_only]
|
||||
pub struct SSEConnection {
|
||||
pub mut:
|
||||
headers map[string]string
|
||||
conn &net.TcpConn
|
||||
write_timeout time.Duration = 600 * time.second
|
||||
}
|
||||
|
||||
pub struct SSEMessage {
|
||||
id string
|
||||
event string
|
||||
data string
|
||||
retry int
|
||||
}
|
||||
|
||||
pub fn new_connection(conn &net.TcpConn) SSEConnection {
|
||||
return SSEConnection{
|
||||
conn: conn
|
||||
}
|
||||
}
|
||||
|
||||
// sse_start is used to send the start of a Server Side Event response.
|
||||
pub fn (mut sse SSEConnection) start() ? {
|
||||
sse.conn.set_write_timeout(sse.write_timeout)
|
||||
mut start_sb := strings.new_builder(512)
|
||||
start_sb.write('HTTP/1.1 200')
|
||||
start_sb.write('\r\nConnection: keep-alive')
|
||||
start_sb.write('\r\nCache-Control: no-cache')
|
||||
start_sb.write('\r\nContent-Type: text/event-stream')
|
||||
for k, v in sse.headers {
|
||||
start_sb.write('\r\n$k: $v')
|
||||
}
|
||||
start_sb.write('\r\n')
|
||||
sse.conn.write(start_sb.buf) or { return error('could not start sse response') }
|
||||
}
|
||||
|
||||
// send_message sends a single message to the http client that listens for SSE.
|
||||
// It does not close the connection, so you can use it many times in a loop.
|
||||
pub fn (mut sse SSEConnection) send_message(message SSEMessage) ? {
|
||||
mut sb := strings.new_builder(512)
|
||||
if message.id != '' {
|
||||
sb.write('id: $message.id\n')
|
||||
}
|
||||
if message.event != '' {
|
||||
sb.write('event: $message.event\n')
|
||||
}
|
||||
if message.data != '' {
|
||||
sb.write('data: $message.data\n')
|
||||
}
|
||||
if message.retry != 0 {
|
||||
sb.write('retry: $message.retry\n')
|
||||
}
|
||||
sb.write('\n')
|
||||
sse.conn.write(sb.buf) ?
|
||||
}
|
@ -158,6 +158,17 @@ pub fn (mut ctx Context) ok(s string) Result {
|
||||
return Result{}
|
||||
}
|
||||
|
||||
pub fn (mut ctx Context) server_error(ecode int) Result {
|
||||
$if debug {
|
||||
eprintln('> ctx.server_error ecode: $ecode')
|
||||
}
|
||||
if ctx.done {
|
||||
return Result{}
|
||||
}
|
||||
send_string(mut ctx.conn, vweb.http_500) or { }
|
||||
return Result{}
|
||||
}
|
||||
|
||||
pub fn (mut ctx Context) redirect(url string) Result {
|
||||
if ctx.done {
|
||||
return Result{}
|
||||
@ -304,7 +315,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
||||
page_gen_start := time.ticks()
|
||||
first_line := reader.read_line() or {
|
||||
$if debug {
|
||||
eprintln('Failed first_line') // show this only in debug mode, because it always would be shown after a chromium user visits the site
|
||||
eprintln('Failed first_line') // show this only in debug mode, because it always would be shown after a chromium user visits the site
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -592,6 +603,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
||||
// call action method
|
||||
if method.args.len == vars.len {
|
||||
app.$method(vars)
|
||||
return
|
||||
} else {
|
||||
eprintln('warning: uneven parameters count ($method.args.len) in `$method.name`, compared to the vweb route `$method.attrs` ($vars.len)')
|
||||
}
|
||||
|
Reference in New Issue
Block a user