1package api
2
3import (
4	"encoding/json"
5	"net/http"
6	"strings"
7	"time"
8
9	"github.com/0xERR0R/blocky/util"
10
11	"github.com/go-chi/chi"
12	log "github.com/sirupsen/logrus"
13)
14
15// BlockingControl interface to control the blocking status
16type BlockingControl interface {
17	EnableBlocking()
18	DisableBlocking(duration time.Duration, disableGroups []string) error
19	BlockingStatus() BlockingStatus
20}
21
22// ListRefresher interface to control the list refresh
23type ListRefresher interface {
24	RefreshLists()
25}
26
27// BlockingEndpoint endpoint for the blocking status control
28type BlockingEndpoint struct {
29	control BlockingControl
30}
31
32// ListRefreshEndpoint endpoint for list refresh
33type ListRefreshEndpoint struct {
34	refresher ListRefresher
35}
36
37// RegisterEndpoint registers an implementation as HTTP endpoint
38func RegisterEndpoint(router chi.Router, t interface{}) {
39	if a, ok := t.(BlockingControl); ok {
40		registerBlockingEndpoints(router, a)
41	}
42
43	if a, ok := t.(ListRefresher); ok {
44		registerListRefreshEndpoints(router, a)
45	}
46}
47
48func registerListRefreshEndpoints(router chi.Router, refresher ListRefresher) {
49	l := &ListRefreshEndpoint{refresher}
50
51	router.Post(PathListsRefresh, l.apiListRefresh)
52}
53
54// apiListRefresh is the http endpoint to trigger the refresh of all lists
55// @Summary List refresh
56// @Description Refresh all lists
57// @Tags lists
58// @Success 200   "Lists were reloaded"
59// @Router /lists/refresh [post]
60func (l *ListRefreshEndpoint) apiListRefresh(_ http.ResponseWriter, _ *http.Request) {
61	l.refresher.RefreshLists()
62}
63
64func registerBlockingEndpoints(router chi.Router, control BlockingControl) {
65	s := &BlockingEndpoint{control}
66	// register API endpoints
67	router.Get(PathBlockingEnablePath, s.apiBlockingEnable)
68	router.Get(PathBlockingDisablePath, s.apiBlockingDisable)
69	router.Get(PathBlockingStatusPath, s.apiBlockingStatus)
70}
71
72// apiBlockingEnable is the http endpoint to enable the blocking status
73// @Summary Enable blocking
74// @Description enable the blocking status
75// @Tags blocking
76// @Success 200   "Blocking is enabled"
77// @Router /blocking/enable [get]
78func (s *BlockingEndpoint) apiBlockingEnable(_ http.ResponseWriter, _ *http.Request) {
79	log.Info("enabling blocking...")
80
81	s.control.EnableBlocking()
82}
83
84// apiBlockingDisable is the http endpoint to disable the blocking status
85// @Summary Disable blocking
86// @Description disable the blocking status
87// @Tags blocking
88// @Param duration query string false "duration of blocking (Example: 300s, 5m, 1h, 5m30s)" Format(duration)
89// @Param groups query string false "groups to disable (comma separated). If empty, disable all groups" Format(string)
90// @Success 200   "Blocking is disabled"
91// @Failure 400   "Wrong duration format"
92// @Failure 400   "Unknown group"
93// @Router /blocking/disable [get]
94func (s *BlockingEndpoint) apiBlockingDisable(rw http.ResponseWriter, req *http.Request) {
95	var (
96		duration time.Duration
97		groups   []string
98		err      error
99	)
100
101	// parse duration from query parameter
102	durationParam := req.URL.Query().Get("duration")
103	if len(durationParam) > 0 {
104		duration, err = time.ParseDuration(durationParam)
105		if err != nil {
106			log.Errorf("wrong duration format '%s'", durationParam)
107			rw.WriteHeader(http.StatusBadRequest)
108
109			return
110		}
111	}
112
113	groupsParam := req.URL.Query().Get("groups")
114	if len(groupsParam) > 0 {
115		groups = strings.Split(groupsParam, ",")
116	}
117
118	err = s.control.DisableBlocking(duration, groups)
119	if err != nil {
120		log.Error("can't disable the blocking: ", err)
121		rw.WriteHeader(http.StatusBadRequest)
122	}
123}
124
125// apiBlockingStatus is the http endpoint to get current blocking status
126// @Summary Blocking status
127// @Description get current blocking status
128// @Tags blocking
129// @Produce  json
130// @Success 200 {object} api.BlockingStatus "Returns current blocking status"
131// @Router /blocking/status [get]
132func (s *BlockingEndpoint) apiBlockingStatus(rw http.ResponseWriter, _ *http.Request) {
133	status := s.control.BlockingStatus()
134
135	response, _ := json.Marshal(status)
136	_, err := rw.Write(response)
137
138	util.LogOnError("unable to write response ", err)
139}
140