@@ -12,14 +12,10 @@ import (
12
12
"strings"
13
13
"time"
14
14
15
- "github.com/didip/tollbooth/v7"
16
- "github.com/didip/tollbooth_chi"
17
- "github.com/go-chi/chi/v5"
18
- "github.com/go-chi/chi/v5/middleware"
19
- "github.com/go-chi/render"
20
15
log "github.com/go-pkgz/lgr"
21
16
"github.com/go-pkgz/rest"
22
17
"github.com/go-pkgz/rest/logger"
18
+ "github.com/go-pkgz/routegroup"
23
19
"go.mongodb.org/mongo-driver/bson/primitive"
24
20
25
21
"github.com/ukeeper/ukeeper-redabilty/backend/datastore"
@@ -67,42 +63,36 @@ func (s *Server) Run(ctx context.Context, address string, port int, frontendDir
67
63
log .Printf ("[WARN] http server terminated, %s" , httpServer .ListenAndServe ())
68
64
}
69
65
70
- func (s * Server ) routes (frontendDir string ) chi. Router {
71
- router := chi . NewRouter ( )
66
+ func (s * Server ) routes (frontendDir string ) http. Handler {
67
+ router := routegroup . New ( http . NewServeMux () )
72
68
73
- router .Use (middleware . RequestID , middleware . RealIP , rest .Recoverer (log .Default ()))
74
- router .Use (middleware . Throttle ( 1000 ), middleware . Timeout ( 60 * time . Second ) )
69
+ router .Use (rest .Recoverer (log .Default ()))
70
+ router .Use (rest . RealIP )
75
71
router .Use (rest .AppInfo ("ureadability" , "Umputun" , s .Version ), rest .Ping )
76
- router .Use (tollbooth_chi .LimitHandler (tollbooth .NewLimiter (50 , nil )))
77
-
72
+ router .Use (rest .Throttle (50 ))
78
73
router .Use (logger .New (logger .Log (log .Default ()), logger .WithBody , logger .Prefix ("[INFO]" )).Handler )
79
74
80
- router .Route ("/api" , func (r chi.Router ) {
81
- r .Get ("/content/v1/parser" , s .extractArticleEmulateReadability )
82
- r .Post ("/extract" , s .extractArticle )
83
- r .Post ("/auth" , s .authFake )
84
-
85
- r .Group (func (protected chi.Router ) {
86
- protected .Use (basicAuth ("ureadability" , s .Credentials ))
87
- protected .Post ("/rule" , s .saveRule )
88
- protected .Post ("/toggle-rule/{id}" , s .toggleRule )
89
- protected .Post ("/preview" , s .handlePreview )
75
+ router .Route (func (api * routegroup.Bundle ) {
76
+ api .Mount ("/api" ).Route (func (api * routegroup.Bundle ) {
77
+ api .HandleFunc ("GET /content/v1/parser" , s .extractArticleEmulateReadability )
78
+ api .HandleFunc ("POST /extract" , s .extractArticle )
79
+ api .HandleFunc ("POST /auth" , s .authFake )
80
+
81
+ // add protected group with its own set of middlewares
82
+ protectedGroup := api .Group ()
83
+ protectedGroup .Use (basicAuth ("ureadability" , s .Credentials ))
84
+ protectedGroup .HandleFunc ("POST /rule" , s .saveRule )
85
+ protectedGroup .HandleFunc ("POST /toggle-rule/{id}" , s .toggleRule )
86
+ protectedGroup .HandleFunc ("POST /preview" , s .handlePreview )
90
87
})
91
88
})
92
89
93
- router .Get ( " /" , s .handleIndex )
94
- router .Get ( " /add/" , s .handleAdd )
95
- router .Get ( " /edit/{id}" , s .handleEdit )
90
+ router .HandleFunc ( "GET /" , s .handleIndex )
91
+ router .HandleFunc ( "GET /add/" , s .handleAdd )
92
+ router .HandleFunc ( "GET /edit/{id}" , s .handleEdit )
96
93
97
94
_ = os .Mkdir (filepath .Join (frontendDir , "static" ), 0o700 )
98
- fs , err := rest .NewFileServer ("/" , filepath .Join (frontendDir , "static" ), rest .FsOptSPA )
99
- if err != nil {
100
- log .Printf ("[ERROR] unable to create file server, %v" , err )
101
- return nil
102
- }
103
- router .Get ("/*" , func (w http.ResponseWriter , r * http.Request ) {
104
- fs .ServeHTTP (w , r )
105
- })
95
+ router .HandleFiles ("/" , http .Dir (filepath .Join (frontendDir , "static" )))
106
96
return router
107
97
}
108
98
@@ -140,7 +130,7 @@ func (s *Server) handleAdd(w http.ResponseWriter, _ *http.Request) {
140
130
}
141
131
142
132
func (s * Server ) handleEdit (w http.ResponseWriter , r * http.Request ) {
143
- id := getBid (chi . URLParam ( r , "id" ))
133
+ id := getBid (r . PathValue ( "id" ))
144
134
rule , found := s .Readability .Rules .GetByID (r .Context (), id )
145
135
if ! found {
146
136
http .Error (w , "Rule not found" , http .StatusNotFound )
@@ -163,59 +153,52 @@ func (s *Server) handleEdit(w http.ResponseWriter, r *http.Request) {
163
153
164
154
func (s * Server ) extractArticle (w http.ResponseWriter , r * http.Request ) {
165
155
artRequest := extractor.Response {}
166
- if err := render .DecodeJSON (r .Body , & artRequest ); err != nil {
167
- render .Status (r , http .StatusInternalServerError )
168
- render .JSON (w , r , JSON {"error" : err .Error ()})
156
+ if err := rest .DecodeJSON (r , & artRequest ); err != nil {
157
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusInternalServerError , err , "can't parse request" )
169
158
return
170
159
}
171
160
172
161
if artRequest .URL == "" {
173
- render .Status (r , http .StatusBadRequest )
174
- render .JSON (w , r , JSON {"error" : "url parameter is required" })
162
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusBadRequest , nil , "url parameter is required" )
175
163
return
176
164
}
177
165
178
166
res , err := s .Readability .Extract (r .Context (), artRequest .URL )
179
167
if err != nil {
180
- render .Status (r , http .StatusBadRequest )
181
- render .JSON (w , r , JSON {"error" : err .Error ()})
168
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusBadRequest , err , "can't extract content" )
182
169
return
183
170
}
184
171
185
- render . JSON ( w , r , & res )
172
+ rest . RenderJSON ( w , & res )
186
173
}
187
174
188
175
// extractArticleEmulateReadability emulates readability API parse - https://www.readability.com/api/content/v1/parser?token=%s&url=%s
189
176
// if token is not set for application, it won't be checked
190
177
func (s * Server ) extractArticleEmulateReadability (w http.ResponseWriter , r * http.Request ) {
191
178
token := r .URL .Query ().Get ("token" )
192
179
if s .Token != "" && token == "" {
193
- render .Status (r , http .StatusExpectationFailed )
194
- render .JSON (w , r , JSON {"error" : "no token passed" })
180
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusExpectationFailed , nil , "no token passed" )
195
181
return
196
182
}
197
183
198
184
if s .Token != "" && s .Token != token {
199
- render .Status (r , http .StatusUnauthorized )
200
- render .JSON (w , r , JSON {"error" : "wrong token passed" })
185
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusUnauthorized , nil , "wrong token passed" )
201
186
return
202
187
}
203
188
204
189
extractURL := r .URL .Query ().Get ("url" )
205
190
if extractURL == "" {
206
- render .Status (r , http .StatusExpectationFailed )
207
- render .JSON (w , r , JSON {"error" : "no url passed" })
191
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusExpectationFailed , nil , "no url passed" )
208
192
return
209
193
}
210
194
211
195
res , err := s .Readability .Extract (r .Context (), extractURL )
212
196
if err != nil {
213
- render .Status (r , http .StatusBadRequest )
214
- render .JSON (w , r , JSON {"error" : err .Error ()})
197
+ rest .SendErrorJSON (w , r , log .Default (), http .StatusBadRequest , err , "can't extract content" )
215
198
return
216
199
}
217
200
218
- render . JSON ( w , r , & res )
201
+ rest . RenderJSON ( w , & res )
219
202
}
220
203
221
204
// generates previews for the provided test URLs
@@ -322,11 +305,11 @@ func (s *Server) saveRule(w http.ResponseWriter, r *http.Request) {
322
305
}
323
306
324
307
w .Header ().Set ("HX-Redirect" , "/" )
325
- render . JSON ( w , r , & srule )
308
+ rest . RenderJSON ( w , & srule )
326
309
}
327
310
328
311
func (s * Server ) toggleRule (w http.ResponseWriter , r * http.Request ) {
329
- id := getBid (chi . URLParam ( r , "id" ))
312
+ id := getBid (r . PathValue ( "id" ))
330
313
rule , found := s .Readability .Rules .GetByID (r .Context (), id )
331
314
if ! found {
332
315
log .Printf ("[WARN] rule not found for id: %s" , id .Hex ())
@@ -356,9 +339,9 @@ func (s *Server) toggleRule(w http.ResponseWriter, r *http.Request) {
356
339
}
357
340
358
341
// authFake just a dummy post request used for external check for protected resource
359
- func (s * Server ) authFake (w http.ResponseWriter , r * http.Request ) {
342
+ func (s * Server ) authFake (w http.ResponseWriter , _ * http.Request ) {
360
343
t := time .Now ()
361
- render . JSON ( w , r , JSON {"pong" : t .Format ("20060102150405" )})
344
+ rest . RenderJSON ( w , JSON {"pong" : t .Format ("20060102150405" )})
362
345
}
363
346
364
347
func getBid (id string ) primitive.ObjectID {
0 commit comments