Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1061dd4c71 | |||
| db15b22e40 | |||
| bfdabd1228 | |||
| ccf0f28da7 | |||
| c5100b35bf | |||
| 9c17248bfa | |||
| dd9fff02a1 |
24
README.md
24
README.md
@ -38,6 +38,28 @@ You can also use HTTP.
|
||||
curl http://localhost:4080
|
||||
```
|
||||
|
||||
## Testing Beyond Localhost
|
||||
|
||||
You can use [Telebit](https://telebit.cloud) to share the experience with friends and loved ones:
|
||||
|
||||
Completely userspace installation:
|
||||
|
||||
```
|
||||
curl -fsSL https://get.telebit.cloud | bash
|
||||
```
|
||||
|
||||
Easy configuration:
|
||||
|
||||
```
|
||||
~/telebit http 4080
|
||||
> Forwarding https://lucky-duck-42.telebit.fun => localhost:4080
|
||||
|
||||
~/telebit tcp 4080
|
||||
> Forwarding telebit.cloud:1234 => localhost:4080
|
||||
```
|
||||
|
||||
Caveat: Due to a bug in telebit you must send 'hello' in telnet to establish a connection.
|
||||
|
||||
# API Docs
|
||||
|
||||
The API docs and examples can be seen at <http://localhost:4080>
|
||||
@ -93,7 +115,7 @@ Not Implemented
|
||||
|
||||
I don't think these things would be difficult to add,
|
||||
but I was having fun learning lots of other things
|
||||
and I figured Some of these things I didn't implement
|
||||
and I figured they're not that important.
|
||||
|
||||
* [ ] local log file
|
||||
* [ ] Rooms
|
||||
|
||||
@ -83,6 +83,7 @@ func handleTelnetConn(bufConn bufferedConn) {
|
||||
email = strings.TrimSpace(msg)
|
||||
emailParts := strings.Split(email, "@")
|
||||
if 2 != len(emailParts) {
|
||||
email = ""
|
||||
fmt.Fprintf(bufConn, "Email: ")
|
||||
continue
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -43,12 +42,12 @@ type ConfMailer struct {
|
||||
// https://stackoverflow.com/questions/51472020/how-to-get-the-size-of-available-tcp-data
|
||||
type bufferedConn struct {
|
||||
r *bufio.Reader
|
||||
rout io.Reader // See https://github.com/polvi/sni/blob/master/sni.go#L135
|
||||
//rout *io.Reader // See https://github.com/polvi/sni/blob/master/sni.go#L135
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func newBufferedConn(c net.Conn) bufferedConn {
|
||||
return bufferedConn{bufio.NewReader(c), nil, c}
|
||||
return bufferedConn{bufio.NewReader(c), c}
|
||||
}
|
||||
|
||||
func (b bufferedConn) Peek(n int) ([]byte, error) {
|
||||
@ -60,9 +59,11 @@ func (b bufferedConn) Buffered() int {
|
||||
}
|
||||
|
||||
func (b bufferedConn) Read(p []byte) (int, error) {
|
||||
/*
|
||||
if b.rout != nil {
|
||||
return b.rout.Read(p)
|
||||
}
|
||||
*/
|
||||
return b.r.Read(p)
|
||||
}
|
||||
|
||||
@ -91,7 +92,7 @@ var broadcastMsg chan chatMsg
|
||||
// Telnet
|
||||
var wantsServerHello chan bufferedConn
|
||||
var authTelnet chan telnetUser
|
||||
var cleanTelnet chan telnetUser
|
||||
var cleanTelnet chan telnetUser // intentionally blocking
|
||||
|
||||
// HTTP
|
||||
var demuxHttpClient chan bufferedConn
|
||||
@ -100,7 +101,7 @@ var valAuthReqs chan authReq
|
||||
var delAuthReqs chan authReq
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "\nusage: go run chatserver.go\n")
|
||||
fmt.Fprintf(os.Stderr, "\nusage: go run chatserver*.go\n")
|
||||
flag.PrintDefaults()
|
||||
fmt.Println()
|
||||
|
||||
@ -166,6 +167,9 @@ func muxTcp(conn bufferedConn) {
|
||||
}
|
||||
|
||||
if "" == protocol {
|
||||
// Throw away the first bytes
|
||||
b := make([]byte, 4096)
|
||||
conn.Read(b)
|
||||
fmt.Fprintf(conn, "\n\nWelcome to Sample Chat! You're not an HTTP client, assuming Telnet.\nYou must authenticate via email to participate\n\nEmail: ")
|
||||
wantsServerHello <- conn
|
||||
return
|
||||
@ -297,7 +301,7 @@ func main() {
|
||||
virginConns = make(chan net.Conn, 128)
|
||||
|
||||
// TCP & Authentication
|
||||
telnetConns := make(map[bufferedConn]telnetUser)
|
||||
telnetConns := make(map[string]telnetUser)
|
||||
wantsServerHello = make(chan bufferedConn, 128)
|
||||
authTelnet = make(chan telnetUser, 128)
|
||||
|
||||
@ -385,7 +389,12 @@ func main() {
|
||||
case u := <-authTelnet:
|
||||
// allow to receive messages
|
||||
// (and be counted among the users)
|
||||
telnetConns[u.bufConn] = u
|
||||
_, ok := telnetConns[u.email]
|
||||
if ok {
|
||||
// this is a blocking channel, and that's important
|
||||
cleanTelnet <- telnetConns[u.email]
|
||||
}
|
||||
telnetConns[u.email] = u
|
||||
// is chan chan the right way to handle this?
|
||||
u.userCount <- len(telnetConns)
|
||||
broadcastMsg <- chatMsg{
|
||||
@ -418,7 +427,7 @@ func main() {
|
||||
close(u.newMsg)
|
||||
// we can safely ignore this error, if any
|
||||
u.bufConn.Close()
|
||||
delete(telnetConns, u.bufConn)
|
||||
delete(telnetConns, u.email)
|
||||
case bufConn := <-gotClientHello:
|
||||
go muxTcp(bufConn)
|
||||
case bufConn := <-demuxHttpClient:
|
||||
|
||||
@ -1,26 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Sample Chat</title></head>
|
||||
<head><title>API Docs</title></head>
|
||||
<body>
|
||||
<h1>Sample Chat - API Docs</h1>
|
||||
|
||||
|
||||
<h2>Login</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<h3>POST /api/sessions
|
||||
<br>
|
||||
<code>{"sub":"<strong><em><email></em></strong>"}</code>
|
||||
</h3>
|
||||
<pre><code># Ask for an auth code (swap sub)
|
||||
|
||||
curl -X POST http://localhost:4080/api/sessions \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{"sub":"<strong><em>jon@example.com</em></strong>"}'
|
||||
</code></pre>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<h3>POST /api/sessions/<strong><em><id></em></strong>
|
||||
<br>
|
||||
<code>{"otp":"<strong><em><auth-code></em></strong>"}</code>
|
||||
</h3>
|
||||
<pre><code># Validate auth code (swap session id, sub, and otp)
|
||||
|
||||
# Validate auth code (swap session id, sub, and otp)
|
||||
curl -X POST http://localhost:4080/api/sessions/<strong><em>xyz</em></strong> \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{"otp":"<strong><em>secret123</em></strong>"}'
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Messages</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<h3>POST /api/rooms/general
|
||||
<br>
|
||||
<code>Authorization: Bearer <strong><em><api-token></em></strong>
|
||||
<br>{"message":"<strong><em><msg></em></strong>"}</code>
|
||||
</h3>
|
||||
<pre><code># Post a message (swap api-token)
|
||||
|
||||
# Post a message (swap api-token)
|
||||
curl -X POST http://localhost:4080/api/rooms/general \
|
||||
-H 'Authorization: Bearer <strong><em>api-token</em></strong>' \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{"message":"Hello, World!"}'
|
||||
</code></pre>
|
||||
</li>
|
||||
|
||||
# Get a room's messages (swap api-token, since unix-epoch)
|
||||
curl http://localhost:4080/api/rooms/general?since=0 \
|
||||
<li>
|
||||
<h3>GET /api/rooms/general
|
||||
<br>
|
||||
<code>Authorization: Bearer <strong><em><api-token></em></strong></code>
|
||||
</h3>
|
||||
<pre><code># Get a room's messages (swap api-token, since unix-epoch)
|
||||
|
||||
curl http://localhost:4080/api/rooms/general \
|
||||
-H 'Authorization: Bearer <strong><em>api-token</em></strong>'
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user