]> 91.132.146.200 Git - scientia.git/commitdiff
starting fresh with the go client
authorBanana <mail@bananas-playground.net>
Sun, 16 Jun 2024 12:47:18 +0000 (14:47 +0200)
committerBanana <mail@bananas-playground.net>
Sun, 16 Jun 2024 12:47:18 +0000 (14:47 +0200)
Signed-off-by: Banana <mail@bananas-playground.net>
20 files changed:
CHANGELOG
client/go-cli/Makefile [deleted file]
client/go-cli/README.md [deleted file]
client/go-cli/go.mod [deleted file]
client/go-cli/go.sum [deleted file]
client/go-cli/scientia-cli.go [deleted file]
client/go-cli/scientia/Makefile [new file with mode: 0644]
client/go-cli/scientia/cmd/config.go [new file with mode: 0644]
client/go-cli/scientia/cmd/config_init.go [new file with mode: 0644]
client/go-cli/scientia/cmd/root.go [new file with mode: 0644]
client/go-cli/scientia/go.mod [new file with mode: 0644]
client/go-cli/scientia/go.sum [new file with mode: 0644]
client/go-cli/scientia/lib/helpers.go [new file with mode: 0644]
client/go-cli/scientia/main.go [new file with mode: 0644]
client/go-cli/scientia/scientia [new file with mode: 0755]
client/go-cli_/Makefile [new file with mode: 0644]
client/go-cli_/README.md [new file with mode: 0644]
client/go-cli_/go.mod [new file with mode: 0644]
client/go-cli_/go.sum [new file with mode: 0644]
client/go-cli_/scientia-cli.go [new file with mode: 0644]

index 8ccc50718e673dcc76589cf5cabb8d398caae455..610a34172785d234964e182821232dab9e3c5ab8 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,5 @@
 1.x Atlas -
-       + i18n. See upgrade-from-1.0.txt for more details.
+       + i18n. See upgrade-from-1.0.md for more details.
        + PHP 8.1 stuff
        + Search
        + Updated clients. A cli client written in Go.
