Skip to content

Commit

Permalink
cli: add basic cli
Browse files Browse the repository at this point in the history
  • Loading branch information
onprem committed Apr 30, 2020
1 parent 3d3887d commit 5a68cbd
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 1 deletion.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ build-static: assets
@echo ">> building statically linked $(PROJECTNAME) binary"
@CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o $(BUILD_DIR)/gonotify ./cmd/gonotify

.PHONY: build-cli
build-cli: ## Builds gncli - the GoNotify CLI client.
build-cli:
@echo ">> building gncli binary"
@go build -o $(BUILD_DIR)/gncli ./cmd/gncli

.PHONY: assets
assets: ## Repacks all static assets into go file for easier deploy.
assets: $(GOBINDATA) $(REACT_APP_OUTPUT_DIR)
Expand Down
163 changes: 163 additions & 0 deletions cmd/gncli/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package client

import (
"bytes"
"encoding/json"
"errors"
"net/http"
"net/url"
)

// Client represents the GoNotify API client
type Client struct {
base *url.URL
token string
hc *http.Client
ep struct {
login *url.URL
register *url.URL
send *url.URL
}
}

// NewClient return an instance of Client
func NewClient(baseURL string, token string) (*Client, error) {
base, err := url.Parse(baseURL + "/api/v1/")
if err != nil {
return nil, err
}

c := &Client{
base: base,
token: token,
hc: &http.Client{},
}
err = c.register()
if err != nil {
return nil, err
}

return c, nil
}

func (c *Client) register() error {
u, err := url.Parse("login")
if err != nil {
return err
}
c.ep.login = c.base.ResolveReference(u)

u, err = url.Parse("register")
if err != nil {
return err
}
c.ep.register = c.base.ResolveReference(u)

u, err = url.Parse("send")
if err != nil {
return err
}
c.ep.send = c.base.ResolveReference(u)

return nil
}

// Login returns a token given valid credentials
func (c *Client) Login(phone, password string) (string, error) {
var token string

if phone == "" || password == "" {
return token, errors.New("Number and password cannot be empty")
}

values := map[string]string{
"phone": phone,
"password": password,
}

v, err := json.Marshal(values)
if err != nil {
return token, err
}

req, err := http.NewRequest("POST", c.ep.login.String(), bytes.NewBuffer(v))
if err != nil {
return token, err
}

req.Header.Set("Content-Type", "application/json")

resp, err := c.hc.Do(req)
if err != nil {
return token, err
}
defer resp.Body.Close()

res := map[string]string{}

err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return token, err
}

msg, ok := res["error"]
if ok {
return token, errors.New(msg)
}

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return token, errors.New("Request failed. Status: " + resp.Status)
}

token = res["token"]
return token, nil
}

// Send sends a message to given group
func (c *Client) Send(body, group string) error {
if c.token == "" {
return errors.New("You are not logged in")
}

if body == "" {
return errors.New("Cannot send empty message")
}

values := map[string]string{
"body": body,
"group": group,
}

v, err := json.Marshal(values)
if err != nil {
return err
}

req, err := http.NewRequest("POST", c.ep.send.String(), bytes.NewBuffer(v))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.token)

resp, err := c.hc.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

res := map[string]string{}

err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return err
}

errMsg, ok := res["error"]
if ok {
return errors.New(errMsg)
}

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return errors.New("Request failed. Status: " + resp.Status)
}

return nil
}
47 changes: 47 additions & 0 deletions cmd/gncli/cmd/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var loginCmd = &cobra.Command{
Use: "login",
Short: "Login to GoNotify",
Long: "This subcommand lets you sign in into GoNotify",
Run: login,
}

var number string
var password string

func login(cmd *cobra.Command, args []string) {
conf := getConfig()

c := getClient(conf.BaseURL, conf.Token)

token, err := c.Login(number, password)
if err != nil {
fmt.Println(err)
os.Exit(2)
}

conf.Token = token
conf.Phone = number
conf.Password = password
err = conf.Save()
if err != nil {
fmt.Println(err)
os.Exit(2)
}

fmt.Println("Login successful")
}

func init() {
loginCmd.Flags().StringVarP(&number, "number", "n", "", "Primary phone number of your account")
loginCmd.Flags().StringVarP(&password, "password", "p", "", "Password of your account")
rootCmd.AddCommand(loginCmd)
}
57 changes: 57 additions & 0 deletions cmd/gncli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cmd

import (
"fmt"
"os"
"path"

"github.com/prmsrswt/gonotify/cmd/gncli/client"
"github.com/prmsrswt/gonotify/cmd/gncli/config"
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "gncli",
Short: "gncli - a commanf-line client for GoNotify",
Version: "v0.1.0",
// Run: list,
}

func getClient(baseURL, token string) *client.Client {
c, err := client.NewClient(baseURL, token)
if err != nil {
fmt.Println("Error initialising API client")
os.Exit(2)
}

return c
}

func getConfig() *config.Config {
homeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
baseDir := path.Join(homeDir, ".gonotify")

err = os.MkdirAll(baseDir, 0755)
if err != nil {
panic(err)
}

c := &config.Config{Path: path.Join(baseDir, "config.json")}

err = c.Load()
if err != nil {
panic(err)
}

return c
}

// Execute executes the root command
func Execute() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
39 changes: 39 additions & 0 deletions cmd/gncli/cmd/send.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cmd

import (
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
)

var sendCmd = &cobra.Command{
Use: "send",
Short: "Send message to a group",
Long: "This subcommand sends a message to the given group",
// Aliases: []string{"ls"},
Run: send,
}

var group string

func send(cmd *cobra.Command, args []string) {
data := strings.Join(args, " ")

conf := getConfig()
client := getClient(conf.BaseURL, conf.Token)

err := client.Send(data, group)
if err != nil {
fmt.Println(err)
os.Exit(2)
}

fmt.Println("Message sent successfully")
}

func init() {
sendCmd.Flags().StringVarP(&group, "group", "g", "", "Name of group to send message")
rootCmd.AddCommand(sendCmd)
}
57 changes: 57 additions & 0 deletions cmd/gncli/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package config

import (
"encoding/json"
"io/ioutil"
"os"
)

// Config represnts cli config
type Config struct {
Phone string `json:"phone"`
Password string `json:"password"`
Token string `json:"token"`
BaseURL string `json:"baseURL"`
Path string `json:"-"`
}

// LoadDefault loads the default config
func (c *Config) LoadDefault() {
c.BaseURL = "https://gonotify.xyz"
}

// Save saves the config at given path
func (c *Config) Save() error {
data, err := json.Marshal(c)
if err != nil {
return err
}

return ioutil.WriteFile(c.Path, data, 0644)
}

// Load loads the config from given path
func (c *Config) Load() error {
file, err := os.Open(c.Path)
if err != nil {
c.LoadDefault()

err := c.Save()
if err != nil {
return err
}

return nil
}

data, err := ioutil.ReadAll(file)
if err != nil {
return err
}

err = json.Unmarshal(data, c)
if err != nil {
return err
}
return nil
}
7 changes: 7 additions & 0 deletions cmd/gncli/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "github.com/prmsrswt/gonotify/cmd/gncli/cmd"

func main() {
cmd.Execute()
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ require (
github.com/ilyakaznacheev/cleanenv v1.2.2
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/nyaruka/phonenumbers v1.0.55
github.com/spf13/cobra v0.0.3
golang.org/x/crypto v0.0.0-20200423195118-18b771bd64f1
)
Loading

0 comments on commit 5a68cbd

Please sign in to comment.