diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c7b5ef1 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/xtaci/gaio v1.2.9 h1:EuVc7Q2JDzIY2mk5mjtq4K5BgTuO+kj5LXzCwjOK+mo= +github.com/xtaci/gaio v1.2.9/go.mod h1:rJMerwiLCLnKa14YTM/sRggTPrnBZrlCg9U3DnV5VBE= diff --git a/main.go b/main.go index 99fc749..db71819 100644 --- a/main.go +++ b/main.go @@ -1,13 +1,11 @@ package main import ( - "bufio" "flag" - "io" "log" "net" - "os/exec" "strconv" + "strings" "sync" "time" @@ -38,108 +36,190 @@ func main() { log.Panicln(err) } - log.Println("new client", conn.RemoteAddr()) - - // set up io channel for this connection - chIO := make(chan gaio.OpResult) + log.Println("new client: ", conn.RemoteAddr()) // submit the first async write IO request - err = (chIO, conn, welcomeHandler()) + err = w.Write(nil, conn, welcomeHandler()) if err != nil { - log.Printf("err sending welcomeHandler: %v\n", err) + log.Printf("err sending welcomeHandler: %v\n", err) return } // hand off channel to menuHandler - menuHandler(chIO, conn, *w) + // menuHandler(w, conn) + wg := new(sync.WaitGroup) + + // chan to terminate watcher goroutine when necessary + WatcherControl := make(chan string) + + // watcher.WaitIO goroutine + wg.Add(1) + go func(WatcherControl *chan string) { + log.Println("starting menu watchercontrol") + defer wg.Done() + ControlLoop: + for { + log.Println("checking watcher waitio") + select { + case msg := <-*WatcherControl: + if msg == "stop" { + log.Println("closing menu watchercontrol") + break ControlLoop + } + default: + log.Println("menu watchercontrol waiting for IO") + inBuf := make([]byte, 256) + err := w.ReadTimeout(nil, conn, inBuf, time.Now().Add(time.Second)) + if err != nil { + log.Printf("err on watcher readtimeout in menu: %v\n", err) + continue + } + results, err := w.WaitIO() + if err != nil { + log.Println("watcher wait err: ", err) + continue + } + + log.Println("menu received IO!") + for _, res := range results { + if res.Operation == gaio.OpRead && res.Size > 0 { + log.Println("menu receive: ", strings.TrimSpace(string(res.Buffer[:res.Size-2]))) + switch string(strings.TrimSpace(string(res.Buffer[:res.Size-2]))) { + case "welcome": + if err := w.Write(nil, conn, welcomeHandler()); err != nil { + log.Printf("error sending welcomeHandler from cmd `welcome`: %v", err) + } + case "adventure": + // start the door and wait + log.Printf("starting door handler...") + /* + if err := doorHandler(&c); err != nil { + log.Printf("error from cmd `adventure`: %v", err) + } + log.Printf("returning from door") + n, err := c.Write([]byte("\n\n> ")) + if err != nil { + log.Printf("error writing to connection: %v", err) + } else { + log.Printf("wrote %d byte prompt to connection", n) + } + */ + case "exit": + /* + if err := exitHandler(); err != nil { + log.Printf("error sending exitHandler from cmd `exit`: %v", err) + } + */ + default: + err := w.Write(nil, conn, []byte("huh?\n\n> ")) + if err != nil { + log.Printf("error writing to connection: %v", err) + } + } + } else { + log.Println("watcher confirming write:", string(res.Buffer)) + } + } + } + time.Sleep(time.Second) + } + log.Println("watcher controlloop closed!") + }(&WatcherControl) + log.Println("main thread waiting on wg") + wg.Wait() + log.Printf("Goodbye %s!", conn.RemoteAddr()) } } -func menuHandler(chIO chan gaio.OpResult, c net.Conn, w gaio.Watcher) { - log.Printf("Connection received: %s", c.RemoteAddr()) - - // watcher.WaitIO goroutine - go func() { - for { - results, err := w.WaitIO() - if err != nil { - log.Println(err) - return - } - - for _, res := range results { - chIO <- res - } - } - }() - - // send welcome banner - if err := welcomeHandler(&c); err != nil { - log.Printf("error sending welcomeHandler on initial connect: %v", err) - } - +func menuHandler(w *gaio.Watcher, c net.Conn) { wg := new(sync.WaitGroup) + // chan to terminate watcher goroutine when necessary + WatcherControl := make(chan string) + + // watcher.WaitIO goroutine wg.Add(1) - go func() { + go func(WatcherControl *chan string) { + log.Println("starting menu watchercontrol") defer wg.Done() - scanner := bufio.NewScanner(c) - scanner.Split(bufio.ScanLines) - - for scanner.Scan() { - line := scanner.Bytes() - - log.Printf("Menu received line: %v (%v)", line, string(line)) - switch string(line) { - case "welcome": - if err := welcomeHandler(&c); err != nil { - log.Printf("error sending welcomeHandler from cmd `welcome`: %v", err) - } - case "adventure": - // start the door and wait - log.Printf("starting door handler...") - if err := doorHandler(&c); err != nil { - log.Printf("error from cmd `adventure`: %v", err) - } - log.Printf("returning from door") - n, err := c.Write([]byte("\n\n> ")) - if err != nil { - log.Printf("error writing to connection: %v", err) - } else { - log.Printf("wrote %d byte prompt to connection", n) - } - case "exit": - if err := exitHandler(c); err != nil { - log.Printf("error sending exitHandler from cmd `exit`: %v", err) + ControlLoop: + for { + log.Println("checking watcher waitio") + select { + case msg := <-*WatcherControl: + if msg == "stop" { + log.Println("closing menu watchercontrol") + break ControlLoop } default: - n, err := c.Write([]byte("huh?\n\n> ")) + log.Println("menu watchercontrol waiting for IO") + results, err := w.WaitIO() if err != nil { - log.Printf("error writing to connection: %v", err) - } else { - log.Printf("wrote %d bytes to connection", n) + log.Println(err) + return + } + + log.Println("menu received IO!") + for _, res := range results { + if res.Operation == gaio.OpRead { + log.Println("menu receive: ", string(res.Buffer)) + switch string(res.Buffer) { + case "": + // noop + case "welcome": + if err := w.Write(nil, c, welcomeHandler()); err != nil { + log.Printf("error sending welcomeHandler from cmd `welcome`: %v", err) + } + case "adventure": + // start the door and wait + log.Printf("starting door handler...") + /* + if err := doorHandler(&c); err != nil { + log.Printf("error from cmd `adventure`: %v", err) + } + log.Printf("returning from door") + n, err := c.Write([]byte("\n\n> ")) + if err != nil { + log.Printf("error writing to connection: %v", err) + } else { + log.Printf("wrote %d byte prompt to connection", n) + } + */ + case "exit": + /* + if err := exitHandler(); err != nil { + log.Printf("error sending exitHandler from cmd `exit`: %v", err) + } + */ + default: + err := w.Write(nil, c, []byte("huh?\n\n> ")) + if err != nil { + log.Printf("error writing to connection: %v", err) + } + } + } else { + log.Println("watcher confirming write:", string(res.Buffer)) + } } } + time.Sleep(time.Second) } - }() - - time.Sleep(time.Millisecond) + log.Println("watcher controlloop closed!") + }(&WatcherControl) + log.Println("main thread waiting on wg") wg.Wait() log.Printf("Goodbye %s!", c.RemoteAddr()) } -func sendClientText(c net.Conn, s string) error { - n, err := c.Write([]byte(s)) - if err != nil { // svr.ListenAndServe() - +func sendClientText(w *gaio.Watcher, c net.Conn, s string) error { + err := w.Write(nil, c, []byte(s)) + if err != nil { log.Printf("error writing to connection: %v", err) return err - } else { - log.Printf("wrote %d bytes to connection", n) } return nil } -func welcomeHandler(c *net.Conn) error { +func welcomeHandler() []byte { const bannerText = "\x1b[2J\x1b[H\x1b[31m\x1b[J\r\n" + ` _ __ _ ` + "" + ` @@ -163,21 +243,21 @@ func welcomeHandler(c *net.Conn) error { ___/ / /_/ /_/ / /_/ / / /_/ (__ ) ` + "" + ` /____/\__/\__,_/\__,_/_/\____/____/ ` + "\x1b[32m\r\n\r\n\r\n" + ` Help is available: type help` + "\r\n\r\n> " - err := sendClientText(*c, bannerText) - if err != nil { - log.Printf("error writing to connection: %v", err) - } - return nil + + return []byte(bannerText) } +/* + + func exitHandler(c net.Conn) error { const exitMessage = "\x1b[2J\x1b[H\x1b[31m\x1b[J\r\n" + ` - ___| | | - \___ \ _ \ _ \ | | _ \ | | __| __ \ _' | __| _ \ __| _ \\ \ \ / __ \ _ \ | | | - | __/ __/ | | ( | | | \__ \ | | ( | ( __/ ( ( |\ \ \ / | | ( | | |_| - _____/ \___|\___| \__, |\___/ \__,_| ) ____/ .__/ \__,_|\___|\___| \___|\___/ \_/\_/ _.__/ \___/ \__, |_) - ____/ / _| ____/ + ___| | | + \___ \ _ \ _ \ | | _ \ | | __| __ \ _' | __| _ \ __| _ \\ \ \ / __ \ _ \ | | | + | __/ __/ | | ( | | | \__ \ | | ( | ( __/ ( ( |\ \ \ / | | ( | | |_| + _____/ \___|\___| \__, |\___/ \__,_| ) ____/ .__/ \__,_|\___|\___| \___|\___/ \_/\_/ _.__/ \___/ \__, |_) + ____/ / _| ____/ ` @@ -258,3 +338,4 @@ func doorHandler(c *net.Conn) error { } return nil } +*/