diff --git a/client/go-cli/Makefile b/client/go-cli/Makefile
deleted file mode 100644 (file)
index b8ab31a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-all:
-       @echo "Options are: build scientia-cli scientia-cli-linux-amd64 scientia-cli-windows-amd64 scientia-cli-darwin-amd64 clean buildall"
-
-scientia-cli:
-       @echo "Building for local os/arch..."
-       go build -o scientia-cli
-
-scientia-cli-linux-amd64:
-       @echo "Building for linux/amd64 arch..."
-       GOOS=linux GOARCH=amd64 go build -o scientia-cli-linux-amd64
-
-scientia-cli-windows-amd64:
-       @echo "Building for windows/amd64 arch..."
-       GOOS=windows GOARCH=amd64 go build -o scientia-cli-windows-amd64
-
-scientia-cli-darwin-amd64:
-       @echo "Building for macOS/amd64 arch..."
-       GOOS=darwin GOARCH=amd64 go build -o scientia-cli-darwin-amd64
-
-build:
-       @echo "Building for local os/arch..."
-       go build -o scientia-cli-`go env GOOS`-`go env GOARCH`
-
-buildall: scientia-cli-linux-amd64 scientia-cli-windows-amd64 scientia-cli-darwin-amd64
-       @echo "Building for linux/amd64, windows/amd64 and macOS/amd64 arch..."
-
-clean:
-       rm -f scientia-cli scientia-cli-darwin-amd64 scientia-cli-windows-amd64 scientia-cli-linux-amd64
\ No newline at end of file
diff --git a/client/go-cli/README.md b/client/go-cli/README.md
deleted file mode 100644 (file)
index 04ff93f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# scienta go cli client
-
-This is a terminal cli client written in go to be used with scientia
-https://://www.bananas-playground.net/projekt/scientia/
-
-!WARNING!
-This is a very simple, with limited experience written, go program.
-Use at own risk and feel free to improve.
-
-# Howto build
-
-Nothing special, just use the provided Makefile or directly 
-"go build -o scientia-cli" to use your current os/arch settings.
-
-# Usage
-
-At first usage you need to create the config and the individual secret.
-Run $scientia-cli -create-config-file to create the default config file.
-The path to the config file is printed.
-Change the host address and update your server it with the secret, which is randomly created.
-
-## Create
-
-Read from a file `$ scientia-cli file.txt` or piped `$ cat file.txt | scientia-cli`
-
-# Commandline arguments
-
-## Optinal
-
-+ `-create-config-file` Create default config file
-+ `-debug` Print debug infos
-+ `-verbose` Produce verbose output
diff --git a/client/go-cli/go.mod b/client/go-cli/go.mod
deleted file mode 100644 (file)
index 5a0b7ac..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-module scientia/go-client-cli
-
-go 1.20
-
-require gopkg.in/yaml.v2 v2.4.0
diff --git a/client/go-cli/go.sum b/client/go-cli/go.sum
deleted file mode 100644 (file)
index dd0bc19..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/client/go-cli/scientia-cli.go b/client/go-cli/scientia-cli.go
deleted file mode 100644 (file)
index cebde96..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-package main
-
-import (
-       "bytes"
-       "encoding/json"
-       "errors"
-       "flag"
-       "fmt"
-       "io"
-       "log"
-       "math/rand"
-       "net/http"
-       "os"
-
-       "gopkg.in/yaml.v2"
-)
-
-/**
- * scientia
- *
- * Copyright 2023 Johannes Keßler
- *
- * https://www.bananas-playground.net/projekt/scientia/
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
- *
- * You should have received a copy of the
- * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
- * along with this program.  If not, see http://www.sun.com/cddl/cddl.html
- */
-
-const website = "https://www.bananas-playground.net/projekt/scientia/"
-const version = "1.0"
-
-// used for non-existing default config
-const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
-
-// command line parameters
-var optsVerbose bool
-var optsCreateConfig bool
-var optsDebug bool
-
-// config
-var cfg Config
-
-// config file struct
-type Config struct {
-       Endpoint struct {
-               Host   string `yaml:"host"`
-               Secret string `yaml:"secret"`
-       } `yaml:"endpoint"`
-}
-
-// post json struct
-type PayloadJson struct {
-       Asl  string `json:"asl"`
-       Data string `json:"data"`
-}
-
-// response json struct
-type Response struct {
-       Message string `json:"message"`
-       Status  int    `json:"status"`
-}
-
-/**
- * Main
- */
-func main() {
-
-       // https://cli.urfave.org/v2/examples/arguments/
-       // https://github.com/dnote/dnote
-       //https://github.com/spf13/cobra/blob/main/site/content/user_guide.md
-
-       // parse commandline parameters
-       flag.BoolVar(&optsVerbose, "verbose", false, "Produce verbose output")
-       flag.BoolVar(&optsCreateConfig, "create-config-file", false, "Create default config file")
-       flag.BoolVar(&optsDebug, "debug", false, "Print debug infos")
-       flag.Parse()
-       if optsDebug {
-               fmt.Println("verbose:", optsVerbose)
-               fmt.Println("create-config-file:", optsCreateConfig)
-               fmt.Println("debug:", optsDebug)
-       }
-
-       // load the config and populate Config
-       loadConfig()
-
-       // get the payload
-       payload := getInput()
-       if optsDebug {
-               log.Println(payload)
-       }
-
-       // do the upload and get the response
-       responseString := uploadCall(payload)
-       response := Response{}
-       json.Unmarshal([]byte(responseString), &response)
-
-       // print the result and link to the pasty
-       fmt.Printf("Status: %d\n", response.Status)
-       fmt.Printf("Message: %s\n", response.Message)
-}
-
-/**
- * Check and display error with additional message
- */
-func errorCheck(e error, msg string) {
-       if e != nil {
-               log.Fatal(msg, " ; Errrormsg: ", e)
-       }
-}
-
-/**
- * just a random string
- */
-func randStringBytes(n int) string {
-       b := make([]byte, n)
-       for i := range b {
-               b[i] = letters[rand.Intn(len(letters))]
-       }
-       return string(b)
-}
-
-/**
- * load or even create a default config
- * $HOME/.scientia.yaml
- */
-func loadConfig() {
-       homeDir, err := os.UserHomeDir()
-       errorCheck(err, "No $HOME directory available?")
-       if optsVerbose {
-               log.Printf("Your $HOME: %s \n", homeDir)
-       }
-
-       var configFile = homeDir + "/.scientia.yaml"
-
-       if _, err := os.Stat(configFile); errors.Is(err, os.ErrNotExist) {
-               log.Printf("Config file not found: %s \n", configFile)
-
-               if optsCreateConfig {
-                       log.Printf("Creating new default config file: %s \n", configFile)
-
-                       newConfig, err := os.Create(configFile)
-                       errorCheck(err, "Can not create config file!")
-                       defer newConfig.Close()
-
-                       _, err = fmt.Fprintf(newConfig, "# scientia go client config file.\n")
-                       errorCheck(err, "Can not write to new config file")
-                       fmt.Fprintf(newConfig, "# See %s for more details.\n", website)
-                       fmt.Fprintf(newConfig, "# Version: %s\n", version)
-                       fmt.Fprintf(newConfig, "endpoint:\n")
-                       fmt.Fprintf(newConfig, "  host: http://your-scientia-endpoi.nt/api.php\n")
-                       fmt.Fprintf(newConfig, "  secret: %s\n", randStringBytes(50))
-
-                       log.Fatalf("New default config file created: - %s - Edit and launch again!", configFile)
-               }
-       }
-
-       existingConfigFile, err := os.Open(configFile)
-       errorCheck(err, "Can not open config file. Did you create one with -create-config-file?")
-       defer existingConfigFile.Close()
-       if optsVerbose {
-               log.Printf("Reading config file: %s \n", configFile)
-       }
-
-       var decoder = yaml.NewDecoder(existingConfigFile)
-       err = decoder.Decode(&cfg)
-       errorCheck(err, "Can not decode config file")
-
-       if cfg.Endpoint.Host == "" || cfg.Endpoint.Secret == "" {
-               log.Fatal("Empty config?")
-       }
-
-       if optsDebug {
-               log.Println(cfg.Endpoint.Host)
-               log.Println(cfg.Endpoint.Secret)
-       }
-}
-
-/**
- * Do a http POST call to the defined endpoint
- * and upload the payload
- * Return response body as string
- */
-func uploadCall(payload string) string {
-
-       if optsVerbose {
-               log.Println("Starting to upload data")
-       }
-       if optsDebug {
-               log.Println(payload)
-       }
-       if len(payload) == 0 {
-               log.Fatal("Nothing provided to upload")
-       }
-
-       payloadStruct := PayloadJson{
-               Asl:  cfg.Endpoint.Secret,
-               Data: payload,
-       }
-
-       jsonData, err := json.Marshal(payloadStruct)
-       errorCheck(err, "Can not create json payload")
-
-       req, err := http.NewRequest(http.MethodPost, cfg.Endpoint.Host, bytes.NewBuffer(jsonData))
-       errorCheck(err, "Can not create http request")
-       // We need to set the content type from the writer, it includes necessary boundary as well
-       req.Header.Set("Content-Type", "application/json; charset=UTF-8")
-       req.Header.Set("User-Agent", "scientiaAgent/1.0")
-
-       // Do the request
-       client := &http.Client{}
-       response, err := client.Do(req)
-       errorCheck(err, "POST request failed")
-
-       responseBody, err := io.ReadAll(response.Body)
-       errorCheck(err, "Can not read response body")
-
-       if optsVerbose {
-               log.Println("Request done")
-       }
-       if optsDebug {
-               log.Printf("Response status code: %d\n", response.StatusCode)
-               log.Printf("Response headers: %#v\n", response.Header)
-               log.Println(string(responseBody))
-       }
-
-       return string(responseBody)
-}
-
-/**
- * check if file is provided as commandline argument
- * or piped into
- * return the read data as string
- */
-func getInput() string {
-       if optsVerbose {
-               log.Println("Getting input")
-       }
-
-       var inputString string
-
-       if filename := flag.Arg(0); filename != "" {
-               if optsVerbose {
-                       log.Println("Read from file argument")
-               }
-
-               bytes, err := os.ReadFile(filename)
-               errorCheck(err, "Error opening file")
-               inputString = string(bytes)
-       } else {
-               stat, _ := os.Stdin.Stat()
-               if (stat.Mode() & os.ModeCharDevice) == 0 {
-                       if optsVerbose {
-                               log.Println("data is being piped")
-                       }
-
-                       bytes, _ := io.ReadAll(os.Stdin)
-                       inputString = string(bytes)
-               }
-       }
-
-       if len(inputString) == 0 {
-               log.Fatal("Nothing provided to upload")
-       }
-
-       return inputString
-}
diff --git a/client/go-cli/scientia/Makefile b/client/go-cli/scientia/Makefile
new file mode 100644 (file)
index 0000000..550711d
--- /dev/null
@@ -0,0 +1,11 @@
+all: scientia
+
+scientia:
+       @echo "Building for local os/arch..."
+       go build -o scientia
+       chmod u+x scientia
+
+devbuild: clean scientia
+
+clean:
+       rm -f scientia
diff --git a/client/go-cli/scientia/cmd/config.go b/client/go-cli/scientia/cmd/config.go
new file mode 100644 (file)
index 0000000..42ee9c9
--- /dev/null
@@ -0,0 +1,23 @@
+package cmd
+
+import (
+       "os"
+
+       "github.com/spf13/cobra"
+)
+
+var configCmd = &cobra.Command {
+       Use: "config",
+       Short: "Modify config",
+       Long: "Read, edit and initialize scientia configuration.",
+       Run: func(cmd *cobra.Command, args []string) {
+               if len(args) == 0 {
+                       cmd.Help()
+                       os.Exit(0)
+               }
+       },
+}
+
+func init() {
+       rootCmd.AddCommand(configCmd)
+}
diff --git a/client/go-cli/scientia/cmd/config_init.go b/client/go-cli/scientia/cmd/config_init.go
new file mode 100644 (file)
index 0000000..5fef19a
--- /dev/null
@@ -0,0 +1,58 @@
+package cmd
+
+import (
+       "errors"
+       "fmt"
+       "os"
+
+       "github.com/kirsle/configdir"
+       "github.com/spf13/cobra"
+
+       Helper "scientia/lib"
+)
+
+var configInitCmd = &cobra.Command {
+       Use: "init",
+       Short: "Initialize config",
+       Long: `Read, edit and initialize scientia configuration`,
+       Run: func(cmd *cobra.Command, args []string) {
+               initConfig()
+       },
+}
+
+func init() {
+       configCmd.AddCommand(configInitCmd)
+}
+
+
+func initConfig() {
+       configPath := configdir.LocalConfig("scientia")
+       err := configdir.MakePath(configPath) // Ensure it exists.
+       Helper.ErrorCheck(err, "No $HOME/.config/scientia directory available?")
+       var configFile = configPath + "/.scientia.yaml"
+
+       if FlagDebug {
+               fmt.Printf("Local user config path: %s\n", configPath)
+               fmt.Printf("Local user config file: %s\n", configFile)
+       }
+
+       if _, err := os.Stat(configFile); errors.Is(err, os.ErrNotExist) {
+               fmt.Printf("Creating new default config file: %s \n", configFile)
+
+               newConfig, err := os.Create(configFile)
+               Helper.ErrorCheck(err, "Can not create config file!")
+               defer newConfig.Close()
+
+               _, err = fmt.Fprintf(newConfig, "# scientia go client config file.\n")
+               Helper.ErrorCheck(err, "Can not write to new config file")
+               fmt.Fprintf(newConfig, "# See %s for more details.\n", Helper.Website)
+               fmt.Fprintf(newConfig, "# Version: %s\n", Helper.Version)
+               fmt.Fprintf(newConfig, "endpoint:\n")
+               fmt.Fprintf(newConfig, "  host: http://your-scientia-endpoi.nt/api.php\n")
+               fmt.Fprintf(newConfig, "  secret: %s\n", Helper.RandStringBytes(50))
+
+       } else {
+               fmt.Printf("Config file exists.: %s \n", configFile)
+               fmt.Println("User read to display or edit to modify the config file.")
+       }
+}
diff --git a/client/go-cli/scientia/cmd/root.go b/client/go-cli/scientia/cmd/root.go
new file mode 100644 (file)
index 0000000..e9a0d79
--- /dev/null
@@ -0,0 +1,44 @@
+package cmd
+
+import (
+       "fmt"
+       "os"
+
+       "github.com/spf13/cobra"
+)
+
+// FlagVerbose is a global flag
+var FlagVerbose bool
+
+// FlagDebug is a global flag
+var FlagDebug bool
+
+// The rootCmd
+var rootCmd = &cobra.Command {
+       Use:   "scientia",
+       Short: "scientia client",
+       Long: `cognizance, insight, knowledge.
+A client to scientia.
+More information: https://www.bananas-playground.net/projekt/scientia/`,
+       Run: func(cmd *cobra.Command, args []string) {
+
+               // display help if no arguments are given
+               if len(args) == 0 {
+                       cmd.Help()
+                       os.Exit(0)
+               }
+       },
+}
+
+func init() {
+       // add global flags
+       rootCmd.PersistentFlags().BoolVarP(&FlagVerbose, "verbose", "v", false, "verbose output")
+       rootCmd.PersistentFlags().BoolVarP(&FlagDebug, "debug", "d", false, "debug output")
+}
+
+func Execute() {
+       if err := rootCmd.Execute(); err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+}
diff --git a/client/go-cli/scientia/go.mod b/client/go-cli/scientia/go.mod
new file mode 100644 (file)
index 0000000..b46d0b3
--- /dev/null
@@ -0,0 +1,10 @@
+module scientia
+
+go 1.22.4
+
+require (
+       github.com/inconshreveable/mousetrap v1.1.0 // indirect
+       github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f // indirect
+       github.com/spf13/cobra v1.8.1 // indirect
+       github.com/spf13/pflag v1.0.5 // indirect
+)
diff --git a/client/go-cli/scientia/go.sum b/client/go-cli/scientia/go.sum
new file mode 100644 (file)
index 0000000..8d8834d
--- /dev/null
@@ -0,0 +1,12 @@
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU=
+github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/client/go-cli/scientia/lib/helpers.go b/client/go-cli/scientia/lib/helpers.go
new file mode 100644 (file)
index 0000000..c221475
--- /dev/null
@@ -0,0 +1,26 @@
+package lib
+
+import (
+       "log"
+       "math/rand"
+)
+
+const Version string = "1.0"
+const Website string = "https://www.bananas-playground.net/projekt/scientia/"
+
+// ErrorCheck if error then display it with an addition message
+func ErrorCheck(e error, msg string) {
+       if e != nil {
+               log.Fatal(msg, " ; Message: ", e)
+       }
+}
+
+// RandStringBytes creates just a random string
+func RandStringBytes(n int) string {
+       var letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
+       b := make([]byte, n)
+       for i := range b {
+               b[i] = letters[rand.Intn(len(letters))]
+       }
+       return string(b)
+}
diff --git a/client/go-cli/scientia/main.go b/client/go-cli/scientia/main.go
new file mode 100644 (file)
index 0000000..05eada2
--- /dev/null
@@ -0,0 +1,9 @@
+package main
+
+import (
+       "scientia/cmd"
+)
+
+func main() {
+       cmd.Execute()
+}
diff --git a/client/go-cli/scientia/scientia b/client/go-cli/scientia/scientia
new file mode 100755 (executable)
index 0000000..0749306
Binary files /dev/null and b/client/go-cli/scientia/scientia differ
diff --git a/client/go-cli_/Makefile b/client/go-cli_/Makefile
new file mode 100644 (file)
index 0000000..b8ab31a
--- /dev/null
@@ -0,0 +1,28 @@
+all:
+       @echo "Options are: build scientia-cli scientia-cli-linux-amd64 scientia-cli-windows-amd64 scientia-cli-darwin-amd64 clean buildall"
+
+scientia-cli:
+       @echo "Building for local os/arch..."
+       go build -o scientia-cli
+
+scientia-cli-linux-amd64:
+       @echo "Building for linux/amd64 arch..."
+       GOOS=linux GOARCH=amd64 go build -o scientia-cli-linux-amd64
+
+scientia-cli-windows-amd64:
+       @echo "Building for windows/amd64 arch..."
+       GOOS=windows GOARCH=amd64 go build -o scientia-cli-windows-amd64
+
+scientia-cli-darwin-amd64:
+       @echo "Building for macOS/amd64 arch..."
+       GOOS=darwin GOARCH=amd64 go build -o scientia-cli-darwin-amd64
+
+build:
+       @echo "Building for local os/arch..."
+       go build -o scientia-cli-`go env GOOS`-`go env GOARCH`
+
+buildall: scientia-cli-linux-amd64 scientia-cli-windows-amd64 scientia-cli-darwin-amd64
+       @echo "Building for linux/amd64, windows/amd64 and macOS/amd64 arch..."
+
+clean:
+       rm -f scientia-cli scientia-cli-darwin-amd64 scientia-cli-windows-amd64 scientia-cli-linux-amd64
\ No newline at end of file
diff --git a/client/go-cli_/README.md b/client/go-cli_/README.md
new file mode 100644 (file)
index 0000000..04ff93f
--- /dev/null
@@ -0,0 +1,32 @@
+# scienta go cli client
+
+This is a terminal cli client written in go to be used with scientia
+https://://www.bananas-playground.net/projekt/scientia/
+
+!WARNING!
+This is a very simple, with limited experience written, go program.
+Use at own risk and feel free to improve.
+
+# Howto build
+
+Nothing special, just use the provided Makefile or directly 
+"go build -o scientia-cli" to use your current os/arch settings.
+
+# Usage
+
+At first usage you need to create the config and the individual secret.
+Run $scientia-cli -create-config-file to create the default config file.
+The path to the config file is printed.
+Change the host address and update your server it with the secret, which is randomly created.
+
+## Create
+
+Read from a file `$ scientia-cli file.txt` or piped `$ cat file.txt | scientia-cli`
+
+# Commandline arguments
+
+## Optinal
+
++ `-create-config-file` Create default config file
++ `-debug` Print debug infos
++ `-verbose` Produce verbose output
diff --git a/client/go-cli_/go.mod b/client/go-cli_/go.mod
new file mode 100644 (file)
index 0000000..5a0b7ac
--- /dev/null
@@ -0,0 +1,5 @@
+module scientia/go-client-cli
+
+go 1.20
+
+require gopkg.in/yaml.v2 v2.4.0
diff --git a/client/go-cli_/go.sum b/client/go-cli_/go.sum
new file mode 100644 (file)
index 0000000..dd0bc19
--- /dev/null
@@ -0,0 +1,4 @@
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/client/go-cli_/scientia-cli.go b/client/go-cli_/scientia-cli.go
new file mode 100644 (file)
index 0000000..ef999a8
--- /dev/null
@@ -0,0 +1,271 @@
+package main
+
+import (
+       "bytes"
+       "encoding/json"
+       "errors"
+       "flag"
+       "fmt"
+       "io"
+       "log"
+       "math/rand"
+       "net/http"
+       "os"
+
+       "gopkg.in/yaml.v2"
+)
+
+/**
+ * scientia
+ *
+ * Copyright 2023 - 2024 Johannes Keßler
+ *
+ * https://www.bananas-playground.net/projekt/scientia/
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ *
+ * You should have received a copy of the
+ * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+ * along with this program.  If not, see http://www.sun.com/cddl/cddl.html
+ */
+
+const website = "https://www.bananas-playground.net/projekt/scientia/"
+const version = "1.0"
+
+// used for non-existing default config
+const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
+
+// command line parameters
+var optsVerbose bool
+var optsCreateConfig bool
+var optsDebug bool
+
+// config
+var cfg Config
+
+// config file struct
+type Config struct {
+       Endpoint struct {
+               Host   string `yaml:"host"`
+               Secret string `yaml:"secret"`
+       } `yaml:"endpoint"`
+}
+
+// post json struct
+type PayloadJson struct {
+       Asl  string `json:"asl"`
+       Data string `json:"data"`
+}
+
+// response json struct
+type Response struct {
+       Message string `json:"message"`
+       Status  int    `json:"status"`
+}
+
+/**
+ * Main
+ */
+func main() {
+
+       // https://cli.urfave.org/v2/examples/arguments/
+       // https://github.com/dnote/dnote
+       //https://github.com/spf13/cobra/blob/main/site/content/user_guide.md
+
+       // parse commandline parameters
+       flag.BoolVar(&optsVerbose, "verbose", false, "Produce verbose output")
+       flag.BoolVar(&optsCreateConfig, "create-config-file", false, "Create default config file")
+       flag.BoolVar(&optsDebug, "debug", false, "Print debug infos")
+       flag.Parse()
+       if optsDebug {
+               fmt.Println("verbose:", optsVerbose)
+               fmt.Println("create-config-file:", optsCreateConfig)
+               fmt.Println("debug:", optsDebug)
+       }
+
+       // load the config and populate Config
+       loadConfig()
+
+       // get the payload
+       payload := getInput()
+       if optsDebug {
+               log.Println(payload)
+       }
+
+       // do the upload and get the response
+       responseString := uploadCall(payload)
+       response := Response{}
+       json.Unmarshal([]byte(responseString), &response)
+
+       // print the result and link to the pasty
+       fmt.Printf("Status: %d\n", response.Status)
+       fmt.Printf("Message: %s\n", response.Message)
+}
+
+/**
+ * Check and display error with additional message
+ */
+func errorCheck(e error, msg string) {
+       if e != nil {
+               log.Fatal(msg, " ; Errrormsg: ", e)
+       }
+}
+
+/**
+ * just a random string
+ */
+func randStringBytes(n int) string {
+       b := make([]byte, n)
+       for i := range b {
+               b[i] = letters[rand.Intn(len(letters))]
+       }
+       return string(b)
+}
+
+/**
+ * load or even create a default config
+ * $HOME/.scientia.yaml
+ */
+func loadConfig() {
+       homeDir, err := os.UserHomeDir()
+       errorCheck(err, "No $HOME directory available?")
+       if optsVerbose {
+               log.Printf("Your $HOME: %s \n", homeDir)
+       }
+
+       var configFile = homeDir + "/.scientia.yaml"
+
+       if _, err := os.Stat(configFile); errors.Is(err, os.ErrNotExist) {
+               log.Printf("Config file not found: %s \n", configFile)
+
+               if optsCreateConfig {
+                       log.Printf("Creating new default config file: %s \n", configFile)
+
+                       newConfig, err := os.Create(configFile)
+                       errorCheck(err, "Can not create config file!")
+                       defer newConfig.Close()
+
+                       _, err = fmt.Fprintf(newConfig, "# scientia go client config file.\n")
+                       errorCheck(err, "Can not write to new config file")
+                       fmt.Fprintf(newConfig, "# See %s for more details.\n", website)
+                       fmt.Fprintf(newConfig, "# Version: %s\n", version)
+                       fmt.Fprintf(newConfig, "endpoint:\n")
+                       fmt.Fprintf(newConfig, "  host: http://your-scientia-endpoi.nt/api.php\n")
+                       fmt.Fprintf(newConfig, "  secret: %s\n", randStringBytes(50))
+
+                       log.Fatalf("New default config file created: - %s - Edit and launch again!", configFile)
+               }
+       }
+
+       existingConfigFile, err := os.Open(configFile)
+       errorCheck(err, "Can not open config file. Did you create one with -create-config-file?")
+       defer existingConfigFile.Close()
+       if optsVerbose {
+               log.Printf("Reading config file: %s \n", configFile)
+       }
+
+       var decoder = yaml.NewDecoder(existingConfigFile)
+       err = decoder.Decode(&cfg)
+       errorCheck(err, "Can not decode config file")
+
+       if cfg.Endpoint.Host == "" || cfg.Endpoint.Secret == "" {
+               log.Fatal("Empty config?")
+       }
+
+       if optsDebug {
+               log.Println(cfg.Endpoint.Host)
+               log.Println(cfg.Endpoint.Secret)
+       }
+}
+
+/**
+ * Do a http POST call to the defined endpoint
+ * and upload the payload
+ * Return response body as string
+ */
+func uploadCall(payload string) string {
+
+       if optsVerbose {
+               log.Println("Starting to upload data")
+       }
+       if optsDebug {
+               log.Println(payload)
+       }
+       if len(payload) == 0 {
+               log.Fatal("Nothing provided to upload")
+       }
+
+       payloadStruct := PayloadJson{
+               Asl:  cfg.Endpoint.Secret,
+               Data: payload,
+       }
+
+       jsonData, err := json.Marshal(payloadStruct)
+       errorCheck(err, "Can not create json payload")
+
+       req, err := http.NewRequest(http.MethodPost, cfg.Endpoint.Host, bytes.NewBuffer(jsonData))
+       errorCheck(err, "Can not create http request")
+       // We need to set the content type from the writer, it includes necessary boundary as well
+       req.Header.Set("Content-Type", "application/json; charset=UTF-8")
+       req.Header.Set("User-Agent", "scientiaAgent/1.0")
+
+       // Do the request
+       client := &http.Client{}
+       response, err := client.Do(req)
+       errorCheck(err, "POST request failed")
+
+       responseBody, err := io.ReadAll(response.Body)
+       errorCheck(err, "Can not read response body")
+
+       if optsVerbose {
+               log.Println("Request done")
+       }
+       if optsDebug {
+               log.Printf("Response status code: %d\n", response.StatusCode)
+               log.Printf("Response headers: %#v\n", response.Header)
+               log.Println(string(responseBody))
+       }
+
+       return string(responseBody)
+}
+
+/**
+ * check if file is provided as commandline argument
+ * or piped into
+ * return the read data as string
+ */
+func getInput() string {
+       if optsVerbose {
+               log.Println("Getting input")
+       }
+
+       var inputString string
+
+       if filename := flag.Arg(0); filename != "" {
+               if optsVerbose {
+                       log.Println("Read from file argument")
+               }
+
+               bytes, err := os.ReadFile(filename)
+               errorCheck(err, "Error opening file")
+               inputString = string(bytes)
+       } else {
+               stat, _ := os.Stdin.Stat()
+               if (stat.Mode() & os.ModeCharDevice) == 0 {
+                       if optsVerbose {
+                               log.Println("data is being piped")
+                       }
+
+                       bytes, _ := io.ReadAll(os.Stdin)
+                       inputString = string(bytes)
+               }
+       }
+
+       if len(inputString) == 0 {
+               log.Fatal("Nothing provided to upload")
+       }
+
+       return inputString
+}