diff options
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/metronode/main.go | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/cmd/metronode/main.go b/cmd/metronode/main.go index b7edd63..31cd8e5 100644 --- a/cmd/metronode/main.go +++ b/cmd/metronode/main.go @@ -1,12 +1,18 @@ package main import ( + "os" "net" "log" + "bufio" + "strings" + "sync/atomic" + "golang.org/x/term" "git.citrons.xyz/metronode/server" ) func main() { + defer os.Exit(0) s := server.NewServer(server.ServerInfo { Name: "Metronode", Motd: "hello, world", @@ -15,5 +21,111 @@ func main() { if err != nil { log.Fatal(err) } + + cons := initConsole() + defer cons.Close() + log.SetOutput(&cons) + go readConsole(s, &cons) + s.Serve(ln) } + +func readConsole(s *server.Server, cons *console) { + rd := bufio.NewReader(cons) + for { + line, err := rd.ReadString('\r') + if line == "" { + continue + } + if len(line) > 0 { + line = line[:len(line) - 1] + } + cons.Write([]byte("> " + line + "\n")) + if err != nil { + return + } + s.ExecuteCommand(cons, server.ConsoleAuth, line) + } +} + +type console struct { + input atomic.Pointer[string] + termState *term.State +} + +func initConsole() console { + var (c console; input string) + c.input.Store(&input) + c.termState, _ = term.MakeRaw(int(os.Stdin.Fd())) + c.showInput() + return c +} + +func (c *console) Close() error { + term.Restore(int(os.Stdin.Fd()), c.termState) + os.Stdout.Write([]byte("\n")) + return nil +} + +func (c *console) Read(p []byte) (n int, err error) { + n, err = os.Stdin.Read(p) + if err != nil { + return + } + var sb strings.Builder + for _, c := range p[:n] { + if c == '\r' { + c = '\n' + } + if c >= 32 || c == '\n' { + sb.WriteByte(c) + } + } + s := sb.String() + newline := strings.LastIndex(s, "\n") + if newline != -1 { + s = s[newline + 1:] + c.input.Store(&s) + } else { + s = *c.input.Load() + s + c.input.Store(&s) + } + c.Write([]byte{}) + return +} + +func (c *console) showInput() { + s := "\0337" // save cursor position + w, _, _ := term.GetSize(int(os.Stdout.Fd())) + s = s + strings.Repeat(" ", w) + s = s + "\0338" // restore + s = s + "\0337" // save + s = s + "> " + *c.input.Load() + os.Stdout.Write([]byte(s)) +} + +func (c *console) Write(p []byte) (n int, err error) { + s := "\0338" // restore cursor position + s = s + "\033[0J" // erase until end of screen + s = s + strings.Replace(string(p), "\n", "\r\n", -1) + n, err = os.Stdout.Write([]byte(s)) + n = max(0, n - (len(s) - len(p))) + c.showInput() + return +} + +func (c *console) OnCommandOutput(from *server.Server, output string) { + s := "\033[33m" // yellow + s = s + output + s = s + "\033[0m" // reset + s = s + "\r\n" + c.Write([]byte(s)) +} + +func (c *console) OnCommandError(from *server.Server, err string) { + s := "\033[31m" // red + s = s + err + s = s + "\033[0m" // reset + s = s + "\r\n" + c.Write([]byte(s)) +} |
