170 lines
4 KiB
Go
170 lines
4 KiB
Go
package apic
|
||
|
||
import (
|
||
"caddydash/config"
|
||
"context"
|
||
"log"
|
||
"os"
|
||
"os/exec"
|
||
"sync"
|
||
"time"
|
||
|
||
"github.com/infinite-iroha/touka"
|
||
)
|
||
|
||
type CaddyRunning struct {
|
||
running bool
|
||
mu sync.Mutex
|
||
}
|
||
|
||
func (c *CaddyRunning) IsRunning() bool {
|
||
c.mu.Lock()
|
||
defer c.mu.Unlock()
|
||
return c.running
|
||
}
|
||
|
||
func (c *CaddyRunning) SetRunning(running bool) {
|
||
c.mu.Lock()
|
||
defer c.mu.Unlock()
|
||
c.running = running
|
||
}
|
||
|
||
var caddyRunning = &CaddyRunning{}
|
||
|
||
func RunCaddy(cfg *config.Config) error {
|
||
if caddyRunning.IsRunning() {
|
||
return nil
|
||
}
|
||
ctx, cancel := context.WithCancel(context.Background())
|
||
caddyPath := cfg.Server.CaddyDir + "caddy"
|
||
cmd := exec.CommandContext(ctx, caddyPath, "run", "--config", "Caddyfile")
|
||
cmd.Stdout = os.Stdout
|
||
cmd.Stderr = os.Stderr
|
||
caddyRunning.SetRunning(true)
|
||
|
||
err := cmd.Start()
|
||
if err != nil {
|
||
cancel()
|
||
return err
|
||
}
|
||
|
||
go func() {
|
||
waitErr := cmd.Wait()
|
||
caddyRunning.SetRunning(false)
|
||
log.Printf("Caddy process exited with error: %v", waitErr)
|
||
cancel()
|
||
if waitErr != nil {
|
||
// 如果 Caddy 非正常退出(例如崩溃),Wait() 会返回 *exec.ExitError
|
||
// 对于优雅关闭,如果 Caddy 接收到 SIGTERM 并正常退出,Wait() 返回 nil
|
||
// 只有当进程以非零状态码退出时,Wait() 才返回非 nil 的 ExitError
|
||
// 这里的日志输出应由外部日志库处理,而不是标准库log
|
||
if exitErr, ok := waitErr.(*exec.ExitError); ok {
|
||
log.Printf("Caddy process exited with non-zero status: %v", exitErr)
|
||
} else {
|
||
log.Printf("Caddy process exited with error: %v", waitErr)
|
||
}
|
||
} else {
|
||
log.Println("Caddy process exited gracefully.")
|
||
}
|
||
}()
|
||
return nil
|
||
}
|
||
|
||
func StartCaddy(cfg *config.Config) touka.HandlerFunc {
|
||
return func(c *touka.Context) {
|
||
if caddyRunning.IsRunning() {
|
||
c.JSON(200, map[string]string{"message": "Caddy is already running"})
|
||
return
|
||
}
|
||
go func() {
|
||
err := RunCaddy(cfg)
|
||
if err != nil {
|
||
c.Errorf("Failed to start Caddy: %v", err)
|
||
c.JSON(500, map[string]string{"error": err.Error()})
|
||
return
|
||
}
|
||
}()
|
||
c.JSON(200, map[string]string{"message": "Caddy is starting"})
|
||
}
|
||
}
|
||
|
||
func IsCaddyRunning() touka.HandlerFunc {
|
||
return func(c *touka.Context) {
|
||
if caddyRunning.IsRunning() {
|
||
c.JSON(200, map[string]string{"message": "Caddy is running"})
|
||
} else {
|
||
c.JSON(200, map[string]string{"message": "Caddy is not running"})
|
||
}
|
||
}
|
||
}
|
||
|
||
func StopCaddy() touka.HandlerFunc {
|
||
return func(c *touka.Context) {
|
||
if !caddyRunning.IsRunning() {
|
||
c.JSON(200, map[string]string{"message": "Caddy is not running"})
|
||
return
|
||
}
|
||
client := c.GetHTTPC()
|
||
rb := client.NewRequestBuilder("POST", "http://127.0.0.1:2019/stop")
|
||
resp, err := rb.Execute()
|
||
if err != nil {
|
||
c.JSON(500, map[string]string{"error": err.Error()})
|
||
return
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != 200 {
|
||
c.JSON(resp.StatusCode, map[string]string{"error": "Failed to stop Caddy"})
|
||
return
|
||
}
|
||
|
||
caddyRunning.SetRunning(false)
|
||
c.JSON(200, map[string]string{"message": "Caddy stopped successfully"})
|
||
}
|
||
}
|
||
|
||
func RestartCaddy(cfg *config.Config) touka.HandlerFunc {
|
||
return func(c *touka.Context) {
|
||
if !caddyRunning.IsRunning() {
|
||
c.JSON(200, map[string]string{"message": "Caddy is not running, starting it now"})
|
||
go func() {
|
||
err := RunCaddy(cfg)
|
||
if err != nil {
|
||
c.Errorf("Failed to start Caddy: %v", err)
|
||
|
||
}
|
||
}()
|
||
return
|
||
}
|
||
|
||
// StopCaddy
|
||
client := c.GetHTTPC()
|
||
rb := client.NewRequestBuilder("POST", "http://127.0.0.1:2019/stop")
|
||
resp, err := rb.Execute()
|
||
if err != nil {
|
||
c.JSON(500, map[string]string{"error": err.Error()})
|
||
return
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != 200 {
|
||
c.JSON(resp.StatusCode, map[string]string{"error": "Failed to stop Caddy for restart"})
|
||
return
|
||
}
|
||
|
||
// 等待caddy关闭
|
||
for caddyRunning.IsRunning() {
|
||
time.Sleep(500 * time.Millisecond) // 等待500ms
|
||
}
|
||
|
||
// StartCaddy
|
||
go func() {
|
||
err := RunCaddy(cfg)
|
||
if err != nil {
|
||
c.Errorf("Failed to restart Caddy: %v", err)
|
||
}
|
||
}()
|
||
c.JSON(200, map[string]string{"message": "Caddy is restarting"})
|
||
|
||
}
|
||
}
|