forked from urdt/ussd
		
	Isolate http specific parts to minimal
This commit is contained in:
		
							parent
							
								
									0f9b5551ec
								
							
						
					
					
						commit
						dde9f552a6
					
				| @ -112,6 +112,7 @@ func getResource(resourceDir string, ctx context.Context) (resource.Resource, er | ||||
| 	return rfs, nil | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| func main() { | ||||
| 	var dbDir string | ||||
| 	var resourceDir string | ||||
|  | ||||
							
								
								
									
										47
									
								
								internal/handlers/single.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								internal/handlers/single.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| package handlers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"git.defalsify.org/vise.git/engine" | ||||
| 	"git.defalsify.org/vise.git/resource" | ||||
| 	"git.defalsify.org/vise.git/persist" | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/internal/storage" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	ErrInvalidRequest = errors.New("invalid request for context") | ||||
| 	ErrSessionMissing = errors.New("missing session") | ||||
| 	ErrInvalidInput = errors.New("invalid input") | ||||
| 	ErrStorage = errors.New("storage retrieval fail") | ||||
| 	ErrEngineType = errors.New("incompatible engine") | ||||
| 	ErrEngineInit = errors.New("engine init fail") | ||||
| 	ErrEngineExec = errors.New("engine exec fail") | ||||
| ) | ||||
| 
 | ||||
| type RequestSession struct { | ||||
| 	Ctx context.Context | ||||
| 	Config engine.Config | ||||
| 	Engine engine.Engine | ||||
| 	Input []byte | ||||
| 	Storage storage.Storage | ||||
| 	Writer io.Writer | ||||
| } | ||||
| 
 | ||||
| type engineMaker func(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine | ||||
| 
 | ||||
| type RequestParser interface { | ||||
| 	GetSessionId(rq any) (string, error) | ||||
| 	GetInput(rq any) ([]byte, error) | ||||
| } | ||||
| 
 | ||||
| type RequestHandler interface { | ||||
| 	GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine  | ||||
| 	Process(rs RequestSession) (RequestSession, error) | ||||
| 	Output(rs RequestSession) (RequestSession, error) | ||||
| 	Reset(rs RequestSession) (RequestSession, error) | ||||
| 	ShutDown() | ||||
| } | ||||
| @ -1,9 +1,9 @@ | ||||
| package http | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"git.defalsify.org/vise.git/db" | ||||
| 	"git.defalsify.org/vise.git/engine" | ||||
| @ -11,32 +11,38 @@ import ( | ||||
| 	"git.defalsify.org/vise.git/persist" | ||||
| 	"git.defalsify.org/vise.git/resource" | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/internal/handlers" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/handlers/ussd" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/storage" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	logg = logging.NewVanilla().WithDomain("httpserver") | ||||
| ) | ||||
| 
 | ||||
| type RequestParser interface { | ||||
| 	GetSessionId(rq *http.Request) (string, error) | ||||
| 	GetInput(rq *http.Request) ([]byte, error) | ||||
| } | ||||
| 
 | ||||
| type DefaultRequestParser struct { | ||||
| } | ||||
| 
 | ||||
| func(rp *DefaultRequestParser) GetSessionId(rq *http.Request) (string, error) { | ||||
| 	v := rq.Header.Get("X-Vise-Session") | ||||
| 
 | ||||
| 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") | ||||
| 	if v == "" { | ||||
| 		return "", fmt.Errorf("no session found") | ||||
| 		return "", handlers.ErrSessionMissing | ||||
| 	} | ||||
| 	return v, nil | ||||
| } | ||||
| 
 | ||||
| func(rp *DefaultRequestParser) GetInput(rq *http.Request) ([]byte, error) { | ||||
| 	defer rq.Body.Close() | ||||
| 	v, err := ioutil.ReadAll(rq.Body) | ||||
| 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) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -45,33 +51,30 @@ func(rp *DefaultRequestParser) GetInput(rq *http.Request) ([]byte, error) { | ||||
| 
 | ||||
| type SessionHandler struct { | ||||
| 	cfgTemplate engine.Config | ||||
| 	rp RequestParser | ||||
| 	rp handlers.RequestParser | ||||
| 	rs resource.Resource | ||||
| 	//first resource.EntryFunc
 | ||||
| 	hn *ussd.Handlers | ||||
| 	provider StorageProvider | ||||
| 	provider storage.StorageProvider | ||||
| } | ||||
| 
 | ||||
| //func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, first resource.EntryFunc) *SessionHandler {
 | ||||
| func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn *ussd.Handlers) *SessionHandler { | ||||
| func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp handlers.RequestParser, hn *ussd.Handlers) *SessionHandler { | ||||
| 	return &SessionHandler{ | ||||
| 		cfgTemplate: cfg, | ||||
| 		rs: rs, | ||||
| 		//first: first,
 | ||||
| 		hn: hn, | ||||
| 		rp: rp, | ||||
| 		provider: NewSimpleStorageProvider(stateDb, userdataDb), | ||||
| 		provider: storage.NewSimpleStorageProvider(stateDb, userdataDb), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func(f *SessionHandler) writeError(w http.ResponseWriter, code int, msg string, err error) { | ||||
| 	w.Header().Set("X-Vise", msg + ": " + err.Error()) | ||||
| 	w.Header().Set("Content-Length", "0") | ||||
| func(f *SessionHandler) writeError(w http.ResponseWriter, code int, err error) { | ||||
| 	s := err.Error() | ||||
| 	w.Header().Set("Content-Length", strconv.Itoa(len(s))) | ||||
| 	w.WriteHeader(code) | ||||
| 	_, err = w.Write([]byte{}) | ||||
| 	if err != nil { | ||||
| 		logg.Errorf("error writing error!!", "err", err, "olderr", s) | ||||
| 		w.WriteHeader(500) | ||||
| 		w.Header().Set("X-Vise", err.Error()) | ||||
| 	} | ||||
| 	return  | ||||
| } | ||||
| @ -83,68 +86,115 @@ func(f* SessionHandler) Shutdown() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func(f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||||
| 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) { | ||||
| 	var r bool | ||||
| 	sessionId, err := f.rp.GetSessionId(req) | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 400, "Session missing", err) | ||||
| 		return | ||||
| 	} | ||||
| 	input, err := f.rp.GetInput(req) | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 400, "Input read fail", err) | ||||
| 		return | ||||
| 	} | ||||
| 	ctx := req.Context() | ||||
| 	cfg := f.cfgTemplate | ||||
| 	cfg.SessionId = sessionId | ||||
| 	var err error | ||||
| 	var ok bool | ||||
| 	 | ||||
| 	logg.InfoCtxf(rqs.Ctx, "new request",  rqs) | ||||
| 
 | ||||
| 	logg.InfoCtxf(ctx, "new request",  "session", cfg.SessionId, "input", input) | ||||
| 
 | ||||
| 	storage, err := f.provider.Get(cfg.SessionId) | ||||
| 	rqs.Storage, err = f.provider.Get(rqs.Config.SessionId) | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 500, "Storage retrieval fail", err) | ||||
| 		return | ||||
| 		logg.ErrorCtxf(rqs.Ctx, "", "storage error", "err", err) | ||||
| 		return rqs, handlers.ErrStorage | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| 	} | ||||
| 	f.hn = f.hn.WithPersister(storage.Persister) | ||||
| 	defer f.provider.Put(cfg.SessionId, storage) | ||||
| 	en := getEngine(cfg, f.rs, storage.Persister) | ||||
| 	en = en.WithFirst(f.hn.Init) | ||||
| 	if cfg.EngineDebug { | ||||
| 	if rqs.Config.EngineDebug { | ||||
| 		en = en.WithDebug(nil) | ||||
| 	} | ||||
| 	rqs.Engine = en | ||||
| 
 | ||||
| 	r, err = en.Init(ctx) | ||||
| 	r, err = rqs.Engine.Init(rqs.Ctx) | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 500, "Engine init fail", err) | ||||
| 		return rqs, err | ||||
| 	} | ||||
| 
 | ||||
