feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
84
internal/webapp/handlers_checks.go
Обычный файл
84
internal/webapp/handlers_checks.go
Обычный файл
@@ -0,0 +1,84 @@
|
||||
package webapp
|
||||
|
||||
import "net/http"
|
||||
|
||||
// handleChecks renders the worker's recent result rows. The
|
||||
// runner's in-memory ring buffer supplies the data; Phase 1 reads
|
||||
// from it directly with no extra caching.
|
||||
//
|
||||
// A "Run now" button is rendered on the page but stays disabled
|
||||
// until the control plane accepts one-off check hints. The hint
|
||||
// protocol is gated on the worker-notifier MVP plan
|
||||
// (docs/plans/worker-notifier-mvp.md §N) and on
|
||||
// docs/plans/separate-checks.md §11.6; once both are in place the
|
||||
// RunNowEnabled flag flips to true and the handler reads
|
||||
// s.deps.Runner.SubmitCheckHint(...) instead of the placeholder.
|
||||
func (s *Server) handleChecks(w http.ResponseWriter, r *http.Request) {
|
||||
s.renderRunnerPage(w, r, "Recent checks", "checks.html", func() any {
|
||||
return checksPageData{
|
||||
basePageData: s.newBasePage(r, "Recent checks", sessionFromContextOrEmpty(r)),
|
||||
Rows: s.deps.Runner.RecentResults(50),
|
||||
RunNowEnabled: false,
|
||||
RunNowTooltip: "Run-now lands with the worker hint protocol (worker-notifier-mvp.md §N + separate-checks.md §11.6).",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type checksPageData struct {
|
||||
basePageData
|
||||
Rows []ResultRow
|
||||
RunNowEnabled bool
|
||||
RunNowTooltip string
|
||||
}
|
||||
|
||||
// handleNotifications renders the worker's recent notification
|
||||
// rows. Phase 1 only emits selfcheck alerts (email/telegram via the
|
||||
// cached credentials), but the runner ring buffer is shape-stable
|
||||
// for the main-app-issued notifications coming online in a later
|
||||
// phase.
|
||||
//
|
||||
// A "Resend" button is rendered on the page but stays disabled
|
||||
// until the worker resend protocol exists. Same gating as the
|
||||
// "Run now" button on /checks.
|
||||
func (s *Server) handleNotifications(w http.ResponseWriter, r *http.Request) {
|
||||
s.renderRunnerPage(w, r, "Recent notifications", "notifications.html", func() any {
|
||||
return notificationsPageData{
|
||||
basePageData: s.newBasePage(r, "Recent notifications", sessionFromContextOrEmpty(r)),
|
||||
Rows: s.deps.Runner.RecentNotifications(50),
|
||||
ResendEnabled: false,
|
||||
ResendTooltip: "Resend lands with the worker notification resend protocol (worker-notifier-mvp.md §N).",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type notificationsPageData struct {
|
||||
basePageData
|
||||
Rows []NotificationRow
|
||||
ResendEnabled bool
|
||||
ResendTooltip string
|
||||
}
|
||||
|
||||
// renderRunnerPage is the small boilerplate-killer shared by
|
||||
// handleChecks / handleNotifications / handleApps: write the
|
||||
// no-store header, look up the session, build the page data via the
|
||||
// caller-supplied closure, execute the template, and log + 500 on
|
||||
// error. The closure receives no arguments because each handler
|
||||
// already has its own copy of *Server and *http.Request in scope
|
||||
// (this method is bound to *Server, so the closure captures them).
|
||||
func (s *Server) renderRunnerPage(w http.ResponseWriter, _ *http.Request, logName, tmpl string, build func() any) {
|
||||
writeNoStore(w)
|
||||
if err := s.templates.Execute(w, tmpl, build()); err != nil {
|
||||
s.deps.Logger.Printf("render %s: %v", logName, err)
|
||||
http.Error(w, "template error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// sessionFromContextOrEmpty is a thin wrapper around
|
||||
// sessionFromContext that returns a nil session instead of a bool,
|
||||
// for handlers that pass the session straight into a page-data
|
||||
// struct (the Session zero value is harmless for template
|
||||
// rendering).
|
||||
func sessionFromContextOrEmpty(r *http.Request) *Session {
|
||||
sess, _ := sessionFromContext(r.Context())
|
||||
return sess
|
||||
}
|
||||
Ссылка в новой задаче
Block a user