This commit is contained in:
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/fonu/fonu/internal/service"
|
||||
"github.com/fonu/fonu/internal/settings"
|
||||
"github.com/fonu/fonu/internal/traffic"
|
||||
"github.com/fonu/fonu/internal/updater"
|
||||
)
|
||||
|
||||
type Deps struct {
|
||||
@@ -34,6 +35,7 @@ type Deps struct {
|
||||
FRPMulti *frp.Service
|
||||
Traffic *traffic.Collector
|
||||
Notify *notify.Service
|
||||
Updater *updater.Client
|
||||
StaticFS fs.FS
|
||||
StartedAt string
|
||||
}
|
||||
|
||||
@@ -74,7 +74,8 @@ func tokenDeniedPath(path string) bool {
|
||||
if path == "/api/auth/password" || path == "/api/auth/logout" {
|
||||
return true
|
||||
}
|
||||
return strings.HasPrefix(path, "/api/settings/tokens")
|
||||
return strings.HasPrefix(path, "/api/settings/tokens") ||
|
||||
strings.HasPrefix(path, "/api/system/update")
|
||||
}
|
||||
|
||||
func sessionIDFromContext(ctx context.Context) string {
|
||||
|
||||
@@ -27,6 +27,7 @@ func NewRouter(deps Deps) http.Handler {
|
||||
metricsHandler: NewMetricsHandler(deps.Metrics),
|
||||
discoveryHandler: NewDiscoveryHandler(deps.Discovery),
|
||||
frpmultiHandler: NewFRPMultiHandler(deps.FRPMulti),
|
||||
updateHandler: NewUpdateHandler(deps.Updater),
|
||||
authSvc: deps.Auth,
|
||||
staticFS: deps.StaticFS,
|
||||
}
|
||||
@@ -94,6 +95,8 @@ func NewRouter(deps Deps) http.Handler {
|
||||
protect("GET /api/logs/system", r.logsHandler.System)
|
||||
protect("GET /api/metrics/history", r.metricsHandler.History)
|
||||
protect("GET /api/logs/stream", r.logsHandler.Stream)
|
||||
protect("GET /api/system/update/status", r.updateHandler.Status)
|
||||
protect("POST /api/system/update/apply", r.updateHandler.Apply)
|
||||
protect("GET /api/backup/export", r.backupHandler.Export)
|
||||
protect("POST /api/backup/restore", r.backupHandler.Restore)
|
||||
protect("GET /api/backup/archives", r.backupHandler.ListArchives)
|
||||
@@ -190,6 +193,7 @@ type Router struct {
|
||||
metricsHandler *MetricsHandler
|
||||
discoveryHandler *DiscoveryHandler
|
||||
frpmultiHandler *FRPMultiHandler
|
||||
updateHandler *UpdateHandler
|
||||
authSvc *auth.Service
|
||||
staticFS fs.FS
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/fonu/fonu/internal/updater"
|
||||
)
|
||||
|
||||
type UpdateHandler struct {
|
||||
client *updater.Client
|
||||
}
|
||||
|
||||
func NewUpdateHandler(client *updater.Client) *UpdateHandler {
|
||||
return &UpdateHandler{client: client}
|
||||
}
|
||||
|
||||
func (h *UpdateHandler) Status(w http.ResponseWriter, r *http.Request) {
|
||||
if h.client == nil || !h.client.Enabled() {
|
||||
writeJSON(w, http.StatusOK, updater.Status{
|
||||
Enabled: false,
|
||||
Phase: updater.PhaseIdle,
|
||||
Message: "当前部署未启用一键升级",
|
||||
})
|
||||
return
|
||||
}
|
||||
status, err := h.client.Status(r.Context())
|
||||
if err != nil {
|
||||
writeError(r, w, http.StatusBadGateway, "读取升级状态失败", err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, status)
|
||||
}
|
||||
|
||||
func (h *UpdateHandler) Apply(w http.ResponseWriter, r *http.Request) {
|
||||
if h.client == nil || !h.client.Enabled() {
|
||||
writeError(r, w, http.StatusServiceUnavailable, "当前部署未启用一键升级")
|
||||
return
|
||||
}
|
||||
status, err := h.client.Apply(r.Context())
|
||||
if err != nil {
|
||||
writeError(r, w, http.StatusBadGateway, "启动升级失败", err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusAccepted, status)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUpdateHandlerDisabled(t *testing.T) {
|
||||
handler := NewUpdateHandler(nil)
|
||||
|
||||
statusRecorder := httptest.NewRecorder()
|
||||
statusReq := httptest.NewRequest(http.MethodGet, "/api/system/update/status", nil)
|
||||
handler.Status(statusRecorder, statusReq)
|
||||
if statusRecorder.Code != http.StatusOK {
|
||||
t.Fatalf("状态接口期望 200,实际 %d", statusRecorder.Code)
|
||||
}
|
||||
if body := statusRecorder.Body.String(); !strings.Contains(body, `"enabled":false`) {
|
||||
t.Fatalf("未返回 enabled=false: %s", body)
|
||||
}
|
||||
|
||||
applyRecorder := httptest.NewRecorder()
|
||||
applyReq := httptest.NewRequest(http.MethodPost, "/api/system/update/apply", nil)
|
||||
handler.Apply(applyRecorder, applyReq)
|
||||
if applyRecorder.Code != http.StatusServiceUnavailable {
|
||||
t.Fatalf("升级接口期望 503,实际 %d", applyRecorder.Code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user