diff --git a/chatserver.go b/chatserver.go index addbf84..b2d063f 100644 --- a/chatserver.go +++ b/chatserver.go @@ -1,7 +1,7 @@ package main -// Lot's of learning right out of the gate: -// https://stackoverflow.com/questions/51472020/how-to-get-the-size-of-available-tcp-data +// TODO learn about chan chan's +// http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/ import ( "bufio" @@ -23,16 +23,21 @@ import ( "gopkg.in/yaml.v2" ) +// I'm not sure how to pass nested structs, so I de-nested this. +// TODO: Learn if passing nested structs is desirable? +type Conf struct { + Port uint `yaml:"port,omitempty"` + Mailer ConfMailer +} type ConfMailer struct { Url string `yaml:"url,omitempty"` ApiKey string `yaml:"api_key,omitempty"` From string `yaml:"from,omitempty"` } -type Conf struct { - Port uint `yaml:"port,omitempty"` - Mailer ConfMailer -} + +// 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 @@ -58,6 +63,8 @@ func (b bufferedConn) Read(p []byte) (int, error) { return b.r.Read(p) } +// Just making these all globals right now +// because... I can clean it up later type myMsg struct { sender net.Conn bytes []byte @@ -67,10 +74,14 @@ type myMsg struct { var firstMsgs chan myMsg var myChans map[string](chan myMsg) -//var myMsgs chan myMsg +var myMsgs chan myMsg var myUnsortedConns map[net.Conn]bool var myRawConns map[net.Conn]bool var newConns chan net.Conn +var newTcpChat chan bufferedConn +var delTcpChat chan bufferedConn +var newHttpChat chan bufferedConn +var delHttpChat chan bufferedConn func usage() { fmt.Fprintf(os.Stderr, "\nusage: go run chatserver.go\n") @@ -115,8 +126,7 @@ func handleRaw(conn bufferedConn) { fmt.Fprintf(os.Stdout, "Ending socket\n") // TODO put this in a channel to prevent data races - conn.Close(); - delete(myRawConns, conn) + delTcpChat <- conn break } buf := buffer[:count] @@ -160,7 +170,8 @@ func handleRaw(conn bufferedConn) { } fmt.Fprintf(os.Stdout, "Queing message...\n"); - myChans["general"] <- myMsg{ + //myChans["general"] <- myMsg{ + myMsgs <- myMsg{ receivedAt: time.Now(), sender: conn, bytes: buf[0:count], @@ -207,7 +218,8 @@ func handleSorted(conn bufferedConn) { // fmt.Fprintf(os.Stdout, "Weird") continue } - myChans["general"] <- myMsg{ + //myChans["general"] <- myMsg{ + myMsgs <- myMsg{ receivedAt: time.Now(), sender: conn, bytes: buf[0:count], @@ -241,11 +253,10 @@ func handleConnection(netConn net.Conn) { m.Lock(); if virgin { virgin = false - go handleSorted(bufConn) + newHttpChat <- bufConn } else { // TODO probably needs to go into a channel - myRawConns[bufConn] = true - go handleRaw(bufConn) + newTcpChat <- bufConn } m.Unlock(); }() @@ -327,15 +338,17 @@ func main() { } firstMsgs = make(chan myMsg, 128) - //myMsgs = make(chan myMsg, 128) myChans = make(map[string](chan myMsg)) newConns = make(chan net.Conn, 128) + newTcpChat = make(chan bufferedConn, 128) + newHttpChat = make(chan bufferedConn, 128) myRawConns = make(map[net.Conn]bool) myUnsortedConns = make(map[net.Conn]bool) // TODO dynamically select on channels? // https://stackoverflow.com/questions/19992334/how-to-listen-to-n-channels-dynamic-select-statement - myChans["general"] = make(chan myMsg, 128) + //myChans["general"] = make(chan myMsg, 128) + myMsgs = make(chan myMsg, 128) var addr string if 0 != int(*port) { @@ -369,8 +382,19 @@ func main() { case conn := <- newConns: ts := time.Now() fmt.Fprintf(os.Stdout, "[Handle New Connection] [Timestamp] %s\n", ts) + // This is short lived go handleConnection(conn) - case msg := <- myChans["general"]: + case bufConn := <- newTcpChat: + myRawConns[bufConn] = true + go handleRaw(bufConn) + case bufConn := <- newHttpChat: + go handleSorted(bufConn) + case bufConn := <- delHttpChat: + bufConn.Close(); + delete(myRawConns, bufConn) + //case msg := <- myChans["general"]: + //delete(myChans["general"], bufConn) + case msg := <- myMsgs: ts, err := msg.receivedAt.MarshalJSON() if nil != err { fmt.Fprintf(os.Stderr, "[Error] %s\n", err)