| 	if r && len(rqs.Input) > 0 { | ||||
| 		r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return rqs, err | ||||
| 	} | ||||
| 
 | ||||
| 	_ = 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, | ||||
| 	} | ||||
| 
 | ||||
| 	cfg := f.cfgTemplate | ||||
| 	cfg.SessionId, err = f.rp.GetSessionId(req) | ||||
| 	if err != nil { | ||||
| 		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) | ||||
| 		return | ||||
| 	} | ||||
| 	if r && len(input) > 0 { | ||||
| 		r, err = en.Exec(ctx, input) | ||||
| 
 | ||||
| 	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 | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 500, "Engine exec fail", err) | ||||
| 
 | ||||
| 	if code != 200 { | ||||
| 		f.writeError(w, 500, err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	w.WriteHeader(200) | ||||
| 	w.Header().Set("Content-Type", "text/plain") | ||||
| 	_, err = en.WriteResult(ctx, w) | ||||
| 	err = f.Output(rqs) | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 500, "Write result fail", err) | ||||
| 		return | ||||
| 	} | ||||
| 	err = en.Finish() | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 500, "Engine finish fail", err) | ||||
| 		f.writeError(w, 500, err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	_ = r | ||||
| } | ||||
| 
 | ||||
| func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *engine.DefaultEngine { | ||||
| 	en := engine.NewEngine(cfg, rs) | ||||
| 	en = en.WithPersister(pr) | ||||
| 	return en | ||||
| 	err = f.Reset(rqs) | ||||
| 	if err != nil { | ||||
| 		f.writeError(w, 500, err) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| package http | ||||
| package storage | ||||
| 
 | ||||
| import ( | ||||
| 	"git.defalsify.org/vise.git/db" | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user