- Server no longer mirrors app.Runtime services (gov/svc/pwSvc/...): 574 call sites now use accessors in runtime_accessors.go - backgroundLoop (mutex+sync.Once) stops sweeper/publisher/reminder/wsGC goroutines race-free (baseline44161d2areproduced DATA RACE; now green under -race) - goose 00071 duplicate (dialogue merge1da17a28brought two 00071): context-conflict-adjudications renumbered to 00072; dev DB applied only through 00070 so zero data migration - task_finalize tests build minimal app.Runtime; test injection via serverTestOverrides + setOverride* (explicit-nil markers for fail-closed cases)
105 lines
3.5 KiB
Go
105 lines
3.5 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"chat-agent-system/internal/projectinstance"
|
|
)
|
|
|
|
func (s *Server) handleGetWorkflowInstance(w http.ResponseWriter, r *http.Request) {
|
|
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
|
if err != nil || instanceID <= 0 {
|
|
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"invalid instance id"}`)
|
|
return
|
|
}
|
|
if s.instSvc() == nil || !s.instSvc().Available() {
|
|
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE","message":"项目实例服务不可用"}`)
|
|
return
|
|
}
|
|
detail, err := s.instSvc().GetInstanceDetail(r.Context(), instanceID)
|
|
if err != nil {
|
|
writeProjectInstanceError(w, err)
|
|
return
|
|
}
|
|
if _, ok := s.requireProjectAccess(w, r, detail.Instance.ProjectID); !ok {
|
|
return
|
|
}
|
|
writeJSONResponse(w, http.StatusOK, detail)
|
|
}
|
|
|
|
func (s *Server) handleGetStageReadiness(w http.ResponseWriter, r *http.Request) {
|
|
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
|
if err != nil || instanceID <= 0 {
|
|
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"invalid instance id"}`)
|
|
return
|
|
}
|
|
stageKey := r.PathValue("stage")
|
|
if s.instSvc() == nil || !s.instSvc().Available() {
|
|
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE","message":"项目实例服务不可用"}`)
|
|
return
|
|
}
|
|
detail, err := s.instSvc().GetInstanceDetail(r.Context(), instanceID)
|
|
if err != nil {
|
|
writeProjectInstanceError(w, err)
|
|
return
|
|
}
|
|
user, ok := s.requireProjectAccess(w, r, detail.Instance.ProjectID)
|
|
if !ok {
|
|
return
|
|
}
|
|
isCreator, _ := s.pwSvc().IsProjectCreator(r.Context(), detail.Instance.ProjectID, user.ID)
|
|
readiness, err := s.instSvc().GetStageReadiness(r.Context(), instanceID, stageKey, user.ID, isCreator)
|
|
if err != nil {
|
|
writeProjectInstanceError(w, err)
|
|
return
|
|
}
|
|
writeJSONResponse(w, http.StatusOK, readiness)
|
|
}
|
|
|
|
func (s *Server) handleAdvanceStage(w http.ResponseWriter, r *http.Request) {
|
|
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
|
if err != nil || instanceID <= 0 {
|
|
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"invalid instance id"}`)
|
|
return
|
|
}
|
|
stageKey := r.PathValue("stage")
|
|
if s.instSvc() == nil || !s.instSvc().Available() {
|
|
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE","message":"项目实例服务不可用"}`)
|
|
return
|
|
}
|
|
detail, err := s.instSvc().GetInstanceDetail(r.Context(), instanceID)
|
|
if err != nil {
|
|
writeProjectInstanceError(w, err)
|
|
return
|
|
}
|
|
user, ok := s.requireProjectAccess(w, r, detail.Instance.ProjectID)
|
|
if !ok {
|
|
return
|
|
}
|
|
isCreator, _ := s.pwSvc().IsProjectCreator(r.Context(), detail.Instance.ProjectID, user.ID)
|
|
var req projectinstance.AdvanceStageInput
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil && r.ContentLength > 0 {
|
|
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"无效的 JSON 请求体"}`)
|
|
return
|
|
}
|
|
if req.StageKey == "" {
|
|
req.StageKey = stageKey
|
|
}
|
|
result, err := s.instSvc().AdvanceStage(r.Context(), instanceID, user.ID, isCreator, req)
|
|
if err != nil {
|
|
writeProjectInstanceError(w, err)
|
|
return
|
|
}
|
|
if s.notifySvc() != nil && result.CompletedStageInstanceID > 0 {
|
|
_ = s.notifySvc().ConfirmStageAdvanceRequest(
|
|
r.Context(),
|
|
result.CompletedStageInstanceID,
|
|
result.CompletedReadinessRevision,
|
|
user.ID,
|
|
)
|
|
}
|
|
writeJSONResponse(w, http.StatusOK, result)
|
|
}
|