forked from tleyden/open-ocr
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathocr_http_handler.go
146 lines (129 loc) · 4.53 KB
/
ocr_http_handler.go
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
142
143
144
145
146
package ocrworker
import (
"encoding/json"
"fmt"
"io"
// "github.com/sasha-s/go-deadlock"
"net/http"
"os"
"sync"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/segmentio/ksuid"
)
// OcrHTTPStatusHandler is for initial handling of ocr request
type OcrHTTPStatusHandler struct {
RabbitConfig RabbitConfig
}
func NewOcrHttpHandler(r *RabbitConfig) *OcrHTTPStatusHandler {
return &OcrHTTPStatusHandler{
RabbitConfig: *r,
}
}
var (
// AppStop and ServiceCanAccept are global. Used to set the flag for logging and stopping the application
AppStop bool
ServiceCanAccept bool
ServiceCanAcceptMu sync.RWMutex
)
func (s *OcrHTTPStatusHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// _ = pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
requestIDRaw := ksuid.New()
requestID := requestIDRaw.String()
log.Info().Str("component", "OCR_HTTP").Str("RequestID", requestID).
Msg("serveHttp called")
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
log.Warn().Err(err).Caller().Str("component", "OCR_HTTP").Msg(req.RequestURI + " request Body could not be removed")
}
}(req.Body)
httpStatus := 200
ServiceCanAcceptMu.Lock()
serviceCanAcceptLocal := ServiceCanAccept
appStopLocal := AppStop
ServiceCanAcceptMu.Unlock()
// check if the API should accept new requests. The part after || is needed because the first part can be slow
if (!serviceCanAcceptLocal && !appStopLocal) || !schedulerByWorkerNumber() {
err := "no resources available to process the request. RequestID " + requestID
log.Warn().Str("component", "OCR_HTTP").Err(fmt.Errorf(err)).
Str("RequestID", requestID).
Msg("conditions for accepting new requests are not met")
httpStatus = 503
http.Error(w, err, httpStatus)
return
}
if !serviceCanAcceptLocal && appStopLocal {
err := "service is going down. RequestID " + requestID
log.Warn().Str("component", "OCR_HTTP").Err(fmt.Errorf(err)).
Str("RequestID", requestID).
Msg("conditions for accepting new requests are not met")
httpStatus = 503
http.Error(w, err, httpStatus)
return
}
ocrRequest := OcrRequest{RequestID: requestID}
decoder := json.NewDecoder(req.Body)
err := decoder.Decode(&ocrRequest)
if err != nil {
log.Warn().Str("component", "OCR_HTTP").Err(err).
Msg("did the client send a valid json? RequestID " + requestID)
httpStatus = 400
http.Error(w, "Unable to unmarshal json, malformed request. RequestID "+requestID, httpStatus)
return
}
ocrResult, httpStatus, err := HandleOcrRequest(&ocrRequest, &s.RabbitConfig)
if err != nil {
msg := "Unable to perform OCR decode. Error: %v"
errMsg := fmt.Sprintf(msg, err)
log.Error().Err(err).Str("component", "OCR_HTTP").Msg("Unable to perform OCR decode. RequestID " + requestID)
http.Error(w, errMsg, httpStatus)
return
}
w.Header().Set("Content-Type", "application/json")
js, err := json.Marshal(ocrResult)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_, err = w.Write(js)
if err != nil {
log.Error().Err(err).Str("component", "OCR_HTTP").Str("RequestID", requestID).
Msg("http write() failed")
}
}
// HandleOcrRequest will process incoming OCR request by routing it through the whole process chain
func HandleOcrRequest(ocrRequest *OcrRequest, workerConfig *RabbitConfig) (OcrResult, int, error) {
httpStatus := 200
// ocrResult := newOcrResult(ocrRequest.RequestID)
// set the context for zerolog, RequestID will be printed on each logging event
logger := zerolog.New(os.Stdout).With().
Str("RequestID", ocrRequest.RequestID).Timestamp().Logger()
switch ocrRequest.InplaceDecode {
case true:
// inplace decode: short circuit rabbitmq, and just call ocr engine directly
ocrEngine := NewOcrEngine(ocrRequest.EngineType)
workingConfig := WorkerConfig{}
ocrResult, err := ocrEngine.ProcessRequest(ocrRequest, &workingConfig)
if err != nil {
logger.Error().Err(err).Str("component", "OCR_HTTP").Msg("Error processing ocr request")
httpStatus = 500
return OcrResult{}, httpStatus, err
}
return ocrResult, httpStatus, nil
default:
// add a new job to rabbitMQ and wait for worker to respond w/ result
ocrClient, err := NewOcrRpcClient(workerConfig)
if err != nil {
logger.Error().Err(err).Str("component", "OCR_HTTP")
httpStatus = 500
return OcrResult{}, httpStatus, err
}
ocrResult, httpStatus, err := ocrClient.DecodeImage(ocrRequest)
if err != nil {
logger.Error().Err(err).Str("component", "OCR_HTTP")
return OcrResult{}, httpStatus, err
}
return ocrResult, httpStatus, nil
}
}