summaryrefslogtreecommitdiff
path: root/sites/pmikkelsen.com/plan9/webfs-websocket.md
blob: 084411b5d4d15cb999876b4cc02404b0426ea6cf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# Creating websocket connections via 9front's webfs

With the following patch (note: work in progress, contains bugs), 9front's webfs can be used
to create websocket connections. The patch is available [here](https://files.pmikkelsen.com/websocket-webfs.patch).

## The idea

Creating a websocket connection is done just like creating a http request is, except the
url must use scheme `wss://` or `ws://`, and the `body` file must be opened read-write to
allow both sending and receiving.

The very first message to be read from `body` is always "websocket ready", meaning the connection has been
established. After that the actual communication begins.

Webfs itself takes care of the control messages, so only the data messages gets delivered to the user, in a textual
format that is easy to parse. Each message read and writen to `body` consists of a 22 byte header in the following format

	b nnnnnnnnnnnnnnnnnnnn

or

	t nnnnnnnnnnnnnnnnnnnn

for binary and text messages respectively. The 20 last bytes are a 0-padded ascii number in base 10, telling the size of the message body,
which follows directly after the header.

## Example program

To demonstrate, the following rc script connects to `wss://echo.websocket.org` which is a service that echos everything
back to the user.

	#!/bin/rc
	
	rfork en
	
	webfs
	
	fn sendtextmsg{
		awk 'BEGIN{printf "t %0.20d%s", length(ARGV[1]), ARGV[1]}' $1 >[1=0]
	}
	
	fn readheader{
		header=`{read -c 22}
		length=`{echo $header(2) p | dc}
		echo $header(1) $length
	}
	
	fn handlemsg{
		echo Handling message:
		echo '	TYPE  :' $1
		echo '	LENGTH:' $2
		echo '	BODY  :' $3
	}
	
	<>/mnt/web/clone {
		d=/mnt/web/^`{sed 1q}
	
		echo url wss://echo.websocket.org >[1=0]
	
		<>$d/body {
			read -n 1 # Read the ready message
	
			sendtextmsg 'First message sent'
			while(header=`{readheader}){
				echo Header: $header
				body=`''{read -c $header(2)}
				handlemsg $header(1) $header(2) $body
				sleep 2
				sendtextmsg 'Echo test'
			}
		}
	}

## Bugs

Yes. The code doesn't really handle errors or connection shutdowns yet. Also, I need to add proper cleanup code
around in different places.