diff --git a/README.md b/README.md index 5e86475ffb91c13d22b63a641ffd9a994845455a..ffd25644ee18a47274a0bef9e46f071f11212337 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This repository contains a number of client under the `cmd` directory. Currently, these are: - **abhelp**: Request help +- **abcli**: Handle requests in a queue Meta ---- @@ -20,3 +21,4 @@ the FAU CS [GitLab][gitlab]. [ab]: https://github.com/noctux/adora-belle [go]: https://golang.org/ [license]: ./LICENSE +[gitlab]: https://gitlab.cs.fau.de/oj14ozun/ablib diff --git a/cmd/abcli/cli.go b/cmd/abcli/cli.go new file mode 100644 index 0000000000000000000000000000000000000000..5dd44b5488a5134ef13f44ddc9e88a57f29845ce --- /dev/null +++ b/cmd/abcli/cli.go @@ -0,0 +1,104 @@ +package main + +import ( + "ablib" + "fmt" + "os" + "sync" + + "golang.org/x/crypto/ssh/terminal" +) + +type cmd struct { + cmd ablib.Command + data string + arg string +} +type cli struct { + sync.Mutex + u string + q []*ablib.Request + c chan *cmd +} + +func (c *cli) interaction() { + var ( + r *ablib.Request + char byte + verb string + ) + + old, err := terminal.MakeRaw(0) + if err != nil { + panic(err) + } + + for { + fmt.Scanf("%c", &char) + switch char { + case 'q', 0x3: + c.Lock() + terminal.Restore(0, old) + os.Exit(0) + case 'd', ' ': + verb = "Discard" + case 'h', '\r': + verb = "Handle" + } + + c.Lock() + r = c.q[0] + c.q = c.q[1:] + c.Unlock() + c.c <- &cmd{ablib.Handle, r.ID, verb} + } +} + +func (c *cli) HandleError(err error) { + fmt.Fprintf(os.Stderr, "ERROR: %s", err) +} + +func (c *cli) OnRequest(r *ablib.Request, handled string) { + if handled != "" { + return + } + + c.Lock() + defer c.Unlock() + c.q = append(c.q, r) + + fmt.Printf("% 4d: new \"%s\" request by %s (%s)\n", + len(c.q), r.Type, r.User, r.ID) +} + +func (c *cli) OnAction(a *ablib.Action) { + // remove request from queue + c.Lock() + defer c.Unlock() + k := -1 + for i, r := range c.q { + if r == a.Request { + k = i + break + } + } + if k != -1 { + // from https://github.com/golang/go/wiki/SliceTricks + copy(c.q[k:], c.q[k+1:]) + c.q[len(c.q)-1] = nil + c.q = c.q[:len(c.q)-1] + } + + if a.Name == c.u { + fmt.Printf("% 4d: handling %s: %s\n", + len(c.q), a.Request.ID, a.Request.Room) + } else { + fmt.Printf("% 4d: request %s handled by %s\n", + len(c.q), a.Request.ID, a.Name) + } +} + +func (c *cli) Listen() (ablib.Command, string, string, error) { + cmd := <-c.c + return cmd.cmd, cmd.data, cmd.arg, nil +} diff --git a/cmd/abcli/main.go b/cmd/abcli/main.go new file mode 100644 index 0000000000000000000000000000000000000000..0823972d887a922a713075da06dd17c56b4d2e23 --- /dev/null +++ b/cmd/abcli/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "ablib" + "flag" + "fmt" + "os" + "time" +) + +const usage = "Usage: %s [options] [help|serve|request]" + +func main() { + var ( + interval uint + user, pass, class string + ) + + // parse flags + flag.UintVar(&interval, "interval", 10, "interval in seconds between re-query") + flag.StringVar(&class, "class", os.Getenv("AB_CLASS"), "name of class") + flag.StringVar(&user, "user", os.Getenv("AB_USER"), "") + flag.StringVar(&pass, "pass", os.Getenv("AB_PASS"), "") + flag.Parse() + + // set up api + api := ablib.API{ + Interval: time.Duration(interval) * time.Second, + User: user, + Pass: pass, + } + + if !api.SetupClass(class) { + fmt.Fprintln(os.Stderr, "Unknown class name \"%s\"", class) + os.Exit(1) + } + + // start ui loop + ui := &cli{u: user, c: make(chan *cmd)} + go ui.interaction() + if err := api.Run(ui); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +}