2024-09-06 01:40:57 +02:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2024-09-11 18:32:55 +02:00
|
|
|
"io/ioutil"
|
2024-09-06 01:40:57 +02:00
|
|
|
"net/http"
|
2024-09-12 04:30:23 +02:00
|
|
|
"strconv"
|
2024-09-06 01:40:57 +02:00
|
|
|
|
|
|
|
"git.defalsify.org/vise.git/db"
|
|
|
|
"git.defalsify.org/vise.git/engine"
|
|
|
|
"git.defalsify.org/vise.git/logging"
|
|
|
|
"git.defalsify.org/vise.git/persist"
|
|
|
|
"git.defalsify.org/vise.git/resource"
|
2024-09-11 18:53:12 +02:00
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
2024-09-11 18:53:12 +02:00
|
|
|
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
2024-09-12 04:30:23 +02:00
|
|
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
2024-09-06 01:40:57 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
logg = logging.NewVanilla().WithDomain("httpserver")
|
|
|
|
)
|
|
|
|
|
2024-09-11 00:09:10 +02:00
|
|
|
type DefaultRequestParser struct {
|
|
|
|
}
|
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
|
|
|
|
func(rp *DefaultRequestParser) GetSessionId(rq any) (string, error) {
|
|
|
|
rqv, ok := rq.(*http.Request)
|
|
|
|
if !ok {
|
|
|
|
return "", handlers.ErrInvalidRequest
|
|
|
|
}
|
|
|
|
v := rqv.Header.Get("X-Vise-Session")
|
2024-09-11 18:32:55 +02:00
|
|
|
if v == "" {
|
2024-09-12 04:30:23 +02:00
|
|
|
return "", handlers.ErrSessionMissing
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
2024-09-11 18:32:55 +02:00
|
|
|
return v, nil
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
func(rp *DefaultRequestParser) GetInput(rq any) ([]byte, error) {
|
|
|
|
rqv, ok := rq.(*http.Request)
|
|
|
|
if !ok {
|
|
|
|
return nil, handlers.ErrInvalidRequest
|
|
|
|
}
|
|
|
|
defer rqv.Body.Close()
|
|
|
|
v, err := ioutil.ReadAll(rqv.Body)
|
2024-09-11 18:32:55 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
2024-09-11 18:32:55 +02:00
|
|
|
return v, nil
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type SessionHandler struct {
|
|
|
|
cfgTemplate engine.Config
|
2024-09-12 04:30:23 +02:00
|
|
|
rp handlers.RequestParser
|
2024-09-06 01:40:57 +02:00
|
|
|
rs resource.Resource
|
2024-09-11 18:53:12 +02:00
|
|
|
hn *ussd.Handlers
|
2024-09-12 04:30:23 +02:00
|
|
|
provider storage.StorageProvider
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp handlers.RequestParser, hn *ussd.Handlers) *SessionHandler {
|
2024-09-06 01:40:57 +02:00
|
|
|
return &SessionHandler{
|
|
|
|
cfgTemplate: cfg,
|
|
|
|
rs: rs,
|
2024-09-11 18:53:12 +02:00
|
|
|
hn: hn,
|
2024-09-11 00:09:10 +02:00
|
|
|
rp: rp,
|
2024-09-12 04:30:23 +02:00
|
|
|
provider: storage.NewSimpleStorageProvider(stateDb, userdataDb),
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
func(f *SessionHandler) writeError(w http.ResponseWriter, code int, err error) {
|
|
|
|
s := err.Error()
|
|
|
|
w.Header().Set("Content-Length", strconv.Itoa(len(s)))
|
2024-09-06 01:40:57 +02:00
|
|
|
w.WriteHeader(code)
|
|
|
|
_, err = w.Write([]byte{})
|
|
|
|
if err != nil {
|
2024-09-12 04:30:23 +02:00
|
|
|
logg.Errorf("error writing error!!", "err", err, "olderr", s)
|
2024-09-06 01:40:57 +02:00
|
|
|
w.WriteHeader(500)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-09-10 21:44:10 +02:00
|
|
|
func(f* SessionHandler) Shutdown() {
|
|
|
|
err := f.provider.Close()
|
|
|
|
if err != nil {
|
|
|
|
logg.Errorf("handler shutdown error", "err", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
func(f *SessionHandler) GetEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine {
|
|
|
|
en := engine.NewEngine(cfg, rs)
|
|
|
|
en = en.WithPersister(pr)
|
|
|
|
return en
|
|
|
|
}
|
|
|
|
|
|
|
|
func(f *SessionHandler) Process(rqs handlers.RequestSession) (handlers.RequestSession, error) {
|
2024-09-06 01:40:57 +02:00
|
|
|
var r bool
|
2024-09-12 04:30:23 +02:00
|
|
|
var err error
|
|
|
|
var ok bool
|
|
|
|
|
|
|
|
logg.InfoCtxf(rqs.Ctx, "new request", rqs)
|
|
|
|
|
|
|
|
rqs.Storage, err = f.provider.Get(rqs.Config.SessionId)
|
2024-09-06 01:40:57 +02:00
|
|
|
if err != nil {
|
2024-09-12 04:30:23 +02:00
|
|
|
logg.ErrorCtxf(rqs.Ctx, "", "storage error", "err", err)
|
|
|
|
return rqs, handlers.ErrStorage
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
2024-09-12 04:30:23 +02:00
|
|
|
|
|
|
|
f.hn = f.hn.WithPersister(rqs.Storage.Persister)
|
|
|
|
eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister)
|
|
|
|
en, ok := eni.(*engine.DefaultEngine)
|
|
|
|
if !ok {
|
|
|
|
return rqs, handlers.ErrEngineType
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
2024-09-12 04:30:23 +02:00
|
|
|
en = en.WithFirst(f.hn.Init)
|
|
|
|
if rqs.Config.EngineDebug {
|
|
|
|
en = en.WithDebug(nil)
|
|
|
|
}
|
|
|
|
rqs.Engine = en
|
2024-09-06 01:40:57 +02:00
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
r, err = rqs.Engine.Init(rqs.Ctx)
|
|
|
|
if err != nil {
|
|
|
|
return rqs, err
|
|
|
|
}
|
2024-09-06 01:40:57 +02:00
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
if r && len(rqs.Input) > 0 {
|
|
|
|
r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input)
|
|
|
|
}
|
2024-09-06 01:40:57 +02:00
|
|
|
if err != nil {
|
2024-09-12 04:30:23 +02:00
|
|
|
return rqs, err
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
2024-09-12 04:30:23 +02:00
|
|
|
|
|
|
|
_ = r
|
|
|
|
return rqs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func(f *SessionHandler) Output(rqs handlers.RequestSession) error {
|
|
|
|
var err error
|
|
|
|
_, err = rqs.Engine.WriteResult(rqs.Ctx, rqs.Writer)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func(f *SessionHandler) Reset(rqs handlers.RequestSession) error {
|
|
|
|
defer f.provider.Put(rqs.Config.SessionId, rqs.Storage)
|
|
|
|
return rqs.Engine.Finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
func(f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
|
|
var code int
|
|
|
|
var err error
|
|
|
|
|
|
|
|
rqs := handlers.RequestSession{
|
|
|
|
Ctx: req.Context(),
|
|
|
|
Writer: w,
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
|
|
|
|
2024-09-12 04:30:23 +02:00
|
|
|
cfg := f.cfgTemplate
|
|
|
|
cfg.SessionId, err = f.rp.GetSessionId(req)
|
2024-09-06 01:40:57 +02:00
|
|
|
if err != nil {
|
2024-09-12 04:30:23 +02:00
|
|
|
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
|
|
|
|
f.writeError(w, 400, err)
|
|
|
|
}
|
|
|
|
rqs.Config = cfg
|
|
|
|
rqs.Input, err = f.rp.GetInput(req)
|
|
|
|
if err != nil {
|
|
|
|
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
|
|
|
|
f.writeError(w, 400, err)
|
2024-09-06 01:40:57 +02:00
|
|
|
return
|
|
|
|
}
|
2024-09-12 04:30:23 +02:00
|
|
|
|
|
|
|
rqs, err = f.Process(rqs)
|
|
|
|
switch err {
|
|
|
|
case handlers.ErrStorage:
|
|
|
|
code = 500
|
|
|
|
case handlers.ErrEngineInit:
|
|
|
|
code = 500
|
|
|
|
case handlers.ErrEngineExec:
|
|
|
|
code = 500
|
|
|
|
default:
|
|
|
|
code = 200
|
2024-09-06 01:40:57 +02:00
|
|
|
}
|
2024-09-12 04:30:23 +02:00
|
|
|
|
|
|
|
if code != 200 {
|
|
|
|
f.writeError(w, 500, err)
|
2024-09-06 01:40:57 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(200)
|
|
|
|
w.Header().Set("Content-Type", "text/plain")
|
2024-09-12 04:30:23 +02:00
|
|
|
err = f.Output(rqs)
|
2024-09-06 01:40:57 +02:00
|
|
|
if err != nil {
|
2024-09-12 04:30:23 +02:00
|
|
|
f.writeError(w, 500, err)
|
2024-09-06 01:40:57 +02:00
|
|
|
return
|
|
|
|
}
|
2024-09-12 04:30:23 +02:00
|
|
|
|
|
|
|
err = f.Reset(rqs)
|
2024-09-06 01:40:57 +02:00
|
|
|
if err != nil {
|
2024-09-12 04:30:23 +02:00
|
|
|
f.writeError(w, 500, err)
|
2024-09-06 01:40:57 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|