diff --git a/commands/service/commands.go b/commands/service/commands.go new file mode 100644 index 0000000..0c2e282 --- /dev/null +++ b/commands/service/commands.go @@ -0,0 +1,45 @@ +package service + +import ( + "context" + "github.com/DariusKlein/kleinCommand/commands/service/subcommands" + "github.com/urfave/cli/v3" +) + +// Category service +func Category() *cli.Command { + return &cli.Command{ + Name: "service", + Usage: "commands for starting, stopping and communicating with services", + Action: Action, + Commands: commands(), + HideHelpCommand: true, + } +} + +// commands for service Category +func commands() []*cli.Command { + return []*cli.Command{ + parrot(), + } +} + +// Action show help command if no sub commands are given for Category +func Action(context context.Context, c *cli.Command) error { + return cli.ShowSubcommandHelp(c) +} + +// parrot sub-category of service Category +func parrot() *cli.Command { + return &cli.Command{ + Name: "parrot", + Usage: "commands for interacting with parrot service", + Action: Action, + Commands: []*cli.Command{ + subcommands.StartParrotService(), + subcommands.StopParrotService(), + subcommands.Talk(), + }, + HideHelpCommand: true, + } +} diff --git a/commands/service/subcommands/startParrotService.go b/commands/service/subcommands/startParrotService.go new file mode 100644 index 0000000..89d2b42 --- /dev/null +++ b/commands/service/subcommands/startParrotService.go @@ -0,0 +1,21 @@ +package subcommands + +import ( + "context" + "github.com/DariusKlein/kleinCommand/services" + "github.com/urfave/cli/v3" +) + +// StartParrotService Command +func StartParrotService() *cli.Command { + return &cli.Command{ + Name: "start", + Usage: "start parrot service", + Action: startParrotServiceAction, + } +} + +// startServiceTemplateAction logic for StartServiceTemplate +func startParrotServiceAction(context context.Context, c *cli.Command) error { + return services.RunParrotService() +} diff --git a/commands/service/subcommands/stopParrotService.go b/commands/service/subcommands/stopParrotService.go new file mode 100644 index 0000000..646b662 --- /dev/null +++ b/commands/service/subcommands/stopParrotService.go @@ -0,0 +1,36 @@ +package subcommands + +import ( + "context" + "github.com/DariusKlein/kleinCommand/common" + "github.com/urfave/cli/v3" + "log/slog" +) + +// StopParrotService Command +func StopParrotService() *cli.Command { + return &cli.Command{ + Name: "stop", + Usage: "stop parrot service", + Action: stopParrotServiceAction, + } +} + +// templateAction logic for Template +func stopParrotServiceAction(context context.Context, c *cli.Command) error { + conn, err := common.GetSocketConnection(common.ParrotServiceSocketPath) + if err != nil { + slog.ErrorContext(context, err.Error()) + return err + } + defer conn.Close() + + // Send the shutdown command. + _, err = conn.Write([]byte("shutdown\n")) + if err != nil { + slog.ErrorContext(context, err.Error()) + return err + } + + return nil +} diff --git a/commands/service/subcommands/talk.go b/commands/service/subcommands/talk.go new file mode 100644 index 0000000..1dac42b --- /dev/null +++ b/commands/service/subcommands/talk.go @@ -0,0 +1,49 @@ +package subcommands + +import ( + "bufio" + "context" + "github.com/DariusKlein/kleinCommand/common" + "github.com/urfave/cli/v3" + "log" + "os" +) + +// Talk Command +func Talk() *cli.Command { + return &cli.Command{ + Name: "talk", + Usage: "talk with parrot", + Action: templateAction, + ArgsUsage: "send arg as message to parrot", + } +} + +// templateAction logic for Template +func templateAction(context context.Context, c *cli.Command) error { + conn, err := common.GetSocketConnection(common.ParrotServiceSocketPath) + if err != nil { + return err + } + defer conn.Close() + + scanner := bufio.NewScanner(os.Stdin) + scanner.Split(bufio.ScanLines) + + common.CatchInterrupt(func() { + conn.Close() + log.Fatal("Closed connection") + }) + + for scanner.Scan() { + if _, err = conn.Write([]byte(scanner.Text() + "\n")); err != nil { + return err + } + response := make([]byte, 1024) + if _, err = conn.Read(response); err != nil { + return err + } + log.Println("Response:", string(response)) + } + return nil +} diff --git a/common/constants.go b/common/constants.go index 1e7569d..4b8dd31 100644 --- a/common/constants.go +++ b/common/constants.go @@ -1,3 +1,4 @@ package common const ExampleServiceName = "exampleService" +const ParrotServiceName = "parrotService" diff --git a/common/socketPaths.go b/common/unixSocket.go similarity index 56% rename from common/socketPaths.go rename to common/unixSocket.go index 029fa4e..e187788 100644 --- a/common/socketPaths.go +++ b/common/unixSocket.go @@ -1,12 +1,18 @@ package common import ( + "net" "os" "path/filepath" ) var ExampleServiceSocketPath = GetSocketPath(ExampleServiceName) +var ParrotServiceSocketPath = GetSocketPath(ParrotServiceName) func GetSocketPath(serviceName string) string { return filepath.Join(os.TempDir(), serviceName+".sock") } + +func GetSocketConnection(socketPath string) (net.Conn, error) { + return net.Dial("unix", socketPath) +} diff --git a/go.work b/go.work index e0caca6..6e8b4aa 100644 --- a/go.work +++ b/go.work @@ -3,4 +3,5 @@ go 1.24.4 use ( . services/example + services/parrot ) diff --git a/main.go b/main.go index 028586d..e1b404f 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "context" "github.com/DariusKlein/kleinCommand/commands/config" + "github.com/DariusKlein/kleinCommand/commands/service" "github.com/DariusKlein/kleinCommand/commands/templateCommand" "github.com/DariusKlein/kleinCommand/common" "github.com/urfave/cli/v3" @@ -37,6 +38,7 @@ func main() { Commands: []*cli.Command{ config.Category(), templateCommand.Category(), + service.Category(), }, } diff --git a/services/baseService.go b/services/baseService.go index 51f168b..dbb7d0d 100644 --- a/services/baseService.go +++ b/services/baseService.go @@ -10,7 +10,7 @@ import ( "time" ) -func BaseService(socketPath string, logic func(string)) { +func BaseService(socketPath string, logic func(string, net.Conn)) { // Remove socket path on os.Interrupt and syscall.SIGTERM common.CatchInterrupt(func() { os.Remove(socketPath) @@ -70,7 +70,7 @@ func BaseService(socketPath string, logic func(string)) { common.DeleteSelf() } -func handleConnection(conn net.Conn, logic func(string), listener net.Listener) { +func handleConnection(conn net.Conn, logic func(string, net.Conn), listener net.Listener) { defer conn.Close() scanner := bufio.NewScanner(conn) @@ -81,7 +81,7 @@ func handleConnection(conn net.Conn, logic func(string), listener net.Listener) log.Println("Shutdown command received, exiting.") listener.Close() } else { - logic(input) + logic(input, conn) } } } diff --git a/services/binaries/exampleService b/services/binaries/exampleService index c493888..40942ec 100755 Binary files a/services/binaries/exampleService and b/services/binaries/exampleService differ diff --git a/services/binaries/exampleService.exe b/services/binaries/exampleService.exe index c798f3a..084ec80 100755 Binary files a/services/binaries/exampleService.exe and b/services/binaries/exampleService.exe differ diff --git a/services/binaries/parrotService b/services/binaries/parrotService new file mode 100755 index 0000000..9ac84df Binary files /dev/null and b/services/binaries/parrotService differ diff --git a/services/binaries/parrotService.exe b/services/binaries/parrotService.exe new file mode 100755 index 0000000..61922c2 Binary files /dev/null and b/services/binaries/parrotService.exe differ diff --git a/services/example/main.go b/services/example/main.go index 79be5fc..74213e3 100644 --- a/services/example/main.go +++ b/services/example/main.go @@ -3,15 +3,11 @@ package main import ( "github.com/DariusKlein/kleinCommand/common" "github.com/DariusKlein/kleinCommand/services" + "net" ) var socketPath = common.ExampleServiceSocketPath func main() { - services.BaseService(socketPath, func(command string) { - switch command { - case "example\n": - - } - }) + services.BaseService(socketPath, func(command string, conn net.Conn) {}) } diff --git a/services/linuxServices.go b/services/linuxServices.go index 5839133..0c2c41f 100644 --- a/services/linuxServices.go +++ b/services/linuxServices.go @@ -3,6 +3,7 @@ package services //go:generate go build -o binaries/ ./example +//go:generate go build -o binaries/ ./parrot import ( _ "embed" @@ -14,6 +15,9 @@ import ( //go:embed binaries/exampleService var exampleService []byte +//go:embed binaries/parrotService +var parrotService []byte + func runService(name string, file []byte) error { tempFile, err := os.CreateTemp("", name) if err != nil { diff --git a/services/parrot/go.mod b/services/parrot/go.mod new file mode 100644 index 0000000..8278650 --- /dev/null +++ b/services/parrot/go.mod @@ -0,0 +1,3 @@ +module parrotService + +go 1.24.4 diff --git a/services/parrot/main.go b/services/parrot/main.go new file mode 100644 index 0000000..d806b83 --- /dev/null +++ b/services/parrot/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "github.com/DariusKlein/kleinCommand/common" + "github.com/DariusKlein/kleinCommand/services" + "log" + "net" +) + +var socketPath = common.ParrotServiceSocketPath + +func main() { + services.BaseService(socketPath, func(command string, conn net.Conn) { + _, err := conn.Write([]byte(command)) + if err != nil { + log.Println(err.Error()) + } + }) +} diff --git a/services/services.go b/services/services.go index e7cd575..67c886d 100644 --- a/services/services.go +++ b/services/services.go @@ -7,3 +7,7 @@ import ( func RunExampleService() error { return runService(common.ExampleServiceName, exampleService) } + +func RunParrotService() error { + return runService(common.ParrotServiceName, parrotService) +} diff --git a/services/windowsServices.go b/services/windowsServices.go index a3a8e3e..6f8123f 100644 --- a/services/windowsServices.go +++ b/services/windowsServices.go @@ -3,6 +3,7 @@ package services //go:generate go build -o binaries/ ./example +//go:generate go build -o binaries/ ./parrot import ( _ "embed" @@ -14,6 +15,9 @@ import ( //go:embed binaries/exampleService.exe var exampleService []byte +//go:embed binaries/parrotService.exe +var parrotService []byte + func runService(name string, file []byte) error { executableName := name + ".exe" tempFile, err := os.CreateTemp("", executableName)