Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Boernsman authored and Boernsman committed Jul 11, 2024
0 parents commit e9b4ba1
Show file tree
Hide file tree
Showing 19 changed files with 1,276 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Go

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:

build:
runs-on: ubuntu-latest

strategy:
matrix:
arch: [amd64, arm64]

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'

- name: Run go mod tidy in src folder
working-directory: ./src
run: go mod tidy

- name: Build
working-directory: ./src
env:
GOARCH: ${{ matrix.arch }}
REPO_NAME: ${{ github.event.repository.name }}
run: go build -o bin/${REPO_NAME}-${{ matrix.arch }} ./...
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/

40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Bon Voyage CLI

`bon-voyage-cli` is a command-line tool for interacting with the `Bon Voyage` service.
The tool also stores the authentication token securely in a temporary file.

## Features

- **User**: Authenticate, register or modify a user account.
- **Device**: List, configure or get a tunnel to connected devices
- **Session**: Change the username of the authenticated user.
- **Snippet**: Create code orlog snipt and share them with a read-only link.

## Installation

### Prerequisites

- Go programming language installed (version 1.22 or higher).

### Build

1. Clone the repository:
```sh
git clone https://github.com/bitcrushtesting/bon-voyage-cli.git
cd bon-voyage-cli
```

2. Build the binary:
```sh
./build.sh
```

## Usage

### Login

Authenticate with the server and store the token.

```sh
./bon-voyage-cli login <username>
```
32 changes: 32 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash

# Exit immediately if a command exits with a non-zero status
set -e

# Variables
BASEDIR=$(dirname $(realpath "$0"))
echo "Base Dir: $BASEDIR"
TARGET="bon-voyage-cli"
SRC_DIR="$BASEDIR/src"
BUILD_DIR="$BASEDIR/build"

# Determine the operating system
OS="$(uname -s)"
case "$OS" in
Linux*) GOOS="linux";;
Darwin*) GOOS="darwin";;
*) echo "Unsupported OS: $OS"; exit 1;;
esac

# Clean previous builds
echo "Cleaning previous builds..."
rm -f $BUILD_DIR/$TARGET

# Build the CLI
echo "Building CLI ..."
cd $SRC_DIR

GIT_HASH=$(git rev-parse HEAD)
go build -o $BUILD_DIR/$TARGET -ldflags="-X main.Commit=$GIT_HASH"
cd $BASEDIR
echo "Build finished. See README.md for usage."
4 changes: 4 additions & 0 deletions example/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Bon Voyage CLI
host: 127.0.0.1
port: 8080

59 changes: 59 additions & 0 deletions src/cmd/device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2024 Bitcrush Testing

package cmd

import (
"bon-voyage-cli/connection"
"fmt"
"os"

"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(deviceCmd)
}

var deviceCmd = &cobra.Command{
Use: "device",
Short: "Interact with devices connected to the server",
Long: `Login device description`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Device command used")
if len(args) < 1 {
os.Exit(1)
}
if err := connection.LoadToken(); err != nil {
fmt.Println("Token not available", err)
os.Exit(1)
}

switch args[0] {
case "list":
devices, err := connection.DeviceList()
if err != nil {
fmt.Println("Could not get device list:", err)
os.Exit(1)
}
fmt.Println("Device count:", len(devices))
if len(devices) > 0 {
fmt.Println(devices)
}

case "socket":
if len(args) < 2 {
fmt.Println("Expected device uuid after socket")
os.Exit(1)
}
deviceId := args[1]
if err := connection.DeviceSocket(deviceId); err != nil {
fmt.Println(err)
os.Exit(1)
}

default:
fmt.Println("Unknown device subcommand:", args[2])
os.Exit(1)
}
},
}
42 changes: 42 additions & 0 deletions src/cmd/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2024 Bitcrush Testing

package cmd

import (
"bon-voyage-cli/connection"
"bon-voyage-cli/utils"
"fmt"
"os"

"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(loginCmd)
}

var loginCmd = &cobra.Command{
Use: "login",
Short: "Login to the 'bon-voyage' server",
Long: `All software has versions. This is bon-voyage-cli's`,
Run: func(cmd *cobra.Command, args []string) {

if len(args) < 1 {
fmt.Println("User missing")
os.Exit(1)
}
username := args[0]
fmt.Println("Username:", username)

password, err := utils.ReadPassword()
if err != nil {
fmt.Printf("Failed to read password: %v", err)
os.Exit(1)
}
if err := connection.Login(username, password); err != nil {
fmt.Println("Could not log in", err)
os.Exit(1)
}
fmt.Println("Successfully logged in account:", username)
},
}
55 changes: 55 additions & 0 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2024 Bitcrush Testing

package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
// Used for flags.
cfgFile string

rootCmd = &cobra.Command{
Use: AppName,
Short: "Command line interface for the 'Bon Voyage' server",
Long: `Longer version is to be created`,
}
)

// Execute executes the root command.
func Execute() error {
return rootCmd.Execute()
}

func init() {
cobra.OnInitialize(initConfig)

rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.bon-voyage-cli.yaml)")
}

func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)

// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".bon-voyage-cli")
}

viper.AutomaticEnv()

if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
104 changes: 104 additions & 0 deletions src/cmd/session.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2024 Bitcrush Testing

package cmd

import (
"bon-voyage-cli/connection"
"fmt"
"os"

"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(sessionCmd)
}

var sessionCmd = &cobra.Command{
Use: "session",
Short: "Create, read, stop, delete and list log sessions",
Long: `Session log debug data from the given device into a database.`,
Run: func(cmd *cobra.Command, args []string) {

if len(args) < 1 {
fmt.Println("Missing sub-command")
os.Exit(1)
}
if err := connection.LoadToken(); err != nil {
fmt.Println("Authorization token not available", err)
os.Exit(1)
}

switch args[0] {
case "list":
sessions, err := connection.SessionList()
if err != nil {
fmt.Println("Could not get session list:", err)
os.Exit(1)
}
fmt.Println("Session count:", len(sessions))

for i, session := range sessions {
fmt.Println(" -", i, "Session ID:", session.SessionId, "Device ID:", session.DeviceId, "Created:", session.Created)
}

case "create":
if len(args) < 2 {
fmt.Println("Expected device id after 'create'")
os.Exit(1)
}
deviceId := args[1]
sessionId, err := connection.SessionCreate(deviceId)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Started session for device '%s' with session id: '%s'\n", deviceId, sessionId)

case "read":
if len(args) < 2 {
fmt.Println("Expected session id after 'read'")
os.Exit(1)
}
sessionId := args[1]
logs, err := connection.SessionRead(sessionId, nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("-----------------------")
fmt.Printf("Logs: %d lines \n", len(logs))
fmt.Println(logs)
fmt.Println("-----------------------")

case "stop":
if len(args) < 2 {
fmt.Println("Expected session id after 'stop'")
os.Exit(1)
}
sessionId := args[1]
err := connection.SessionUpdate(sessionId, "stop")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Session stopped successfully")

case "delete":
if len(args) < 2 {
fmt.Println("Expected session id after 'delete'")
os.Exit(1)
}
sessionId := args[1]
if err := connection.SessionDelete(sessionId); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Session deleted successfully")

default:
fmt.Println("Unknown 'session' sub-command:", args[0])
os.Exit(1)
}
},
}
3 changes: 3 additions & 0 deletions src/cmd/terminal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Copyright 2024 Bitcrush Testing

package cmd
Loading

0 comments on commit e9b4ba1

Please sign in to comment.