-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhandler.go
More file actions
141 lines (117 loc) · 3.52 KB
/
handler.go
File metadata and controls
141 lines (117 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package mwsengine
import (
"encoding/json"
"log"
"net/http"
"time"
"github.com/MathWebSearch/mwsapi/connection"
"github.com/MathWebSearch/mwsapi/engine"
"github.com/MathWebSearch/mwsapi/query"
"github.com/MathWebSearch/mwsapi/result"
"github.com/pkg/errors"
)
// MWSHandler represents an http server capable of answering queries to mws
type MWSHandler struct {
Host string
Port int
connection *connection.MWSConnection
}
// Connect connects this handler
func (handler *MWSHandler) Connect() (err error) {
if handler.Host != "" {
handler.connection, err = connection.NewMWSConnection(handler.Port, handler.Host)
if err == nil {
err = connection.AwaitConnect(handler.connection, 5*time.Second, -1, func(e error) {
log.Printf("Failed to connect to MWS, retyring: %s", e)
})
}
if err != nil {
err = errors.Wrap(err, "Failed to connect to MWS")
return
}
log.Printf("Connected to MWS at %s", handler.connection.URL())
}
return
}
// Name returns the name of this daemon
func (handler *MWSHandler) Name() string {
return "mws"
}
// Enabled checks if the MWSDaemon is enabled
func (handler *MWSHandler) Enabled() bool {
return handler.connection != nil
}
// ServeHTTP implements handling of a request
func (handler *MWSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (code int, res interface{}, err error) {
var request MWSAPIRequest
// decode the request
decoder := json.NewDecoder(r.Body)
err = decoder.Decode(&request)
if err != nil {
code = http.StatusBadRequest
err = errors.Wrap(err, "Failed to read query from request body")
return
}
// default the size to 10
if request.Size == 0 {
request.Size = 10
}
// validate the request
err = request.Validate()
if err != nil {
code = http.StatusBadRequest
err = errors.Wrap(err, "Failed to read query from request body")
return
}
// if we have no daemon connection, return
if !handler.Enabled() {
code = http.StatusNotFound
err = errors.Errorf("MathWebSearch is not enabled on this server")
return
}
log.Printf("[%s] %v\n", r.RemoteAddr, request.MWSQuery.Expressions)
// run the query, or the count
if request.Count {
res, err = Count(handler.connection, request.MWSQuery)
} else {
res, err = Run(handler.connection, request.MWSQuery, request.From, request.Size)
if(!request.Complete){
// remove the math source when requested
i,ok := res.(*result.Result)
if(ok){
for _, hit := range i.Hits {
hit.Element.MathSource = nil
}
}
}
}
// if there was an error, wrap it and set the status code
if err != nil {
code = http.StatusInternalServerError
err = errors.Wrap(err, "Query failed")
}
return
}
// MaxRequestSize is the maximum request size supported by the api
const MaxRequestSize = 100
// MWSAPIRequest is a request sent to mws via the REST API
type MWSAPIRequest struct {
*query.MWSQuery
Count bool `json:"count,omitempty"`
From int64 `json:"from,omitempty"`
Size int64 `json:"size,omitempty"`
Complete bool `json:"complete,omitempty"`
}
// Validate validates an MWSAPI Request
func (req *MWSAPIRequest) Validate() error {
if req.From < 0 {
return errors.Errorf("Expected \"from\" to be non-negative, but got %d", req.From)
}
if req.Size < 0 || req.Size > MaxRequestSize {
return errors.Errorf("Expected \"size\" to be between 0 and %d (inclusive), but got %d", MaxRequestSize, req.Size)
}
return nil
}
func init() {
var _ engine.Handler = engine.Handler((*MWSHandler)(nil))
}