From a80457578e93a90804e7b3ce4e9662603d72c833 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Sun, 29 Aug 2021 19:56:01 -0700 Subject: [PATCH] [#73] Minimum nonviable product for Riju CLI Just for fun --- Makefile | 6 +++ cli/compile.bash | 16 ++++++++ cli/go.mod | 8 ++++ cli/go.sum | 14 +++++++ cli/src/main.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+) create mode 100755 cli/compile.bash create mode 100644 cli/go.mod create mode 100644 cli/go.sum create mode 100644 cli/src/main.go diff --git a/Makefile b/Makefile index f0ca2ee..a6400eb 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,12 @@ supervisor: # Compile supervisor binary for production supervisor-dev: # Compile and watch supervisor binary for development watchexec -w supervisor/src -n -- ./supervisor/compile.bash +cli: # Compile cli binary for production + ./cli/compile.bash + +cli-dev: # Compile and watch cli binary for development + watchexec -w cli/src -n -- ./cli/compile.bash + server: # Run server for production node backend/server.js diff --git a/cli/compile.bash b/cli/compile.bash new file mode 100755 index 0000000..f9424b8 --- /dev/null +++ b/cli/compile.bash @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +function verbosely { + echo "$@" + "$@" +} + +cd cli +mkdir -p build/go out + +export GOCACHE="$PWD/build/go/cache" +export GOMODCACHE="$PWD/build/go/mod" + +verbosely go build -o out/riju ./src diff --git a/cli/go.mod b/cli/go.mod new file mode 100644 index 0000000..3e7656a --- /dev/null +++ b/cli/go.mod @@ -0,0 +1,8 @@ +module github.com/raxod502/riju/cli + +go 1.16 + +require ( + github.com/alecthomas/kong v0.2.17 // indirect + github.com/gorilla/websocket v1.4.2 // indirect +) diff --git a/cli/go.sum b/cli/go.sum new file mode 100644 index 0000000..58e9275 --- /dev/null +++ b/cli/go.sum @@ -0,0 +1,14 @@ +github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0= +github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cli/src/main.go b/cli/src/main.go new file mode 100644 index 0000000..479db5d --- /dev/null +++ b/cli/src/main.go @@ -0,0 +1,96 @@ +package main + +// Based in part on +// https://github.com/gorilla/websocket/blob/master/examples/echo/client.go + +import ( + "encoding/json" + "fmt" + "log" + "net/url" + "path" + + "github.com/alecthomas/kong" + "github.com/gorilla/websocket" +) + +var cli struct { + Lang string `arg help:"Name of programming language."` + File string `arg optional type:"path" help:"File to run."` + Host string `default:"https://riju.codes/api/v1" help:"URL of Riju API."` +} + +type message struct { + Event string `json:"event"` +} + +type terminalInput struct { + message + Input string `json:"input"` +} + +type terminalOutput struct { + message + Output string `json:"output"` +} + +func run() error { + apiUrl, err := url.Parse(cli.Host) + if err != nil { + return err + } + scheme := "wss" + if apiUrl.Scheme == "http" { + scheme = "ws" + } + socketUrl := url.URL{ + Scheme: scheme, + Host: apiUrl.Host, + Path: path.Join(apiUrl.Path, "ws"), + RawQuery: url.Values{ + "lang": []string{cli.Lang}, + }.Encode(), + } + conn, _, err := websocket.DefaultDialer.Dial(socketUrl.String(), nil) + if err != nil { + return err + } + defer conn.Close() + done := make(chan struct{}) + go func() { + defer close(done) + for { + _, rawMsg, err := conn.ReadMessage() + if err != nil { + log.Println("failed to read websocket message:", err) + return + } + var genericMsg message + if err := json.Unmarshal(rawMsg, &genericMsg); err != nil { + log.Println("failed to parse websocket message:", err) + } + switch genericMsg.Event { + case "terminalOutput": + var msg terminalOutput + if err := json.Unmarshal(rawMsg, &msg); err != nil { + log.Println("failed to parse websocket message:", err) + } + fmt.Print(msg.Output) + } + } + }() + for { + select { + case <-done: + return nil + } + } + return nil +} + +func main() { + kong.Parse(&cli) + if err := run(); err != nil { + log.Fatalln(err) + } +}