summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/metronode/main.go112
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))
+}