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" | ||||
| @ -42,13 +41,13 @@ type ConfMailer struct { | ||||
| // So we can peek at net.Conn, which we can't do natively | ||||
| // 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 | ||||
| 	r *bufio.Reader | ||||
| 	//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) | ||||
| 	} | ||||
| 	/* | ||||
| 		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