Files
worker/internal/webapp/handlers_apps.go
Gleb Tv 2c7a0236da feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
2026-07-13 17:55:14 +03:00

104 строки
2.3 KiB
Go

package webapp
import "net/http"
// handleApps lists the inventory rows the most recent refresh loop
// persisted. Each row links to the detail view at /apps/:id, which
// Phase 1 implements as a single-process summary (comm, cmdline,
// cwd, ports, uptime).
func (s *Server) handleApps(w http.ResponseWriter, r *http.Request) {
writeNoStore(w)
sess, _ := sessionFromContext(r.Context())
apps := s.inventory.Snapshot()
data := appsPageData{
basePageData: s.newBasePage(r, "Discovered apps", sess),
Apps: apps,
}
if err := s.templates.Execute(w, "apps.html", data); err != nil {
s.deps.Logger.Printf("render apps: %v", err)
http.Error(w, "template error", http.StatusInternalServerError)
}
}
// handleAppDetail renders the detail page for a single inventory
// row. Phase 1 has no grouping, so :id is the row index in the
// snapshot (matching the table id column).
func (s *Server) handleAppDetail(w http.ResponseWriter, r *http.Request) {
writeNoStore(w)
sess, _ := sessionFromContext(r.Context())
id := r.PathValue("id")
apps := s.inventory.Snapshot()
var found *DiscoveredApp
for i := range apps {
if idMatch(&apps[i], id, i) {
found = &apps[i]
break
}
}
if found == nil {
http.NotFound(w, r)
return
}
data := appDetailPageData{
basePageData: s.newBasePage(r, "App: "+found.Name, sess),
App: *found,
}
if err := s.templates.Execute(w, "app_detail.html", data); err != nil {
s.deps.Logger.Printf("render app detail: %v", err)
http.Error(w, "template error", http.StatusInternalServerError)
}
}
// idMatch matches either by pid (when id is a positive integer) or
// by name (otherwise). Keeps URLs short and avoids leaking pids to
// browser history.
func idMatch(a *DiscoveredApp, id string, idx int) bool {
if a.Name == id {
return true
}
if id == pidOrIndex(a, idx) {
return true
}
return false
}
func pidOrIndex(a *DiscoveredApp, idx int) string {
if a.PID > 0 {
return itoa(a.PID)
}
return itoa(idx)
}
func itoa(n int) string {
const digits = "0123456789"
if n == 0 {
return "0"
}
neg := n < 0
if neg {
n = -n
}
var buf [20]byte
i := len(buf)
for n > 0 {
i--
buf[i] = digits[n%10]
n /= 10
}
if neg {
i--
buf[i] = '-'
}
return string(buf[i:])
}
type appsPageData struct {
basePageData
Apps []DiscoveredApp
}
type appDetailPageData struct {
basePageData
App DiscoveredApp
}