feat(render+node-agent+admin): install fonts on all render nodes + verify
Build backend images / build content-svc (push) Failing after 53s
Build backend images / build file-svc (push) Failing after 47s
Build backend images / build gateway (push) Failing after 52s
Build backend images / build identity-svc (push) Failing after 58s
Build backend images / build notification-svc (push) Failing after 55s
Build backend images / build render-svc (push) Failing after 59s
Build backend images / build studio-svc (push) Failing after 48s
Build backend images / build content-svc (push) Failing after 53s
Build backend images / build file-svc (push) Failing after 47s
Build backend images / build gateway (push) Failing after 52s
Build backend images / build identity-svc (push) Failing after 58s
Build backend images / build notification-svc (push) Failing after 55s
Build backend images / build render-svc (push) Failing after 59s
Build backend images / build studio-svc (push) Failing after 48s
Push a font once → every node installs it → admin sees per-node status. - render-svc: font_requests + node_fonts tables (mig 25); admin GET/POST/DELETE /v1/node-fonts (with per-node status matrix); internal (HMAC) GET pending + POST status for node-agents - node-agent: fontSyncLoop polls pending fonts every 60s, downloads, installs (Windows Fonts dir + registry / macOS / linux fc-cache), reports Installed/Failed - gateway: /v1/node-fonts/* → render - admin /admin/node-fonts: upload a .ttf/.otf → install on all nodes; per-node Installed/Pending/Failed badges + counts + delete Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,48 @@ func decodeJSON(resp *http.Response, out any) error {
|
||||
return json.NewDecoder(resp.Body).Decode(out)
|
||||
}
|
||||
|
||||
// ── Fonts ───────────────────────────────────────────────────────────────────
|
||||
|
||||
type PendingFont struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SystemName string `json:"system_name"`
|
||||
FileURL string `json:"file_url"`
|
||||
}
|
||||
|
||||
type pendingFontsResp struct {
|
||||
Fonts []PendingFont `json:"fonts"`
|
||||
}
|
||||
|
||||
// PendingFonts returns fonts this node still needs to install.
|
||||
func (c *Client) PendingFonts(ctx context.Context, nodeID string) ([]PendingFont, error) {
|
||||
resp, err := c.do(ctx, http.MethodGet, fmt.Sprintf("/v1/internal/nodes/%s/fonts/pending", nodeID), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
resp.Body.Close()
|
||||
return nil, fmt.Errorf("pending fonts status %d", resp.StatusCode)
|
||||
}
|
||||
var out pendingFontsResp
|
||||
if err := decodeJSON(resp, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Fonts, nil
|
||||
}
|
||||
|
||||
// ReportFont reports a font install result (Installed | Failed).
|
||||
func (c *Client) ReportFont(ctx context.Context, nodeID, requestID, status, errMsg string) error {
|
||||
resp, err := c.do(ctx, http.MethodPost,
|
||||
fmt.Sprintf("/v1/internal/nodes/%s/fonts/%s/status", nodeID, requestID),
|
||||
map[string]string{"status": status, "error": errMsg})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ── Domain types ──────────────────────────────────────────────────────────────
|
||||
|
||||
// OnlineRequest is sent once on startup to mark the node Ready.
|
||||
|
||||
Reference in New Issue
Block a user