diff --git a/cmd/wsget/main.go b/cmd/wsget/main.go index 5bb33d3..4d9d80c 100644 --- a/cmd/wsget/main.go +++ b/cmd/wsget/main.go @@ -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{} diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index c71d590..09ae458 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -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 @@ -34,6 +37,7 @@ type CLI struct { input Inputer output io.Writer commands chan Executer + macro *Macro } type RunOptions struct { @@ -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{ @@ -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 } @@ -80,11 +93,6 @@ func (c *CLI) Run(opts RunOptions) error { } }() - macro, err := LoadMacro("./example-macro-preset.yml") - if err != nil { - return err - } - c.hideCursor() keysEvents, err := c.input.GetKeys() @@ -103,7 +111,6 @@ func (c *CLI) Run(opts RunOptions) error { input: keysEvents, cli: c, outputFile: opts.OutputFile, - macro: macro, } for { diff --git a/pkg/cli/commands.go b/pkg/cli/commands.go index 68e71b2..3beea4a 100644 --- a/pkg/cli/commands.go +++ b/pkg/cli/commands.go @@ -20,7 +20,6 @@ type ExecutionContext struct { input <-chan keyboard.KeyEvent cli *CLI outputFile io.Writer - macro *Macro } type Executer interface { @@ -210,7 +209,7 @@ func (c *CommandCmdEdit) Execute(exCtx *ExecutionContext) (Executer, error) { return nil, err } - cmd, err := CommandFactory(rawCmd, exCtx.macro) + cmd, err := CommandFactory(rawCmd, exCtx.cli.macro) if err != nil { color.New(color.FgRed).Fprintln(exCtx.cli.output, err) diff --git a/pkg/cli/macro.go b/pkg/cli/macro.go index 32ccdb5..a96fd91 100644 --- a/pkg/cli/macro.go +++ b/pkg/cli/macro.go @@ -2,7 +2,9 @@ package cli import ( "fmt" + "log" "os" + "strings" "gopkg.in/yaml.v3" ) @@ -53,6 +55,18 @@ func (m *Macro) AddCommands(name string, rawCommands []string) error { 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 @@ -73,7 +87,7 @@ func LoadMacro(path string) (*Macro, error) { } if cfg.Version != "1" { - return nil, fmt.Errorf("unsupported macro version: %s", cfg.Version) + return nil, fmt.Errorf("unsupported macro file version: %s", path) } macroCfg := NewMacro(cfg.Domains) @@ -86,3 +100,45 @@ func LoadMacro(path string) (*Macro, error) { 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 +} diff --git a/pkg/ws/ws.go b/pkg/ws/ws.go index 52e62c8..0e60e3c 100644 --- a/pkg/ws/ws.go +++ b/pkg/ws/ws.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "fmt" "net/http" + "net/url" "strings" "sync" "sync/atomic" @@ -45,6 +46,7 @@ type Connection struct { ws *websocket.Conn Messages chan Message waitGroup *sync.WaitGroup + Hostname string isClosed atomic.Bool } @@ -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 } @@ -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() {