master
go 150 lines 3.96 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package funcctl
4
5 import (
6 "encoding/json"
7 "fmt"
8
9 "github.com/netdata/netdata/go/plugins/pkg/funcapi"
10 "github.com/netdata/netdata/go/plugins/plugin/framework/dyncfg"
11 "github.com/netdata/netdata/go/plugins/plugin/framework/functions"
12 )
13
14 type methodResponseWriter func(dataResp *funcapi.FunctionResponse, methodParams []funcapi.ParamConfig, updateEvery int)
15
16 func (c *Controller) respondWithParams(fn functions.Function, moduleName string, dataResp *funcapi.FunctionResponse, methodParams []funcapi.ParamConfig, updateEvery int, methodType string, includeJobParam bool) {
17 c.respondMethodDataWithParams(
18 fn,
19 dataResp,
20 methodParams,
21 updateEvery,
22 methodType,
23 func(params []funcapi.ParamConfig) []string {
24 return buildAcceptedParams(params, includeJobParam)
25 },
26 func(params []funcapi.ParamConfig) []map[string]any {
27 return c.buildRequiredParams(moduleName, params, includeJobParam)
28 },
29 )
30 }
31
32 func (c *Controller) respondJobMethodWithParams(fn functions.Function, dataResp *funcapi.FunctionResponse, methodParams []funcapi.ParamConfig, updateEvery int, methodType string) {
33 c.respondMethodDataWithParams(
34 fn,
35 dataResp,
36 methodParams,
37 updateEvery,
38 methodType,
39 buildJobMethodAcceptedParams,
40 buildJobMethodRequiredParams,
41 )
42 }
43
44 func (c *Controller) respondMethodDataWithParams(
45 fn functions.Function,
46 dataResp *funcapi.FunctionResponse,
47 methodParams []funcapi.ParamConfig,
48 updateEvery int,
49 methodType string,
50 buildAccepted func([]funcapi.ParamConfig) []string,
51 buildRequired func([]funcapi.ParamConfig) []map[string]any,
52 ) {
53 if dataResp == nil {
54 c.respondError(fn, 500, "internal error: module returned nil response")
55 return
56 }
57 if dataResp.Status >= 400 {
58 c.respondError(fn, dataResp.Status, "%s", dataResp.Message)
59 return
60 }
61
62 paramsForResponse := methodParams
63 if len(dataResp.RequiredParams) > 0 {
64 paramsForResponse = funcapi.MergeParamConfigs(paramsForResponse, dataResp.RequiredParams)
65 }
66
67 resp := map[string]any{
68 "v": 3,
69 "update_every": updateEvery,
70 "status": dataResp.Status,
71 "type": resolveResponseType(dataResp.ResponseType, methodType),
72 "has_history": false,
73 "help": dataResp.Help,
74 "accepted_params": buildAccepted(paramsForResponse),
75 "required_params": buildRequired(paramsForResponse),
76 }
77
78 if dataResp.Columns != nil {
79 resp["columns"] = dataResp.Columns
80 }
81 if dataResp.Data != nil {
82 resp["data"] = dataResp.Data
83 }
84 if dataResp.DefaultSortColumn != "" {
85 resp["default_sort_column"] = dataResp.DefaultSortColumn
86 }
87 if len(dataResp.Charts) > 0 {
88 resp["charts"] = dataResp.Charts
89 }
90 if len(dataResp.DefaultCharts) > 0 {
91 resp["default_charts"] = dataResp.DefaultCharts.Build()
92 }
93 if len(dataResp.GroupBy) > 0 {
94 resp["group_by"] = dataResp.GroupBy
95 }
96
97 c.respondJSON(fn, resp)
98 }
99
100 func resolveResponseType(dataType, methodType string) string {
101 if dataType != "" {
102 return dataType
103 }
104 if methodType != "" {
105 return methodType
106 }
107 return "table"
108 }
109
110 func (c *Controller) respondError(fn functions.Function, status int, format string, args ...any) {
111 c.respondJSON(fn, map[string]any{
112 "status": status,
113 "errorMessage": fmt.Sprintf(format, args...),
114 })
115 }
116
117 func (c *Controller) respondJSON(fn functions.Function, resp map[string]any) {
118 data, err := json.Marshal(resp)
119 if err != nil {
120 c.Errorf("failed to marshal function response: %v", err)
121 c.sendJSON(fn, string(functions.BuildJSONPayload(500, "internal error: failed to encode response")), 500)
122 return
123 }
124
125 code := 200
126 if status, ok := resp["status"]; ok {
127 switch value := status.(type) {
128 case int:
129 code = value
130 case int64:
131 code = int(value)
132 case float64:
133 code = int(value)
134 }
135 }
136
137 c.sendJSON(fn, string(data), code)
138 }
139
140 func (c *Controller) sendJSON(fn functions.Function, payload string, code int) {
141 if c.jsonWriter != nil {
142 c.jsonWriter([]byte(payload), code)
143 return
144 }
145 if c.api == nil {
146 return
147 }
148
149 c.api.SendJSONWithCode(dyncfg.NewFunction(fn), payload, code)
150 }