1package api
2
3import (
4	"encoding/json"
5	"fmt"
6	"net/http"
7	"sort"
8	"strconv"
9	"strings"
10
11	"github.com/gorilla/mux"
12	"github.com/traefik/traefik/v2/pkg/config/runtime"
13	"github.com/traefik/traefik/v2/pkg/log"
14)
15
16type tcpRouterRepresentation struct {
17	*runtime.TCPRouterInfo
18	Name     string `json:"name,omitempty"`
19	Provider string `json:"provider,omitempty"`
20}
21
22func newTCPRouterRepresentation(name string, rt *runtime.TCPRouterInfo) tcpRouterRepresentation {
23	return tcpRouterRepresentation{
24		TCPRouterInfo: rt,
25		Name:          name,
26		Provider:      getProviderName(name),
27	}
28}
29
30type tcpServiceRepresentation struct {
31	*runtime.TCPServiceInfo
32	Name     string `json:"name,omitempty"`
33	Provider string `json:"provider,omitempty"`
34	Type     string `json:"type,omitempty"`
35}
36
37func newTCPServiceRepresentation(name string, si *runtime.TCPServiceInfo) tcpServiceRepresentation {
38	return tcpServiceRepresentation{
39		TCPServiceInfo: si,
40		Name:           name,
41		Provider:       getProviderName(name),
42		Type:           strings.ToLower(extractType(si.TCPService)),
43	}
44}
45
46type tcpMiddlewareRepresentation struct {
47	*runtime.TCPMiddlewareInfo
48	Name     string `json:"name,omitempty"`
49	Provider string `json:"provider,omitempty"`
50	Type     string `json:"type,omitempty"`
51}
52
53func newTCPMiddlewareRepresentation(name string, mi *runtime.TCPMiddlewareInfo) tcpMiddlewareRepresentation {
54	return tcpMiddlewareRepresentation{
55		TCPMiddlewareInfo: mi,
56		Name:              name,
57		Provider:          getProviderName(name),
58		Type:              strings.ToLower(extractType(mi.TCPMiddleware)),
59	}
60}
61
62func (h Handler) getTCPRouters(rw http.ResponseWriter, request *http.Request) {
63	results := make([]tcpRouterRepresentation, 0, len(h.runtimeConfiguration.TCPRouters))
64
65	criterion := newSearchCriterion(request.URL.Query())
66
67	for name, rt := range h.runtimeConfiguration.TCPRouters {
68		if keepTCPRouter(name, rt, criterion) {
69			results = append(results, newTCPRouterRepresentation(name, rt))
70		}
71	}
72
73	sort.Slice(results, func(i, j int) bool {
74		return results[i].Name < results[j].Name
75	})
76
77	rw.Header().Set("Content-Type", "application/json")
78
79	pageInfo, err := pagination(request, len(results))
80	if err != nil {
81		writeError(rw, err.Error(), http.StatusBadRequest)
82		return
83	}
84
85	rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
86
87	err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
88	if err != nil {
89		log.FromContext(request.Context()).Error(err)
90		writeError(rw, err.Error(), http.StatusInternalServerError)
91	}
92}
93
94func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
95	routerID := mux.Vars(request)["routerID"]
96
97	rw.Header().Set("Content-Type", "application/json")
98
99	router, ok := h.runtimeConfiguration.TCPRouters[routerID]
100	if !ok {
101		writeError(rw, fmt.Sprintf("router not found: %s", routerID), http.StatusNotFound)
102		return
103	}
104
105	result := newTCPRouterRepresentation(routerID, router)
106
107	err := json.NewEncoder(rw).Encode(result)
108	if err != nil {
109		log.FromContext(request.Context()).Error(err)
110		writeError(rw, err.Error(), http.StatusInternalServerError)
111	}
112}
113
114func (h Handler) getTCPServices(rw http.ResponseWriter, request *http.Request) {
115	results := make([]tcpServiceRepresentation, 0, len(h.runtimeConfiguration.TCPServices))
116
117	criterion := newSearchCriterion(request.URL.Query())
118
119	for name, si := range h.runtimeConfiguration.TCPServices {
120		if keepTCPService(name, si, criterion) {
121			results = append(results, newTCPServiceRepresentation(name, si))
122		}
123	}
124
125	sort.Slice(results, func(i, j int) bool {
126		return results[i].Name < results[j].Name
127	})
128
129	rw.Header().Set("Content-Type", "application/json")
130
131	pageInfo, err := pagination(request, len(results))
132	if err != nil {
133		writeError(rw, err.Error(), http.StatusBadRequest)
134		return
135	}
136
137	rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
138
139	err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
140	if err != nil {
141		log.FromContext(request.Context()).Error(err)
142		writeError(rw, err.Error(), http.StatusInternalServerError)
143	}
144}
145
146func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
147	serviceID := mux.Vars(request)["serviceID"]
148
149	rw.Header().Set("Content-Type", "application/json")
150
151	service, ok := h.runtimeConfiguration.TCPServices[serviceID]
152	if !ok {
153		writeError(rw, fmt.Sprintf("service not found: %s", serviceID), http.StatusNotFound)
154		return
155	}
156
157	result := newTCPServiceRepresentation(serviceID, service)
158
159	err := json.NewEncoder(rw).Encode(result)
160	if err != nil {
161		log.FromContext(request.Context()).Error(err)
162		writeError(rw, err.Error(), http.StatusInternalServerError)
163	}
164}
165
166func (h Handler) getTCPMiddlewares(rw http.ResponseWriter, request *http.Request) {
167	results := make([]tcpMiddlewareRepresentation, 0, len(h.runtimeConfiguration.Middlewares))
168
169	criterion := newSearchCriterion(request.URL.Query())
170
171	for name, mi := range h.runtimeConfiguration.TCPMiddlewares {
172		if keepTCPMiddleware(name, mi, criterion) {
173			results = append(results, newTCPMiddlewareRepresentation(name, mi))
174		}
175	}
176
177	sort.Slice(results, func(i, j int) bool {
178		return results[i].Name < results[j].Name
179	})
180
181	rw.Header().Set("Content-Type", "application/json")
182
183	pageInfo, err := pagination(request, len(results))
184	if err != nil {
185		writeError(rw, err.Error(), http.StatusBadRequest)
186		return
187	}
188
189	rw.Header().Set(nextPageHeader, strconv.Itoa(pageInfo.nextPage))
190
191	err = json.NewEncoder(rw).Encode(results[pageInfo.startIndex:pageInfo.endIndex])
192	if err != nil {
193		log.FromContext(request.Context()).Error(err)
194		writeError(rw, err.Error(), http.StatusInternalServerError)
195	}
196}
197
198func (h Handler) getTCPMiddleware(rw http.ResponseWriter, request *http.Request) {
199	middlewareID := mux.Vars(request)["middlewareID"]
200
201	rw.Header().Set("Content-Type", "application/json")
202
203	middleware, ok := h.runtimeConfiguration.TCPMiddlewares[middlewareID]
204	if !ok {
205		writeError(rw, fmt.Sprintf("middleware not found: %s", middlewareID), http.StatusNotFound)
206		return
207	}
208
209	result := newTCPMiddlewareRepresentation(middlewareID, middleware)
210
211	err := json.NewEncoder(rw).Encode(result)
212	if err != nil {
213		log.FromContext(request.Context()).Error(err)
214		writeError(rw, err.Error(), http.StatusInternalServerError)
215	}
216}
217
218func keepTCPRouter(name string, item *runtime.TCPRouterInfo, criterion *searchCriterion) bool {
219	if criterion == nil {
220		return true
221	}
222
223	return criterion.withStatus(item.Status) && criterion.searchIn(item.Rule, name)
224}
225
226func keepTCPService(name string, item *runtime.TCPServiceInfo, criterion *searchCriterion) bool {
227	if criterion == nil {
228		return true
229	}
230
231	return criterion.withStatus(item.Status) && criterion.searchIn(name)
232}
233
234func keepTCPMiddleware(name string, item *runtime.TCPMiddlewareInfo, criterion *searchCriterion) bool {
235	if criterion == nil {
236		return true
237	}
238
239	return criterion.withStatus(item.Status) && criterion.searchIn(name)
240}
241