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 .
|
||||
@ -35,11 +35,14 @@ func Action(context context.Context, c *cli.Command) error {
|
||||
func subCategory() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "sub-category-template",
|
||||
Aliases: []string{"category"},
|
||||
Usage: "commands for sub-category-template",
|
||||
Action: Action,
|
||||
Commands: []*cli.Command{
|
||||
//commands or sub-category here
|
||||
subcommands.Template(),
|
||||
subcommands.StartServiceTemplate(),
|
||||
subcommands.StopServiceTemplate(),
|
||||
},
|
||||
HideHelpCommand: true,
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ var templateVar bool
|
||||
// Template Command
|
||||
func Template() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "template command",
|
||||
Name: "basic",
|
||||
Usage: "template command usage",
|
||||
Action: templateAction,
|
||||
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