Skip to content

Commit

Permalink
Merge pull request #5 from ksysoev/macros_feature
Browse files Browse the repository at this point in the history
Macro feature
  • Loading branch information
ksysoev authored Nov 11, 2023
2 parents 3353d33 + 6d9128f commit 36c4103
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 7 deletions.
1 change: 1 addition & 0 deletions cmd/wsget/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func run(cmd *cobra.Command, args []string) {
client, err := cli.NewCLI(wsConn, input, os.Stdout)
if err != nil {
color.New(color.FgRed).Println("Unable to start CLI: ", err)
return
}

opts := cli.RunOptions{}
Expand Down
9 changes: 9 additions & 0 deletions example-macro-preset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: '1'

domains:
- derivws.com
- binaryws.com
- deriv.dev

macro:
ticks: ['edit {"ticks": "R_50"}']
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ require (
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.13.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
17 changes: 15 additions & 2 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import (
)

const (
HistoryFilename = ".wsget_history"
HistoryCmdFilename = ".wsget_cmd_history"
MacroDir = "macro"
ConfigDir = ".wsget"
HistoryFilename = ConfigDir + "/history"
HistoryCmdFilename = ConfigDir + "/cmd_history"
ConfigDirMode = 0o755
CommandsLimit = 100
HistoryLimit = 100

Expand All @@ -34,6 +37,7 @@ type CLI struct {
input Inputer
output io.Writer
commands chan Executer
macro *Macro
}

type RunOptions struct {
Expand All @@ -53,10 +57,18 @@ func NewCLI(wsConn *ws.Connection, input Inputer, output io.Writer) (*CLI, error
}

homeDir := currentUser.HomeDir
if err = os.MkdirAll(homeDir+"/"+ConfigDir+"/"+MacroDir, ConfigDirMode); err != nil {
return nil, fmt.Errorf("fail to get current user: %s", err)
}

history := NewHistory(homeDir+"/"+HistoryFilename, HistoryLimit)
cmdHistory := NewHistory(homeDir+"/"+HistoryCmdFilename, HistoryLimit)

macro, err := LoadMacroForDomain(homeDir+"/"+ConfigDir+"/"+MacroDir, wsConn.Hostname)
if err != nil {
return nil, fmt.Errorf("fail to load macro: %s", err)
}

commands := make(chan Executer, CommandsLimit)

return &CLI{
Expand All @@ -67,6 +79,7 @@ func NewCLI(wsConn *ws.Connection, input Inputer, output io.Writer) (*CLI, error
input: input,
output: output,
commands: commands,
macro: macro,
}, nil
}

Expand Down
29 changes: 27 additions & 2 deletions pkg/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type Executer interface {
Execute(*ExecutionContext) (Executer, error)
}

func CommandFactory(raw string) (Executer, error) {
func CommandFactory(raw string, macro *Macro) (Executer, error) {
if raw == "" {
return nil, fmt.Errorf("empty command")
}
Expand Down Expand Up @@ -64,6 +64,10 @@ func CommandFactory(raw string) (Executer, error) {

return NewCommandWaitForResp(timeout), nil
default:
if macro != nil {
return macro.Get(cmd)
}

return nil, fmt.Errorf("unknown command: %s", cmd)
}
}
Expand Down Expand Up @@ -205,7 +209,7 @@ func (c *CommandCmdEdit) Execute(exCtx *ExecutionContext) (Executer, error) {
return nil, err
}

cmd, err := CommandFactory(rawCmd)
cmd, err := CommandFactory(rawCmd, exCtx.cli.macro)

if err != nil {
color.New(color.FgRed).Fprintln(exCtx.cli.output, err)
Expand All @@ -214,3 +218,24 @@ func (c *CommandCmdEdit) Execute(exCtx *ExecutionContext) (Executer, error) {

return cmd, nil
}

type CommandSequence struct {
subCommands []Executer
}

func NewCommandSequence(subCommands []Executer) *CommandSequence {
return &CommandSequence{subCommands}
}

func (c *CommandSequence) Execute(exCtx *ExecutionContext) (Executer, error) {
for _, cmd := range c.subCommands {
for cmd != nil {
var err error
if cmd, err = cmd.Execute(exCtx); err != nil {
return nil, err
}
}
}

return nil, nil
}
144 changes: 144 additions & 0 deletions pkg/cli/macro.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package cli

import (
"fmt"
"log"
"os"
"strings"

"gopkg.in/yaml.v3"
)

type Config struct {
Version string `yaml:"version"`
Macro map[string][]string `yaml:"macro"`
Domains []string `yaml:"domains"`
}

type Macro struct {
macro map[string]Executer
domains []string
}

func NewMacro(domains []string) *Macro {
return &Macro{
macro: make(map[string]Executer),
domains: domains,
}
}

func (m *Macro) AddCommands(name string, rawCommands []string) error {
if _, ok := m.macro[name]; ok {
return fmt.Errorf("macro already exists: %s", name)
}

commands := []Executer{}

for _, rawCommand := range rawCommands {
cmd, err := CommandFactory(rawCommand, nil)
if err != nil {
return err
}

commands = append(commands, cmd)
}

switch len(commands) {
case 0:
return fmt.Errorf("empty macro: %s", name)
case 1:
m.macro[name] = commands[0]
default:
m.macro[name] = NewCommandSequence(commands)
}

return nil
}

func (m *Macro) merge(macro *Macro) error {
for name, cmd := range macro.macro {
if _, ok := m.macro[name]; ok {
return fmt.Errorf("duplicate macro name: %s", name)
}

m.macro[name] = cmd
}

return nil
}

func (m *Macro) Get(name string) (Executer, error) {
if cmd, ok := m.macro[name]; ok {
return cmd, nil
}

return nil, fmt.Errorf("unknown command: %s", name)
}

func LoadMacro(path string) (*Macro, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}

var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}

if cfg.Version != "1" {
return nil, fmt.Errorf("unsupported macro file version: %s", path)
}

macroCfg := NewMacro(cfg.Domains)

for name, rawCommands := range cfg.Macro {
if err := macroCfg.AddCommands(name, rawCommands); err != nil {
return nil, err
}
}

return macroCfg, nil
}

func LoadMacroForDomain(macroDir, domain string) (*Macro, error) {
files, err := os.ReadDir(macroDir)
if err != nil {
log.Fatal(err)
}

var macro *Macro

for _, file := range files {
fileMacro, err := LoadMacro(macroDir + "/" + file.Name())

if err != nil {
return nil, err
}

hasDomain := false

for _, fileDomain := range fileMacro.domains {
if strings.HasSuffix(domain, fileDomain) {
hasDomain = true
break
}
}

if !hasDomain {
continue
}

if macro == nil {
macro = fileMacro
} else {
err := macro.merge(fileMacro)

if err != nil {
return nil, fmt.Errorf("fail to loading macro from file %s, %s ", file.Name(), err)
}
}
}

return macro, nil
}
13 changes: 10 additions & 3 deletions pkg/ws/ws.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"strings"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -45,6 +46,7 @@ type Connection struct {
ws *websocket.Conn
Messages chan Message
waitGroup *sync.WaitGroup
Hostname string
isClosed atomic.Bool
}

Expand All @@ -53,8 +55,13 @@ type Options struct {
SkipSSLVerification bool
}

func NewWS(url string, opts Options) (*Connection, error) {
cfg, err := websocket.NewConfig(url, "http://localhost")
func NewWS(wsURL string, opts Options) (*Connection, error) {
parsedURL, err := url.Parse(wsURL)
if err != nil {
return nil, err
}

cfg, err := websocket.NewConfig(wsURL, "http://localhost")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -94,7 +101,7 @@ func NewWS(url string, opts Options) (*Connection, error) {

messages := make(chan Message, WSMessageBufferSize)

wsInsp := &Connection{ws: ws, Messages: messages, waitGroup: &waitGroup}
wsInsp := &Connection{ws: ws, Messages: messages, waitGroup: &waitGroup, Hostname: parsedURL.Hostname()}

go func() {
defer func() {
Expand Down

0 comments on commit 36c4103

Please sign in to comment.