mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
Merge pull request #1012 from fudiwei/main
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase"
|
||||
)
|
||||
|
||||
func Serve(app *pocketbase.PocketBase) error {
|
||||
return app.Start()
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
)
|
||||
|
||||
type winscHandler struct {
|
||||
pb *pocketbase.PocketBase
|
||||
elog *eventlog.Log
|
||||
}
|
||||
|
||||
func (h *winscHandler) Execute(args []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (bool, uint32) {
|
||||
go func() {
|
||||
if err := h.pb.Start(); err != nil {
|
||||
h.elog.Error(999, fmt.Sprintf("Start failed: %v", err))
|
||||
}
|
||||
}()
|
||||
|
||||
s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}
|
||||
for {
|
||||
select {
|
||||
case c := <-r:
|
||||
switch c.Cmd {
|
||||
case svc.Interrogate:
|
||||
s <- c.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
event := new(core.TerminateEvent)
|
||||
event.App = h.pb
|
||||
h.pb.OnTerminate().Trigger(event, func(e *core.TerminateEvent) error {
|
||||
return e.App.ResetBootstrapState()
|
||||
})
|
||||
s <- svc.Status{State: svc.Stopped}
|
||||
return false, 0
|
||||
default:
|
||||
h.elog.Warning(998, fmt.Sprintf("unexpected control request: %v", c.Cmd))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Serve(app *pocketbase.PocketBase) error {
|
||||
if isWinsc, _ := svc.IsWindowsService(); isWinsc {
|
||||
elog, _ := eventlog.Open(winscName)
|
||||
defer elog.Close()
|
||||
return svc.Run(winscName, &winscHandler{pb: app, elog: elog})
|
||||
}
|
||||
|
||||
return app.Start()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewWinscCommand(app core.App) *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "winsc",
|
||||
Short: "Install/Uninstall Windows service (Not supported on non-Windows OS)",
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
const winscName = "certimate"
|
||||
|
||||
func NewWinscCommand(app core.App) *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "winsc",
|
||||
Short: "Install/Uninstall Windows service",
|
||||
}
|
||||
|
||||
command.AddCommand(winscInstallCommand(app))
|
||||
command.AddCommand(winscUninstallCommand(app))
|
||||
command.AddCommand(winscStartCommand(app))
|
||||
command.AddCommand(winscStopCommand(app))
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func winscInstallCommand(app core.App) *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "install [args...]",
|
||||
Example: "winsc install",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
srvPath, err := os.Executable()
|
||||
if err != nil {
|
||||
srvPath = os.Args[0]
|
||||
}
|
||||
|
||||
srvArgs := []string{"serve"}
|
||||
srvArgs = append(srvArgs, args...)
|
||||
|
||||
manager, err := mgr.Connect()
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to connect to service manager: %v", err))
|
||||
return
|
||||
}
|
||||
defer manager.Disconnect()
|
||||
|
||||
config := mgr.Config{
|
||||
DisplayName: "Certimate",
|
||||
Description: "https://github.com/certimate-go/certimate",
|
||||
StartType: mgr.StartAutomatic,
|
||||
}
|
||||
service, err := manager.CreateService(winscName, srvPath, config, srvArgs...)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to create service: %v", err))
|
||||
return
|
||||
}
|
||||
defer service.Close()
|
||||
|
||||
eventlog.InstallAsEventCreate(winscName, eventlog.Error|eventlog.Warning|eventlog.Info)
|
||||
slog.Info(fmt.Sprintf("service '%s' installed", winscName))
|
||||
|
||||
if err := service.Start(); err != nil {
|
||||
slog.Warn(fmt.Sprintf("failed to start service: %v", err))
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("service '%s' started", winscName))
|
||||
},
|
||||
DisableFlagParsing: true,
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func winscUninstallCommand(app core.App) *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "uninstall",
|
||||
Example: "winsc uninstall",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
manager, err := mgr.Connect()
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to connect to service manager: %v", err))
|
||||
return
|
||||
}
|
||||
defer manager.Disconnect()
|
||||
|
||||
service, err := manager.OpenService(winscName)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to open service: %v", err))
|
||||
return
|
||||
}
|
||||
defer service.Close()
|
||||
|
||||
status, err := service.Query()
|
||||
if err == nil && status.State != svc.Stopped {
|
||||
_, err = service.Control(svc.Stop)
|
||||
if err != nil {
|
||||
slog.Warn(fmt.Sprintf("failed to stop service: %v", err))
|
||||
}
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
slog.Info(fmt.Sprintf("service '%s' stopped", winscName))
|
||||
}
|
||||
|
||||
if err = service.Delete(); err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to delete service: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
eventlog.Remove(winscName)
|
||||
slog.Info(fmt.Sprintf("service '%s' uninstalled", winscName))
|
||||
},
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func winscStartCommand(app core.App) *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "start",
|
||||
Example: "winsc start",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
manager, err := mgr.Connect()
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to connect to service manager: %v", err))
|
||||
return
|
||||
}
|
||||
defer manager.Disconnect()
|
||||
|
||||
service, err := manager.OpenService(winscName)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to open service: %v", err))
|
||||
return
|
||||
}
|
||||
defer service.Close()
|
||||
|
||||
if err := service.Start(); err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to start service: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("service '%s' started", winscName))
|
||||
},
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func winscStopCommand(app core.App) *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "stop",
|
||||
Example: "winsc stop",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
manager, err := mgr.Connect()
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to connect to service manager: %v", err))
|
||||
return
|
||||
}
|
||||
defer manager.Disconnect()
|
||||
|
||||
service, err := manager.OpenService(winscName)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to open service: %v", err))
|
||||
return
|
||||
}
|
||||
defer service.Close()
|
||||
|
||||
status, err := service.Query()
|
||||
if err == nil && status.State != svc.Stopped {
|
||||
_, err = service.Control(svc.Stop)
|
||||
if err != nil {
|
||||
slog.Warn(fmt.Sprintf("failed to stop service: %v", err))
|
||||
}
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
slog.Info(fmt.Sprintf("service '%s' stopped", winscName))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
@@ -218,7 +218,7 @@ require (
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/sys v0.37.0
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
|
||||
@@ -206,7 +206,7 @@ func (wd *workflowDispatcher) tryExecuteAsync(task *taskInfo) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
wd.syslog.Error(fmt.Sprintf("workflow dispatcher panic: %v", r), slog.String("workflowId", task.WorkflowId), slog.String("runId", task.RunId))
|
||||
slog.Default().Error(fmt.Sprintf("workflow dispatcher panic: %v, stack trace: %s", r, string(debug.Stack())), slog.String("workflowId", task.WorkflowId), slog.String("runId", task.RunId))
|
||||
slog.Error(fmt.Sprintf("workflow dispatcher panic: %v, stack trace: %s", r, string(debug.Stack())), slog.String("workflowId", task.WorkflowId), slog.String("runId", task.RunId))
|
||||
|
||||
if workflowRun != nil {
|
||||
workflowRun.Status = domain.WorkflowRunStatusTypeFailed
|
||||
|
||||
@@ -60,7 +60,7 @@ func (we *workflowEngine) Invoke(ctx context.Context, execution WorkflowExecutio
|
||||
if r := recover(); r != nil {
|
||||
we.fireOnErrorHooks(ctx, fmt.Errorf("workflow engine panic: %v", r))
|
||||
we.syslog.Error(fmt.Sprintf("workflow engine panic: %v", r), slog.String("workflowId", execution.WorkflowId), slog.String("runId", execution.RunId))
|
||||
slog.Default().Error(fmt.Sprintf("workflow engine panic: %v, stack trace: %s", r, string(debug.Stack())), slog.String("workflowId", execution.WorkflowId), slog.String("runId", execution.RunId))
|
||||
slog.Error(fmt.Sprintf("workflow engine panic: %v, stack trace: %s", r, string(debug.Stack())), slog.String("workflowId", execution.WorkflowId), slog.String("runId", execution.RunId))
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ func main() {
|
||||
})
|
||||
|
||||
app.RootCmd.AddCommand(cmd.NewInternalCommand(app))
|
||||
app.RootCmd.AddCommand(cmd.NewWinscCommand(app))
|
||||
|
||||
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||
scheduler.Register()
|
||||
@@ -72,7 +73,7 @@ func main() {
|
||||
return e.Next()
|
||||
})
|
||||
|
||||
if err := app.Start(); err != nil {
|
||||
if err := cmd.Serve(app); err != nil {
|
||||
slog.Error("[CERTIMATE] Start failed.", slog.Any("error", err))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user