Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,41 @@
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
body {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin-left: 30px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
#message-list {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
margin: 0px;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid lightgray;
|
||||
overflow-y: scroll;
|
||||
overscroll-behavior-y: contain;
|
||||
scroll-snap-type: y proximity;
|
||||
}
|
||||
#message-list > li {
|
||||
list-style-type: none;
|
||||
}
|
||||
#message-list > li:last-child {
|
||||
scroll-snap-align: end;
|
||||
border-top: 1px solid #eeeeff !important;
|
||||
}
|
||||
|
||||
#message-input {
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang=en>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>veb websocket example</title>
|
||||
<link rel="stylesheet" type="text/css" href="/assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<p>This is an example of using V's `veb` and `net.websocket` modules in
|
||||
the same app, where the websocket connection happens on the /ws route of
|
||||
your veb app.</p>
|
||||
<ul id="message-list"></ul>
|
||||
<input id="message-input" placeholder="Enter your message here" value=""/>
|
||||
<div>Client status: <span id="message-status">---</span></div>
|
||||
<script type="text/javascript" src="/assets/client.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
module main
|
||||
|
||||
import os
|
||||
import veb
|
||||
import log
|
||||
import time
|
||||
import term
|
||||
import net
|
||||
import net.http
|
||||
import net.websocket
|
||||
|
||||
const app_port = 8990
|
||||
|
||||
fn main() {
|
||||
log.use_stdout()
|
||||
mut app := &App{
|
||||
wss: new_websocker_server()!
|
||||
}
|
||||
app.mount_static_folder_at(os.resource_abs_path('assets'), '/assets')!
|
||||
app.serve_static('/favicon.ico', os.resource_abs_path('assets/favicon.ico'))!
|
||||
veb.run[App, Context](mut app, app_port)
|
||||
}
|
||||
|
||||
pub struct Context {
|
||||
veb.Context
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
veb.StaticHandler
|
||||
mut:
|
||||
wss &websocket.Server
|
||||
}
|
||||
|
||||
pub fn (mut app App) index(mut ctx Context) veb.Result {
|
||||
return $veb.html()
|
||||
}
|
||||
|
||||
pub fn (mut app App) ws(mut ctx Context) veb.Result {
|
||||
key := ctx.get_header(http.CommonHeader.sec_websocket_key) or { '' }
|
||||
if key == '' {
|
||||
ctx.error('Invalid websocket handshake. Key is missing.')
|
||||
return ctx.redirect('/')
|
||||
}
|
||||
dump(ctx.req.cookie('token') or { http.Cookie{} }.value)
|
||||
wlog('> transferring connection with key: ${key}, to the websocket server ${voidptr(app.wss)} ...')
|
||||
ctx.takeover_conn()
|
||||
ctx.conn.set_write_timeout(time.infinite)
|
||||
ctx.conn.set_read_timeout(time.infinite)
|
||||
spawn fn (mut wss websocket.Server, mut connection net.TcpConn, key string) {
|
||||
wss.handle_handshake(mut connection, key) or { wlog('handle_handshake error: ${err}') }
|
||||
wlog('>> wss.handle_handshake finished, key: ${key}')
|
||||
}(mut app.wss, mut ctx.conn, key)
|
||||
wlog('> done transferring connection')
|
||||
return veb.no_result()
|
||||
}
|
||||
|
||||
fn slog(message string) {
|
||||
eprintln(term.colorize(term.bright_yellow, message))
|
||||
}
|
||||
|
||||
fn wlog(message string) {
|
||||
eprintln(term.colorize(term.bright_blue, message))
|
||||
}
|
||||
|
||||
fn new_websocker_server() !&websocket.Server {
|
||||
mut logger := &log.Log{}
|
||||
logger.set_level(.info)
|
||||
logger.set_output_stream(os.stderr())
|
||||
mut wss := websocket.new_server(.ip, app_port, '', logger: logger)
|
||||
wss.set_ping_interval(100)
|
||||
wss.on_connect(fn [mut logger] (mut server_client websocket.ServerClient) !bool {
|
||||
server_client.client.logger = logger
|
||||
slog('wss.on_connect client.id: ${server_client.client.id} | server_client.client_key: ${server_client.client_key}')
|
||||
return true
|
||||
})!
|
||||
wss.on_close(fn (mut client websocket.Client, code int, reason string) ! {
|
||||
slog('wss.on_close client.id: ${client.id} | code: ${code}, reason: ${reason}')
|
||||
})
|
||||
wss.on_message(fn [mut wss] (mut client websocket.Client, msg &websocket.Message) ! {
|
||||
slog('wss.on_message client.id: ${client.id} | msg.opcode: ${msg.opcode} | msg.payload: `${msg.payload.bytestr()}`')
|
||||
text := '${client.id} says: "${msg.payload.bytestr()}"'
|
||||
// client.write_string(text) or { slog('client.write err: ${err}') return err }
|
||||
for i, _ in rlock wss.server_state {
|
||||
wss.server_state.clients
|
||||
} {
|
||||
mut c := rlock wss.server_state {
|
||||
wss.server_state.clients[i] or { continue }
|
||||
}
|
||||
if c.client.get_state() == .open {
|
||||
c.client.write_string(text) or {
|
||||
slog('error while broadcasting to i: ${i}, ${voidptr(c)}, err: ${err}')
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
slog('Websocket Server initialized, wss: ${voidptr(wss)}')
|
||||
return wss
|
||||
}
|
||||
Reference in new issue
Block a user