package main import ( "bufio" "fmt" "io" "log" "os" "github.com/cjdenio/crossword/game" "github.com/cjdenio/crossword/puz" "github.com/gliderlabs/ssh" ) func main() { file, err := os.ReadFile(os.Args[1]) if err != nil { log.Fatal(err) } port := ":2222" if portEnv, ok := os.LookupEnv("PORT"); ok && portEnv != "" { port = ":" + portEnv } ssh.Handle(func(s ssh.Session) { log.Printf("new connection from %s (username %s)\n", s.RemoteAddr().String(), s.User()) puzzle, err := puz.ParsePuz(file) if err != nil { log.Fatal(err) } state := game.NewState(puzzle) io.WriteString(s, "\x1b[?25l") defer func() { io.WriteString(s, "\x1b[?25h") }() pty, _, _ := s.Pty() // TODO: actually handle terminal size changes uiHeight := state.RenderUI(s, pty.Window.Width) scanner := bufio.NewScanner(s) scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { if len(data) == 0 { return 0, nil, bufio.ErrFinalToken } if data[0] == 0x1b { if len(data) < 3 { return 0, nil, nil } return 3, data[0:3], nil } return 1, data[0:1], nil }) for { ok := scanner.Scan() if !ok { break } buffer := scanner.Bytes() exited := state.HandleInput(buffer) if exited { state.SelectedClue = nil state.SelectedCell = -1 fmt.Fprintf(s, "\r\x1b[%dA", uiHeight) fmt.Fprint(s, "\x1b[J") state.RenderUI(s, pty.Window.Width) break } fmt.Fprintf(s, "\r\x1b[%dA", uiHeight) fmt.Fprint(s, "\x1b[J") uiHeight = state.RenderUI(s, pty.Window.Width) } log.Printf("%s disconnected\n", s.RemoteAddr().String()) }) log.Printf("starting on port %s...\n", port) log.Fatal(ssh.ListenAndServe(port, nil)) }