mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: change optional to result of io (#16075)
This commit is contained in:
@@ -32,26 +32,26 @@ struct CloseEventHandler {
|
||||
ref voidptr // referenced object
|
||||
}
|
||||
|
||||
pub type AcceptClientFn = fn (mut c ServerClient) ?bool
|
||||
pub type AcceptClientFn = fn (mut c ServerClient) !bool
|
||||
|
||||
pub type SocketMessageFn = fn (mut c Client, msg &Message) ?
|
||||
pub type SocketMessageFn = fn (mut c Client, msg &Message) !
|
||||
|
||||
pub type SocketMessageFn2 = fn (mut c Client, msg &Message, v voidptr) ?
|
||||
pub type SocketMessageFn2 = fn (mut c Client, msg &Message, v voidptr) !
|
||||
|
||||
pub type SocketErrorFn = fn (mut c Client, err string) ?
|
||||
pub type SocketErrorFn = fn (mut c Client, err string) !
|
||||
|
||||
pub type SocketErrorFn2 = fn (mut c Client, err string, v voidptr) ?
|
||||
pub type SocketErrorFn2 = fn (mut c Client, err string, v voidptr) !
|
||||
|
||||
pub type SocketOpenFn = fn (mut c Client) ?
|
||||
pub type SocketOpenFn = fn (mut c Client) !
|
||||
|
||||
pub type SocketOpenFn2 = fn (mut c Client, v voidptr) ?
|
||||
pub type SocketOpenFn2 = fn (mut c Client, v voidptr) !
|
||||
|
||||
pub type SocketCloseFn = fn (mut c Client, code int, reason string) ?
|
||||
pub type SocketCloseFn = fn (mut c Client, code int, reason string) !
|
||||
|
||||
pub type SocketCloseFn2 = fn (mut c Client, code int, reason string, v voidptr) ?
|
||||
pub type SocketCloseFn2 = fn (mut c Client, code int, reason string, v voidptr) !
|
||||
|
||||
// on_connect registers a callback when client connects to the server
|
||||
pub fn (mut s Server) on_connect(fun AcceptClientFn) ? {
|
||||
pub fn (mut s Server) on_connect(fun AcceptClientFn) ! {
|
||||
if s.accept_client_callbacks.len > 0 {
|
||||
return error('only one callback can be registered for accept client')
|
||||
}
|
||||
@@ -156,13 +156,13 @@ pub fn (mut ws Client) on_close_ref(fun SocketCloseFn2, ref voidptr) {
|
||||
}
|
||||
|
||||
// send_connect_event invokes the on_connect callback
|
||||
fn (mut s Server) send_connect_event(mut c ServerClient) ?bool {
|
||||
fn (mut s Server) send_connect_event(mut c ServerClient) !bool {
|
||||
if s.accept_client_callbacks.len == 0 {
|
||||
// If no callback all client will be accepted
|
||||
return true
|
||||
}
|
||||
fun := s.accept_client_callbacks[0]
|
||||
res := fun(mut c)?
|
||||
res := fun(mut c)!
|
||||
return res
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import encoding.base64
|
||||
import strings
|
||||
|
||||
// handshake manages the websocket handshake process
|
||||
fn (mut ws Client) handshake() ? {
|
||||
fn (mut ws Client) handshake() ! {
|
||||
nonce := get_nonce(ws.nonce_size)
|
||||
seckey := base64.encode_str(nonce)
|
||||
mut sb := strings.new_builder(1024)
|
||||
@@ -34,21 +34,21 @@ fn (mut ws Client) handshake() ? {
|
||||
}
|
||||
handshake_bytes := handshake.bytes()
|
||||
ws.debug_log('sending handshake: $handshake')
|
||||
ws.socket_write(handshake_bytes)?
|
||||
ws.read_handshake(seckey)?
|
||||
ws.socket_write(handshake_bytes)!
|
||||
ws.read_handshake(seckey)!
|
||||
unsafe { handshake_bytes.free() }
|
||||
}
|
||||
|
||||
// handle_server_handshake manages websocket server handshake process
|
||||
fn (mut s Server) handle_server_handshake(mut c Client) ?(string, &ServerClient) {
|
||||
msg := c.read_handshake_str()?
|
||||
handshake_response, client := s.parse_client_handshake(msg, mut c)?
|
||||
fn (mut s Server) handle_server_handshake(mut c Client) !(string, &ServerClient) {
|
||||
msg := c.read_handshake_str()!
|
||||
handshake_response, client := s.parse_client_handshake(msg, mut c)!
|
||||
unsafe { msg.free() }
|
||||
return handshake_response, client
|
||||
}
|
||||
|
||||
// parse_client_handshake parses result from handshake process
|
||||
fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client) ?(string, &ServerClient) {
|
||||
fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client) !(string, &ServerClient) {
|
||||
s.logger.debug('server-> client handshake:\n$client_handshake')
|
||||
lines := client_handshake.split_into_lines()
|
||||
get_tokens := lines[0].split(' ')
|
||||
@@ -81,7 +81,7 @@ fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client)
|
||||
'Sec-WebSocket-Key', 'sec-websocket-key' {
|
||||
key = keys[1].trim_space()
|
||||
s.logger.debug('server-> got key: $key')
|
||||
seckey = create_key_challenge_response(key)?
|
||||
seckey = create_key_challenge_response(key)!
|
||||
s.logger.debug('server-> challenge: $seckey, response: ${keys[1]}')
|
||||
flags << .has_accept
|
||||
}
|
||||
@@ -112,12 +112,12 @@ fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client)
|
||||
}
|
||||
|
||||
// read_handshake_str returns the handshake response
|
||||
fn (mut ws Client) read_handshake_str() ?string {
|
||||
fn (mut ws Client) read_handshake_str() !string {
|
||||
mut total_bytes_read := 0
|
||||
mut msg := [1024]u8{}
|
||||
mut buffer := [1]u8{}
|
||||
for total_bytes_read < 1024 {
|
||||
bytes_read := ws.socket_read_ptr(&buffer[0], 1)?
|
||||
bytes_read := ws.socket_read_ptr(&buffer[0], 1)!
|
||||
if bytes_read == 0 {
|
||||
return error_with_code('unexpected no response from handshake', 5)
|
||||
}
|
||||
@@ -134,15 +134,15 @@ fn (mut ws Client) read_handshake_str() ?string {
|
||||
}
|
||||
|
||||
// read_handshake reads the handshake result and check if valid
|
||||
fn (mut ws Client) read_handshake(seckey string) ? {
|
||||
mut msg := ws.read_handshake_str()?
|
||||
ws.check_handshake_response(msg, seckey)?
|
||||
fn (mut ws Client) read_handshake(seckey string) ! {
|
||||
mut msg := ws.read_handshake_str()!
|
||||
ws.check_handshake_response(msg, seckey)!
|
||||
unsafe { msg.free() }
|
||||
}
|
||||
|
||||
// check_handshake_response checks the response from handshake and returns
|
||||
// the response and secure key provided by the websocket client
|
||||
fn (mut ws Client) check_handshake_response(handshake_response string, seckey string) ? {
|
||||
fn (mut ws Client) check_handshake_response(handshake_response string, seckey string) ! {
|
||||
ws.debug_log('handshake response:\n$handshake_response')
|
||||
lines := handshake_response.split_into_lines()
|
||||
header := lines[0]
|
||||
@@ -164,7 +164,7 @@ fn (mut ws Client) check_handshake_response(handshake_response string, seckey st
|
||||
}
|
||||
'Sec-WebSocket-Accept', 'sec-websocket-accept' {
|
||||
ws.debug_log('seckey: $seckey')
|
||||
challenge := create_key_challenge_response(seckey)?
|
||||
challenge := create_key_challenge_response(seckey)!
|
||||
ws.debug_log('challenge: $challenge, response: ${keys[1]}')
|
||||
if keys[1].trim_space() != challenge {
|
||||
return error_with_code('handshake_handler: Sec-WebSocket-Accept header does not match computed sha1/base64 response.',
|
||||
@@ -179,7 +179,7 @@ fn (mut ws Client) check_handshake_response(handshake_response string, seckey st
|
||||
}
|
||||
unsafe { lines.free() }
|
||||
if ws.flags.len < 3 {
|
||||
ws.close(1002, 'invalid websocket HTTP headers')?
|
||||
ws.close(1002, 'invalid websocket HTTP headers')!
|
||||
return error_with_code('invalid websocket HTTP headers', 8)
|
||||
}
|
||||
}
|
||||
|
@@ -3,41 +3,41 @@ module websocket
|
||||
import net
|
||||
|
||||
// socket_read reads from socket into the provided buffer
|
||||
fn (mut ws Client) socket_read(mut buffer []u8) ?int {
|
||||
fn (mut ws Client) socket_read(mut buffer []u8) !int {
|
||||
lock {
|
||||
if ws.state in [.closed, .closing] || ws.conn.sock.handle <= 1 {
|
||||
return error('socket_read: trying to read a closed socket')
|
||||
}
|
||||
if ws.is_ssl {
|
||||
r := ws.ssl_conn.read(mut buffer) or { return none }
|
||||
r := ws.ssl_conn.read(mut buffer) or { return error('none') }
|
||||
return r
|
||||
} else {
|
||||
r := ws.conn.read(mut buffer) or { return none }
|
||||
r := ws.conn.read(mut buffer) or { return error('none') }
|
||||
return r
|
||||
}
|
||||
}
|
||||
return none
|
||||
return error('none')
|
||||
}
|
||||
|
||||
// socket_read reads from socket into the provided byte pointer and length
|
||||
fn (mut ws Client) socket_read_ptr(buf_ptr &u8, len int) ?int {
|
||||
fn (mut ws Client) socket_read_ptr(buf_ptr &u8, len int) !int {
|
||||
lock {
|
||||
if ws.state in [.closed, .closing] || ws.conn.sock.handle <= 1 {
|
||||
return error('socket_read_ptr: trying to read a closed socket')
|
||||
}
|
||||
if ws.is_ssl {
|
||||
r := ws.ssl_conn.socket_read_into_ptr(buf_ptr, len)?
|
||||
r := ws.ssl_conn.socket_read_into_ptr(buf_ptr, len)!
|
||||
return r
|
||||
} else {
|
||||
r := ws.conn.read_ptr(buf_ptr, len)?
|
||||
r := ws.conn.read_ptr(buf_ptr, len)!
|
||||
return r
|
||||
}
|
||||
}
|
||||
return none
|
||||
return error('none')
|
||||
}
|
||||
|
||||
// socket_write writes the provided byte array to the socket
|
||||
fn (mut ws Client) socket_write(bytes []u8) ?int {
|
||||
fn (mut ws Client) socket_write(bytes []u8) !int {
|
||||
lock {
|
||||
if ws.state == .closed || ws.conn.sock.handle <= 1 {
|
||||
ws.debug_log('socket_write: Socket allready closed')
|
||||
@@ -61,25 +61,25 @@ fn (mut ws Client) socket_write(bytes []u8) ?int {
|
||||
}
|
||||
|
||||
// shutdown_socket shuts down the socket properly when connection is closed
|
||||
fn (mut ws Client) shutdown_socket() ? {
|
||||
fn (mut ws Client) shutdown_socket() ! {
|
||||
ws.debug_log('shutting down socket')
|
||||
if ws.is_ssl {
|
||||
ws.ssl_conn.shutdown()?
|
||||
ws.ssl_conn.shutdown()!
|
||||
} else {
|
||||
ws.conn.close()?
|
||||
ws.conn.close()!
|
||||
}
|
||||
}
|
||||
|
||||
// dial_socket connects tcp socket and initializes default configurations
|
||||
fn (mut ws Client) dial_socket() ?&net.TcpConn {
|
||||
fn (mut ws Client) dial_socket() !&net.TcpConn {
|
||||
tcp_address := '$ws.uri.hostname:$ws.uri.port'
|
||||
mut t := net.dial_tcp(tcp_address)?
|
||||
mut t := net.dial_tcp(tcp_address)!
|
||||
optval := int(1)
|
||||
t.sock.set_option_int(.keep_alive, optval)?
|
||||
t.sock.set_option_int(.keep_alive, optval)!
|
||||
t.set_read_timeout(ws.read_timeout)
|
||||
t.set_write_timeout(ws.write_timeout)
|
||||
if ws.is_ssl {
|
||||
ws.ssl_conn.connect(mut t, ws.uri.hostname)?
|
||||
ws.ssl_conn.connect(mut t, ws.uri.hostname)!
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
@@ -37,35 +37,35 @@ const (
|
||||
)
|
||||
|
||||
// validate_client validates client frame rules from RFC6455
|
||||
pub fn (mut ws Client) validate_frame(frame &Frame) ? {
|
||||
pub fn (mut ws Client) validate_frame(frame &Frame) ! {
|
||||
if frame.rsv1 || frame.rsv2 || frame.rsv3 {
|
||||
ws.close(1002, 'rsv cannot be other than 0, not negotiated')?
|
||||
ws.close(1002, 'rsv cannot be other than 0, not negotiated')!
|
||||
return error('rsv cannot be other than 0, not negotiated')
|
||||
}
|
||||
if (int(frame.opcode) >= 3 && int(frame.opcode) <= 7)
|
||||
|| (int(frame.opcode) >= 11 && int(frame.opcode) <= 15) {
|
||||
ws.close(1002, 'use of reserved opcode')?
|
||||
ws.close(1002, 'use of reserved opcode')!
|
||||
return error('use of reserved opcode')
|
||||
}
|
||||
if frame.has_mask && !ws.is_server {
|
||||
// server should never send masked frames
|
||||
// to client, close connection
|
||||
ws.close(1002, 'client got masked frame')?
|
||||
ws.close(1002, 'client got masked frame')!
|
||||
return error('client sent masked frame')
|
||||
}
|
||||
if is_control_frame(frame.opcode) {
|
||||
if !frame.fin {
|
||||
ws.close(1002, 'control message must not be fragmented')?
|
||||
ws.close(1002, 'control message must not be fragmented')!
|
||||
return error('unexpected control frame with no fin')
|
||||
}
|
||||
if frame.payload_len > 125 {
|
||||
ws.close(1002, 'control frames must not exceed 125 bytes')?
|
||||
ws.close(1002, 'control frames must not exceed 125 bytes')!
|
||||
return error('unexpected control frame payload length')
|
||||
}
|
||||
}
|
||||
if frame.fin == false && ws.fragments.len == 0 && frame.opcode == .continuation {
|
||||
err_msg := 'unexecpected continuation, there are no frames to continue, $frame'
|
||||
ws.close(1002, err_msg)?
|
||||
ws.close(1002, err_msg)!
|
||||
return error(err_msg)
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ fn is_data_frame(opcode OPCode) bool {
|
||||
}
|
||||
|
||||
// read_payload reads the message payload from the socket
|
||||
fn (mut ws Client) read_payload(frame &Frame) ?[]u8 {
|
||||
fn (mut ws Client) read_payload(frame &Frame) ![]u8 {
|
||||
if frame.payload_len == 0 {
|
||||
return []u8{}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ fn (mut ws Client) read_payload(frame &Frame) ?[]u8 {
|
||||
mut read_buf := [1]u8{}
|
||||
mut bytes_read := 0
|
||||
for bytes_read < frame.payload_len {
|
||||
len := ws.socket_read_ptr(&read_buf[0], 1)?
|
||||
len := ws.socket_read_ptr(&read_buf[0], 1)!
|
||||
if len != 1 {
|
||||
return error('expected read all message, got zero')
|
||||
}
|
||||
@@ -109,21 +109,21 @@ fn (mut ws Client) read_payload(frame &Frame) ?[]u8 {
|
||||
|
||||
// validate_utf_8 validates payload for valid utf8 encoding
|
||||
// - Future implementation needs to support fail fast utf errors for strict autobahn conformance
|
||||
fn (mut ws Client) validate_utf_8(opcode OPCode, payload []u8) ? {
|
||||
fn (mut ws Client) validate_utf_8(opcode OPCode, payload []u8) ! {
|
||||
if opcode in [.text_frame, .close] && !utf8.validate(payload.data, payload.len) {
|
||||
ws.logger.error('malformed utf8 payload, payload len: ($payload.len)')
|
||||
ws.send_error_event('Recieved malformed utf8.')
|
||||
ws.close(1007, 'malformed utf8 payload')?
|
||||
ws.close(1007, 'malformed utf8 payload')!
|
||||
return error('malformed utf8 payload')
|
||||
}
|
||||
}
|
||||
|
||||
// read_next_message reads 1 to n frames to compose a message
|
||||
pub fn (mut ws Client) read_next_message() ?Message {
|
||||
pub fn (mut ws Client) read_next_message() !Message {
|
||||
for {
|
||||
frame := ws.parse_frame_header()?
|
||||
ws.validate_frame(&frame)?
|
||||
frame_payload := ws.read_payload(&frame)?
|
||||
frame := ws.parse_frame_header()!
|
||||
ws.validate_frame(&frame)!
|
||||
frame_payload := ws.read_payload(&frame)!
|
||||
if is_control_frame(frame.opcode) {
|
||||
// Control frames can interject other frames
|
||||
// and need to be returned immediately
|
||||
@@ -161,12 +161,12 @@ pub fn (mut ws Client) read_next_message() ?Message {
|
||||
ws.fragments = []
|
||||
}
|
||||
if is_data_frame(frame.opcode) {
|
||||
ws.close(0, '')?
|
||||
ws.close(0, '')!
|
||||
return error('Unexpected frame opcode')
|
||||
}
|
||||
payload := ws.payload_from_fragments(frame_payload)?
|
||||
payload := ws.payload_from_fragments(frame_payload)!
|
||||
opcode := ws.opcode_from_fragments()
|
||||
ws.validate_utf_8(opcode, payload)?
|
||||
ws.validate_utf_8(opcode, payload)!
|
||||
msg := Message{
|
||||
opcode: opcode
|
||||
payload: payload.clone()
|
||||
@@ -177,11 +177,11 @@ pub fn (mut ws Client) read_next_message() ?Message {
|
||||
}
|
||||
return msg
|
||||
}
|
||||
return none
|
||||
return error('none')
|
||||
}
|
||||
|
||||
// payload_from_fragments returs the whole paylaod from fragmented message
|
||||
fn (ws Client) payload_from_fragments(fin_payload []u8) ?[]u8 {
|
||||
fn (ws Client) payload_from_fragments(fin_payload []u8) ![]u8 {
|
||||
mut total_size := 0
|
||||
for f in ws.fragments {
|
||||
if f.data.len > 0 {
|
||||
@@ -208,14 +208,14 @@ fn (ws Client) opcode_from_fragments() OPCode {
|
||||
}
|
||||
|
||||
// parse_frame_header parses next message by decoding the incoming frames
|
||||
pub fn (mut ws Client) parse_frame_header() ?Frame {
|
||||
pub fn (mut ws Client) parse_frame_header() !Frame {
|
||||
mut buffer := [256]u8{}
|
||||
mut bytes_read := 0
|
||||
mut frame := Frame{}
|
||||
mut rbuff := [1]u8{}
|
||||
mut mask_end_byte := 0
|
||||
for ws.state == .open {
|
||||
read_bytes := ws.socket_read_ptr(&rbuff[0], 1)?
|
||||
read_bytes := ws.socket_read_ptr(&rbuff[0], 1)!
|
||||
if read_bytes == 0 {
|
||||
// this is probably a timeout or close
|
||||
continue
|
||||
|
@@ -10,20 +10,20 @@ fn main() {
|
||||
}
|
||||
// update the reports
|
||||
uri := 'ws://autobahn_server:9001/updateReports?agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn handle_case(case_nr int) ? {
|
||||
fn handle_case(case_nr int) ! {
|
||||
uri := 'ws://autobahn_server:9001/runCase?case=$case_nr&agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.on_message(on_message)
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ? {
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ! {
|
||||
// autobahn tests expects to send same message back
|
||||
if msg.opcode == .pong {
|
||||
// We just wanna pass text and binary message back to autobahn
|
||||
|
@@ -11,21 +11,21 @@ fn main() {
|
||||
// update the reports
|
||||
// uri := 'wss://localhost:9002/updateReports?agent=v-client'
|
||||
uri := 'wss://autobahn_server_wss:9002/updateReports?agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn handle_case(case_nr int) ? {
|
||||
fn handle_case(case_nr int) ! {
|
||||
uri := 'wss://autobahn_server_wss:9002/runCase?case=$case_nr&agent=v-client'
|
||||
// uri := 'wss://localhost:9002/runCase?case=$case_nr&agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.on_message(on_message)
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ? {
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ! {
|
||||
// autobahn tests expects to send same message back
|
||||
if msg.opcode == .pong {
|
||||
// We just wanna pass text and binary message back to autobahn
|
||||
|
@@ -9,15 +9,15 @@ fn main() {
|
||||
s.listen() or { panic(err) }
|
||||
}
|
||||
|
||||
fn handle_case(case_nr int) ? {
|
||||
fn handle_case(case_nr int) ! {
|
||||
uri := 'ws://localhost:9002/runCase?case=$case_nr&agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.on_message(on_message)
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ? {
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ! {
|
||||
// autobahn tests expects to send same message back
|
||||
if msg.opcode == .pong {
|
||||
// We just wanna pass text and binary message back to autobahn
|
||||
|
@@ -10,20 +10,20 @@ fn main() {
|
||||
}
|
||||
// update the reports
|
||||
uri := 'ws://localhost:9001/updateReports?agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn handle_case(case_nr int) ? {
|
||||
fn handle_case(case_nr int) ! {
|
||||
uri := 'ws://localhost:9001/runCase?case=$case_nr&agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.on_message(on_message)
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ? {
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ! {
|
||||
// autobahn tests expects to send same message back
|
||||
if msg.opcode == .pong {
|
||||
// We just wanna pass text and binary message back to autobahn
|
||||
|
@@ -11,21 +11,21 @@ fn main() {
|
||||
// update the reports
|
||||
// uri := 'wss://localhost:9002/updateReports?agent=v-client'
|
||||
uri := 'wss://autobahn_server_wss:9002/updateReports?agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn handle_case(case_nr int) ? {
|
||||
fn handle_case(case_nr int) ! {
|
||||
uri := 'wss://autobahn_server_wss:9002/runCase?case=$case_nr&agent=v-client'
|
||||
// uri := 'wss://localhost:9002/runCase?case=$case_nr&agent=v-client'
|
||||
mut ws := websocket.new_client(uri)?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.on_message(on_message)
|
||||
ws.connect()?
|
||||
ws.listen()?
|
||||
ws.connect()!
|
||||
ws.listen()!
|
||||
}
|
||||
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ? {
|
||||
fn on_message(mut ws websocket.Client, msg &websocket.Message) ! {
|
||||
// autobahn tests expects to send same message back
|
||||
if msg.opcode == .pong {
|
||||
// We just wanna pass text and binary message back to autobahn
|
||||
|
@@ -27,7 +27,7 @@ fn create_masking_key() []u8 {
|
||||
}
|
||||
|
||||
// create_key_challenge_response creates a key challange response from security key
|
||||
fn create_key_challenge_response(seckey string) ?string {
|
||||
fn create_key_challenge_response(seckey string) !string {
|
||||
if seckey.len == 0 {
|
||||
return error('unexpected seckey lengt zero')
|
||||
}
|
||||
|
@@ -88,12 +88,12 @@ pub struct ClientOpt {
|
||||
}
|
||||
|
||||
// new_client instance a new websocket client
|
||||
pub fn new_client(address string, opt ClientOpt) ?&Client {
|
||||
uri := parse_uri(address)?
|
||||
pub fn new_client(address string, opt ClientOpt) !&Client {
|
||||
uri := parse_uri(address)!
|
||||
return &Client{
|
||||
conn: 0
|
||||
is_server: false
|
||||
ssl_conn: ssl.new_ssl_conn()?
|
||||
ssl_conn: ssl.new_ssl_conn()!
|
||||
is_ssl: address.starts_with('wss')
|
||||
logger: opt.logger
|
||||
uri: uri
|
||||
@@ -106,19 +106,19 @@ pub fn new_client(address string, opt ClientOpt) ?&Client {
|
||||
}
|
||||
|
||||
// connect connects to remote websocket server
|
||||
pub fn (mut ws Client) connect() ? {
|
||||
ws.assert_not_connected()?
|
||||
pub fn (mut ws Client) connect() ! {
|
||||
ws.assert_not_connected()!
|
||||
ws.set_state(.connecting)
|
||||
ws.logger.info('connecting to host $ws.uri')
|
||||
ws.conn = ws.dial_socket()?
|
||||
ws.handshake()?
|
||||
ws.conn = ws.dial_socket()!
|
||||
ws.handshake()!
|
||||
ws.set_state(.open)
|
||||
ws.logger.info('successfully connected to host $ws.uri')
|
||||
ws.send_open_event()
|
||||
}
|
||||
|
||||
// listen listens and processes incoming messages
|
||||
pub fn (mut ws Client) listen() ? {
|
||||
pub fn (mut ws Client) listen() ! {
|
||||
mut log := 'Starting client listener, server($ws.is_server)...'
|
||||
ws.logger.info(log)
|
||||
unsafe { log.free() }
|
||||
@@ -185,30 +185,30 @@ pub fn (mut ws Client) listen() ? {
|
||||
}
|
||||
if msg.payload.len > 0 {
|
||||
if msg.payload.len == 1 {
|
||||
ws.close(1002, 'close payload cannot be 1 byte')?
|
||||
ws.close(1002, 'close payload cannot be 1 byte')!
|
||||
return error('close payload cannot be 1 byte')
|
||||
}
|
||||
code := u16(msg.payload[0]) << 8 | u16(msg.payload[1])
|
||||
if code in invalid_close_codes {
|
||||
ws.close(1002, 'invalid close code: $code')?
|
||||
ws.close(1002, 'invalid close code: $code')!
|
||||
return error('invalid close code: $code')
|
||||
}
|
||||
reason := if msg.payload.len > 2 { msg.payload[2..] } else { []u8{} }
|
||||
if reason.len > 0 {
|
||||
ws.validate_utf_8(.close, reason)?
|
||||
ws.validate_utf_8(.close, reason)!
|
||||
}
|
||||
if ws.state !in [.closing, .closed] {
|
||||
// sending close back according to spec
|
||||
ws.debug_log('close with reason, code: $code, reason: $reason')
|
||||
r := reason.bytestr()
|
||||
ws.close(code, r)?
|
||||
ws.close(code, r)!
|
||||
}
|
||||
unsafe { msg.free() }
|
||||
} else {
|
||||
if ws.state !in [.closing, .closed] {
|
||||
ws.debug_log('close with reason, no code')
|
||||
// sending close back according to spec
|
||||
ws.close(1000, 'normal')?
|
||||
ws.close(1000, 'normal')!
|
||||
}
|
||||
unsafe { msg.free() }
|
||||
}
|
||||
@@ -217,7 +217,7 @@ pub fn (mut ws Client) listen() ? {
|
||||
.continuation {
|
||||
ws.logger.error('unexpected opcode continuation, nothing to continue')
|
||||
ws.send_error_event('unexpected opcode continuation, nothing to continue')
|
||||
ws.close(1002, 'nothing to continue')?
|
||||
ws.close(1002, 'nothing to continue')!
|
||||
return error('unexpected opcode continuation, nothing to continue')
|
||||
}
|
||||
}
|
||||
@@ -230,17 +230,17 @@ fn (mut ws Client) manage_clean_close() {
|
||||
}
|
||||
|
||||
// ping sends ping message to server
|
||||
pub fn (mut ws Client) ping() ? {
|
||||
ws.send_control_frame(.ping, 'PING', [])?
|
||||
pub fn (mut ws Client) ping() ! {
|
||||
ws.send_control_frame(.ping, 'PING', [])!
|
||||
}
|
||||
|
||||
// pong sends pong message to server,
|
||||
pub fn (mut ws Client) pong() ? {
|
||||
ws.send_control_frame(.pong, 'PONG', [])?
|
||||
pub fn (mut ws Client) pong() ! {
|
||||
ws.send_control_frame(.pong, 'PONG', [])!
|
||||
}
|
||||
|
||||
// write_ptr writes len bytes provided a byteptr with a websocket messagetype
|
||||
pub fn (mut ws Client) write_ptr(bytes &u8, payload_len int, code OPCode) ?int {
|
||||
pub fn (mut ws Client) write_ptr(bytes &u8, payload_len int, code OPCode) !int {
|
||||
// ws.debug_log('write_ptr code: $code')
|
||||
if ws.state != .open || ws.conn.sock.handle < 1 {
|
||||
// todo: send error here later
|
||||
@@ -290,7 +290,7 @@ pub fn (mut ws Client) write_ptr(bytes &u8, payload_len int, code OPCode) ?int {
|
||||
header[12] = masking_key[2]
|
||||
header[13] = masking_key[3]
|
||||
} else {
|
||||
ws.close(1009, 'frame too large')?
|
||||
ws.close(1009, 'frame too large')!
|
||||
return error('frame too large')
|
||||
}
|
||||
}
|
||||
@@ -307,7 +307,7 @@ pub fn (mut ws Client) write_ptr(bytes &u8, payload_len int, code OPCode) ?int {
|
||||
frame_buf[header_len + i] ^= masking_key[i % 4] & 0xff
|
||||
}
|
||||
}
|
||||
written_len := ws.socket_write(frame_buf)?
|
||||
written_len := ws.socket_write(frame_buf)!
|
||||
unsafe {
|
||||
frame_buf.free()
|
||||
masking_key.free()
|
||||
@@ -317,17 +317,17 @@ pub fn (mut ws Client) write_ptr(bytes &u8, payload_len int, code OPCode) ?int {
|
||||
}
|
||||
|
||||
// write writes a byte array with a websocket messagetype to socket
|
||||
pub fn (mut ws Client) write(bytes []u8, code OPCode) ?int {
|
||||
pub fn (mut ws Client) write(bytes []u8, code OPCode) !int {
|
||||
return ws.write_ptr(&u8(bytes.data), bytes.len, code)
|
||||
}
|
||||
|
||||
// write_str, writes a string with a websocket texttype to socket
|
||||
pub fn (mut ws Client) write_string(str string) ?int {
|
||||
pub fn (mut ws Client) write_string(str string) !int {
|
||||
return ws.write_ptr(str.str, str.len, .text_frame)
|
||||
}
|
||||
|
||||
// close closes the websocket connection
|
||||
pub fn (mut ws Client) close(code int, message string) ? {
|
||||
pub fn (mut ws Client) close(code int, message string) ! {
|
||||
ws.debug_log('sending close, $code, $message')
|
||||
if ws.state in [.closed, .closing] || ws.conn.sock.handle <= 1 {
|
||||
ws.debug_log('close: Websocket allready closed ($ws.state), $message, $code handle($ws.conn.sock.handle)')
|
||||
@@ -350,16 +350,16 @@ pub fn (mut ws Client) close(code int, message string) ? {
|
||||
for i in 0 .. message.len {
|
||||
close_frame[i + 2] = message[i]
|
||||
}
|
||||
ws.send_control_frame(.close, 'CLOSE', close_frame)?
|
||||
ws.send_control_frame(.close, 'CLOSE', close_frame)!
|
||||
unsafe { close_frame.free() }
|
||||
} else {
|
||||
ws.send_control_frame(.close, 'CLOSE', [])?
|
||||
ws.send_control_frame(.close, 'CLOSE', [])!
|
||||
}
|
||||
ws.fragments = []
|
||||
}
|
||||
|
||||
// send_control_frame sends a control frame to the server
|
||||
fn (mut ws Client) send_control_frame(code OPCode, frame_typ string, payload []u8) ? {
|
||||
fn (mut ws Client) send_control_frame(code OPCode, frame_typ string, payload []u8) ! {
|
||||
ws.debug_log('send control frame $code, frame_type: $frame_typ')
|
||||
if ws.state !in [.open, .closing] && ws.conn.sock.handle > 1 {
|
||||
return error('socket is not connected')
|
||||
@@ -419,8 +419,8 @@ fn (mut ws Client) send_control_frame(code OPCode, frame_typ string, payload []u
|
||||
}
|
||||
|
||||
// parse_uri parses the url to a Uri
|
||||
fn parse_uri(url string) ?&Uri {
|
||||
u := urllib.parse(url)?
|
||||
fn parse_uri(url string) !&Uri {
|
||||
u := urllib.parse(url)!
|
||||
request_uri := u.request_uri()
|
||||
v := request_uri.split('?')
|
||||
mut port := u.port()
|
||||
@@ -452,7 +452,7 @@ fn (mut ws Client) set_state(state State) {
|
||||
}
|
||||
|
||||
// assert_not_connected returns error if the connection is not connected
|
||||
fn (ws Client) assert_not_connected() ? {
|
||||
fn (ws Client) assert_not_connected() ! {
|
||||
match ws.state {
|
||||
.connecting { return error('connect: websocket is connecting') }
|
||||
.open { return error('connect: websocket already open') }
|
||||
@@ -462,10 +462,10 @@ fn (ws Client) assert_not_connected() ? {
|
||||
}
|
||||
|
||||
// reset_state resets the websocket and initialize default settings
|
||||
fn (mut ws Client) reset_state() ? {
|
||||
fn (mut ws Client) reset_state() ! {
|
||||
lock {
|
||||
ws.state = .closed
|
||||
ws.ssl_conn = ssl.new_ssl_conn()?
|
||||
ws.ssl_conn = ssl.new_ssl_conn()!
|
||||
ws.flags = []
|
||||
ws.fragments = []
|
||||
}
|
||||
|
@@ -60,9 +60,9 @@ pub fn (mut s Server) set_ping_interval(seconds int) {
|
||||
}
|
||||
|
||||
// listen start listen and process to incoming connections from websocket clients
|
||||
pub fn (mut s Server) listen() ? {
|
||||
pub fn (mut s Server) listen() ! {
|
||||
s.logger.info('websocket server: start listen on port $s.port')
|
||||
s.ls = net.listen_tcp(s.family, ':$s.port')?
|
||||
s.ls = net.listen_tcp(s.family, ':$s.port')!
|
||||
s.set_state(.open)
|
||||
go s.handle_ping()
|
||||
for {
|
||||
@@ -110,20 +110,20 @@ fn (mut s Server) handle_ping() {
|
||||
}
|
||||
|
||||
// serve_client accepts incoming connection and sets up the callbacks
|
||||
fn (mut s Server) serve_client(mut c Client) ? {
|
||||
fn (mut s Server) serve_client(mut c Client) ! {
|
||||
c.logger.debug('server-> Start serve client ($c.id)')
|
||||
defer {
|
||||
c.logger.debug('server-> End serve client ($c.id)')
|
||||
}
|
||||
mut handshake_response, mut server_client := s.handle_server_handshake(mut c)?
|
||||
accept := s.send_connect_event(mut server_client)?
|
||||
mut handshake_response, mut server_client := s.handle_server_handshake(mut c)!
|
||||
accept := s.send_connect_event(mut server_client)!
|
||||
if !accept {
|
||||
s.logger.debug('server-> client not accepted')
|
||||
c.shutdown_socket()?
|
||||
c.shutdown_socket()!
|
||||
return
|
||||
}
|
||||
// the client is accepted
|
||||
c.socket_write(handshake_response.bytes())?
|
||||
c.socket_write(handshake_response.bytes())!
|
||||
lock {
|
||||
s.clients[server_client.client.id] = server_client
|
||||
}
|
||||
@@ -155,7 +155,7 @@ fn (mut s Server) setup_callbacks(mut sc ServerClient) {
|
||||
}
|
||||
}
|
||||
// set standard close so we can remove client if closed
|
||||
sc.client.on_close_ref(fn (mut c Client, code int, reason string, mut sc ServerClient) ? {
|
||||
sc.client.on_close_ref(fn (mut c Client, code int, reason string, mut sc ServerClient) ! {
|
||||
c.logger.debug('server-> Delete client')
|
||||
lock {
|
||||
sc.server.clients.delete(sc.client.id)
|
||||
@@ -164,12 +164,12 @@ fn (mut s Server) setup_callbacks(mut sc ServerClient) {
|
||||
}
|
||||
|
||||
// accept_new_client creates a new client instance for client that connects to the socket
|
||||
fn (mut s Server) accept_new_client() ?&Client {
|
||||
mut new_conn := s.ls.accept()?
|
||||
fn (mut s Server) accept_new_client() !&Client {
|
||||
mut new_conn := s.ls.accept()!
|
||||
c := &Client{
|
||||
is_server: true
|
||||
conn: new_conn
|
||||
ssl_conn: ssl.new_ssl_conn()?
|
||||
ssl_conn: ssl.new_ssl_conn()!
|
||||
logger: s.logger
|
||||
state: .open
|
||||
last_pong_ut: time.now().unix
|
||||
|
@@ -50,12 +50,12 @@ fn test_ws_ipv4() {
|
||||
}
|
||||
}
|
||||
|
||||
fn start_server(family net.AddrFamily, listen_port int) ? {
|
||||
fn start_server(family net.AddrFamily, listen_port int) ! {
|
||||
mut s := websocket.new_server(family, listen_port, '')
|
||||
// make that in execution test time give time to execute at least one time
|
||||
s.ping_interval = 1
|
||||
|
||||
s.on_connect(fn (mut s websocket.ServerClient) ?bool {
|
||||
s.on_connect(fn (mut s websocket.ServerClient) !bool {
|
||||
// here you can look att the client info and accept or not accept
|
||||
// just returning a true/false
|
||||
if s.resource_name != '/' {
|
||||
@@ -63,37 +63,37 @@ fn start_server(family net.AddrFamily, listen_port int) ? {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})?
|
||||
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
|
||||
})!
|
||||
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
|
||||
match msg.opcode {
|
||||
.pong { ws.write_string('pong')? }
|
||||
else { ws.write(msg.payload, msg.opcode)? }
|
||||
.pong { ws.write_string('pong')! }
|
||||
else { ws.write(msg.payload, msg.opcode)! }
|
||||
}
|
||||
})
|
||||
|
||||
s.on_close(fn (mut ws websocket.Client, code int, reason string) ? {
|
||||
s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
|
||||
// not used
|
||||
})
|
||||
s.listen() or { panic('websocket server could not listen, err: $err') }
|
||||
}
|
||||
|
||||
// ws_test tests connect to the websocket server from websocket client
|
||||
fn ws_test(family net.AddrFamily, uri string) ? {
|
||||
fn ws_test(family net.AddrFamily, uri string) ! {
|
||||
eprintln('connecting to $uri ...')
|
||||
|
||||
mut test_results := WebsocketTestResults{}
|
||||
mut ws := websocket.new_client(uri)?
|
||||
ws.on_open(fn (mut ws websocket.Client) ? {
|
||||
ws.pong()?
|
||||
mut ws := websocket.new_client(uri)!
|
||||
ws.on_open(fn (mut ws websocket.Client) ! {
|
||||
ws.pong()!
|
||||
assert true
|
||||
})
|
||||
ws.on_error(fn (mut ws websocket.Client, err string) ? {
|
||||
ws.on_error(fn (mut ws websocket.Client, err string) ! {
|
||||
println('error: $err')
|
||||
// this can be thrown by internet connection problems
|
||||
assert false
|
||||
})
|
||||
|
||||
ws.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut res WebsocketTestResults) ? {
|
||||
ws.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut res WebsocketTestResults) ! {
|
||||
println('client got type: $msg.opcode payload:\n$msg.payload')
|
||||
if msg.opcode == .text_frame {
|
||||
smessage := msg.payload.bytestr()
|
||||
|
Reference in New Issue
Block a user