master
go 150 lines 3.92 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package dyncfg
4
5 import (
6 "fmt"
7 "strconv"
8 "sync"
9 "time"
10
11 "github.com/netdata/netdata/go/plugins/pkg/netdataapi"
12 fnpkg "github.com/netdata/netdata/go/plugins/plugin/framework/functions"
13 )
14
15 // Responder handles standardized responses for dyncfg operations
16 type Responder struct {
17 api *netdataapi.API
18
19 finalizeMux sync.RWMutex
20 finalize fnpkg.TerminalFinalizer
21 }
22
23 // NewResponder creates a new responder
24 func NewResponder(api *netdataapi.API) *Responder {
25 return &Responder{
26 api: api,
27 finalize: fnpkg.DirectTerminalFinalizer,
28 }
29 }
30
31 // SetTerminalFinalizer overrides terminal response finalization behavior.
32 func (r *Responder) SetTerminalFinalizer(finalize fnpkg.TerminalFinalizer) {
33 r.finalizeMux.Lock()
34 defer r.finalizeMux.Unlock()
35
36 if finalize == nil {
37 r.finalize = fnpkg.DirectTerminalFinalizer
38 return
39 }
40 r.finalize = finalize
41 }
42
43 // TerminalFinalizer returns the currently configured terminal finalizer.
44 func (r *Responder) TerminalFinalizer() fnpkg.TerminalFinalizer {
45 r.finalizeMux.RLock()
46 defer r.finalizeMux.RUnlock()
47 return r.finalize
48 }
49
50 func (r *Responder) finalizeTerminal(uid, source string, emit func()) bool {
51 r.finalizeMux.RLock()
52 finalize := r.finalize
53 r.finalizeMux.RUnlock()
54 return finalize(uid, source, emit)
55 }
56
57 // SendCodef sends a response with a specific code and message
58 func (r *Responder) SendCodef(fn Function, code int, message string, args ...any) {
59 if fn.UID() == "" {
60 return
61 }
62
63 msg := message
64 if len(args) > 0 {
65 msg = fmt.Sprintf(message, args...)
66 }
67
68 payload := fnpkg.BuildJSONPayload(code, msg)
69
70 res := netdataapi.FunctionResult{
71 UID: fn.UID(),
72 ContentType: "application/json",
73 Payload: string(payload),
74 Code: strconv.Itoa(code),
75 ExpireTimestamp: strconv.FormatInt(time.Now().Unix(), 10),
76 }
77 r.finalizeTerminal(fn.UID(), "dyncfg.responder.sendcodef", func() {
78 r.api.FUNCRESULT(res)
79 })
80 }
81
82 // SendJSON sends a JSON payload response with HTTP 200 status
83 func (r *Responder) SendJSON(fn Function, payload string) {
84 r.sendPayload(fn, payload, "application/json")
85 }
86
87 // SendJSONWithCode sends a JSON payload response with a specific HTTP status code
88 func (r *Responder) SendJSONWithCode(fn Function, payload string, code int) {
89 if fn.UID() == "" {
90 return
91 }
92
93 res := netdataapi.FunctionResult{
94 UID: fn.UID(),
95 ContentType: "application/json",
96 Payload: payload,
97 Code: strconv.Itoa(code),
98 ExpireTimestamp: strconv.FormatInt(time.Now().Unix(), 10),
99 }
100 r.finalizeTerminal(fn.UID(), "dyncfg.responder.sendjsonwithcode", func() {
101 r.api.FUNCRESULT(res)
102 })
103 }
104
105 // SendYAML sends a YAML payload response
106 func (r *Responder) SendYAML(fn Function, payload string) {
107 r.sendPayload(fn, payload, "application/yaml")
108 }
109
110 // sendPayload sends a response with a specific payload and content type
111 func (r *Responder) sendPayload(fn Function, payload, contentType string) {
112 if fn.UID() == "" {
113 return
114 }
115
116 res := netdataapi.FunctionResult{
117 UID: fn.UID(),
118 ContentType: contentType,
119 Payload: payload,
120 Code: "200",
121 ExpireTimestamp: strconv.FormatInt(time.Now().Unix(), 10),
122 }
123 r.finalizeTerminal(fn.UID(), "dyncfg.responder.sendpayload", func() {
124 r.api.FUNCRESULT(res)
125 })
126 }
127
128 func (r *Responder) ConfigCreate(opts netdataapi.ConfigOpts) {
129 r.api.CONFIGCREATE(opts)
130 }
131
132 // ConfigStatus sends a CONFIG STATUS command
133 func (r *Responder) ConfigStatus(id string, status Status) {
134 r.api.CONFIGSTATUS(id, status.String())
135 }
136
137 // ConfigDelete sends a CONFIG DELETE command
138 func (r *Responder) ConfigDelete(id string) {
139 r.api.CONFIGDELETE(id)
140 }
141
142 // FunctionGlobal registers a global function with Netdata
143 func (r *Responder) FunctionGlobal(opts netdataapi.FunctionGlobalOpts) {
144 r.api.FUNCTIONGLOBAL(opts)
145 }
146
147 // FunctionRemove removes a function from Netdata (no-op until Netdata core supports it)
148 func (r *Responder) FunctionRemove(name string) {
149 r.api.FUNCTIONREMOVE(name)
150 }