Added template service launcher
This commit is contained in:
parent
8c2eebc438
commit
e904beb657
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
## windows
|
||||||
|
- GOOS=windows go generate ./services
|
||||||
|
- GOOS=windows go build .
|
||||||
|
## linux
|
||||||
|
- GOOS=linux go generate ./services
|
||||||
|
- GOOS=linux go build .
|
||||||
@ -34,12 +34,15 @@ func Action(context context.Context, c *cli.Command) error {
|
|||||||
// PLACEHOLDER sub-category of CATEGORY NAME Category
|
// PLACEHOLDER sub-category of CATEGORY NAME Category
|
||||||
func subCategory() *cli.Command {
|
func subCategory() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "sub-category-template",
|
Name: "sub-category-template",
|
||||||
Usage: "commands for sub-category-template",
|
Aliases: []string{"category"},
|
||||||
Action: Action,
|
Usage: "commands for sub-category-template",
|
||||||
|
Action: Action,
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
//commands or sub-category here
|
//commands or sub-category here
|
||||||
subcommands.Template(),
|
subcommands.Template(),
|
||||||
|
subcommands.StartServiceTemplate(),
|
||||||
|
subcommands.StopServiceTemplate(),
|
||||||
},
|
},
|
||||||
HideHelpCommand: true,
|
HideHelpCommand: true,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ var templateVar bool
|
|||||||
// Template Command
|
// Template Command
|
||||||
func Template() *cli.Command {
|
func Template() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "template command",
|
Name: "basic",
|
||||||
Usage: "template command usage",
|
Usage: "template command usage",
|
||||||
Action: templateAction,
|
Action: templateAction,
|
||||||
Flags: templateFlags(),
|
Flags: templateFlags(),
|
||||||
23
commands/templateCommand/subcommands/startServiceTemplate.go
Normal file
23
commands/templateCommand/subcommands/startServiceTemplate.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package subcommands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/DariusKlein/kleinCommand/services"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartServiceTemplate Command
|
||||||
|
func StartServiceTemplate() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "start service",
|
||||||
|
Aliases: []string{"start"},
|
||||||
|
Usage: "template command usage",
|
||||||
|
Action: startServiceTemplateAction,
|
||||||
|
ArgsUsage: "args usage",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// startServiceTemplateAction logic for StartServiceTemplate
|
||||||
|
func startServiceTemplateAction(context context.Context, c *cli.Command) error {
|
||||||
|
return services.RunExampleService()
|
||||||
|
}
|
||||||
39
commands/templateCommand/subcommands/stopServiceTemplate.go
Normal file
39
commands/templateCommand/subcommands/stopServiceTemplate.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package subcommands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/DariusKlein/kleinCommand/common"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
"log/slog"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StopServiceTemplate Command
|
||||||
|
func StopServiceTemplate() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "stop service",
|
||||||
|
Aliases: []string{"stop"},
|
||||||
|
Usage: "template command usage",
|
||||||
|
Action: stopServiceTemplateAction,
|
||||||
|
ArgsUsage: "args usage",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// templateAction logic for Template
|
||||||
|
func stopServiceTemplateAction(context context.Context, c *cli.Command) error {
|
||||||
|
conn, err := net.Dial("unix", common.ExampleServiceSocketPath)
|
||||||
|
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
|
||||||
|
}
|
||||||
3
common/constants.go
Normal file
3
common/constants.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
const ExampleServiceName = "exampleService"
|
||||||
18
common/files.go
Normal file
18
common/files.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FileExists(filename string) bool {
|
||||||
|
info, err := os.Stat(filename)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !info.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteSelf() {
|
||||||
|
path, _ := os.Executable()
|
||||||
|
os.Remove(path)
|
||||||
|
}
|
||||||
17
common/interrupt.go
Normal file
17
common/interrupt.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CatchInterrupt(logic func()) {
|
||||||
|
cmd := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(cmd, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-cmd
|
||||||
|
logic()
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
}
|
||||||
12
common/socketPaths.go
Normal file
12
common/socketPaths.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ExampleServiceSocketPath = GetSocketPath(ExampleServiceName)
|
||||||
|
|
||||||
|
func GetSocketPath(serviceName string) string {
|
||||||
|
return filepath.Join(os.TempDir(), serviceName+".sock")
|
||||||
|
}
|
||||||
3
services/example/go.mod
Normal file
3
services/example/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module exampleService
|
||||||
|
|
||||||
|
go 1.24.4
|
||||||
60
services/example/main.go
Normal file
60
services/example/main.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"github.com/DariusKlein/kleinCommand/common"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var socketPath = common.ExampleServiceSocketPath
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
common.CatchInterrupt(func() {
|
||||||
|
os.Remove(socketPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
if common.FileExists(socketPath) {
|
||||||
|
log.Fatal("Socket file exists.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the UNIX socket listener.
|
||||||
|
listener, err := net.Listen("unix", socketPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to listen on socket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
log.Println("Service started, listening on", socketPath)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Accept error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
reader := bufio.NewReader(conn)
|
||||||
|
command, err := reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Read error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if command == "shutdown\n" {
|
||||||
|
log.Println("Shutdown command received, exiting.")
|
||||||
|
// This will cause the listener.Accept() to unblock and the program to exit.
|
||||||
|
listener.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if _, err := os.Stat(socketPath); os.IsNotExist(err) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
common.DeleteSelf()
|
||||||
|
}
|
||||||
10
services/linuxServices.go
Normal file
10
services/linuxServices.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package services
|
||||||
|
|
||||||
|
//go:generate go build ./example
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed exampleService
|
||||||
|
var exampleService []byte
|
||||||
38
services/services.go
Normal file
38
services/services.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/DariusKlein/kleinCommand/common"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RunExampleService() error {
|
||||||
|
return runService(common.ExampleServiceName, exampleService)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runService(name string, file []byte) error {
|
||||||
|
tempFile, err := os.CreateTemp("", name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = tempFile.Write(file); err != nil {
|
||||||
|
tempFile.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = tempFile.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.Chmod(tempFile.Name(), 0777); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(tempFile.Name())
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
||||||
|
if err = cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
10
services/windowsServices.go
Normal file
10
services/windowsServices.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package services
|
||||||
|
|
||||||
|
//go:generate go build ./example
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed exampleService.exe
|
||||||
|
var exampleService []byte
|
||||||
Loading…
x
Reference in New Issue
Block a user