wip-http-server #45

Closed
Alfred-mk wants to merge 1 commits from wip-http-server into master

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"flag" "flag"
"fmt" "fmt"
"io"
"net/http"
"os" "os"
"path" "path"
@ -23,6 +25,65 @@ var (
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
) )
type LocalHandler struct {
sessionId string
}
func NewLocalHandler() *LocalHandler {
return &LocalHandler{
sessionId: "",
}
}
type RequestParser interface {
GetSessionId(*http.Request) (string, error)
GetInput(*http.Request) ([]byte, error)
}
type DefaultRequestParser struct {
}
func(rp *DefaultRequestParser) GetSessionId(rq *http.Request) (string, error) {
v := rq.Header.Get("X-Vise-Session")
if v == "" {
return "", fmt.Errorf("no session found")
}
return v, nil
}
func(rp *DefaultRequestParser) GetInput(rq *http.Request) ([]byte, error) {
defer rq.Body.Close()
v, err := io.ReadAll(rq.Body)
if err != nil {
return nil, err
}
return v, nil
}
type DefaultSessionHandler struct {
cfgTemplate engine.Config
rp RequestParser
rh *LocalHandler
dbDir string
resourceDir string
}
func NewDefaultSessionHandler(dbDir string, resourceDir string, rp RequestParser, outputSize uint32, flagCount uint32) *DefaultSessionHandler {
rh := NewLocalHandler()
return &DefaultSessionHandler{
cfgTemplate: engine.Config{
OutputSize: outputSize,
Root: "root",
FlagCount: flagCount,
},
rh: rh,
rp: rp,
dbDir: dbDir,
resourceDir: resourceDir,
}
}
func getParser(fp string, debug bool) (*asm.FlagParser, error) { func getParser(fp string, debug bool) (*asm.FlagParser, error) {
flagParser := asm.NewFlagParser().WithDebug() flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp) _, err := flagParser.Load(fp)
@ -74,29 +135,29 @@ func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.P
return ussdHandlers, nil return ussdHandlers, nil
} }
func getPersister(dbDir string, ctx context.Context) (*persist.Persister, error) { func(f *DefaultSessionHandler) getPersister(ctx context.Context) (*persist.Persister, error) {
err := os.MkdirAll(dbDir, 0700) err := os.MkdirAll(f.dbDir, 0700)
if err != nil { if err != nil {
return nil, fmt.Errorf("state dir create exited with error: %v\n", err) return nil, fmt.Errorf("state dir create exited with error: %v\n", err)
} }
store := gdbmdb.NewGdbmDb() store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "state.gdbm") storeFile := path.Join(f.dbDir, "state.gdbm")
store.Connect(ctx, storeFile) store.Connect(ctx, storeFile)
pr := persist.NewPersister(store) pr := persist.NewPersister(store)
return pr, nil return pr, nil
} }
func getUserdataDb(dbDir string, ctx context.Context) db.Db { func(f *DefaultSessionHandler) getUserdataDb(ctx context.Context) db.Db {
store := gdbmdb.NewGdbmDb() store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "userdata.gdbm") storeFile := path.Join(f.dbDir, "userdata.gdbm")
store.Connect(ctx, storeFile) store.Connect(ctx, storeFile)
return store return store
} }
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) { func(f *DefaultSessionHandler) getResource(ctx context.Context) (resource.Resource, error) {
store := fsdb.NewFsDb() store := fsdb.NewFsDb()
err := store.Connect(ctx, resourceDir) err := store.Connect(ctx, f.resourceDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -104,87 +165,144 @@ func getResource(resourceDir string, ctx context.Context) (resource.Resource, er
return rfs, nil return rfs, nil
} }
func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *engine.DefaultEngine { func(f *DefaultSessionHandler) getEngine(rs resource.Resource, pr *persist.Persister, sessionId string) *engine.DefaultEngine {
cfg := f.cfgTemplate
cfg.SessionId = sessionId
en := engine.NewEngine(cfg, rs) en := engine.NewEngine(cfg, rs)
en = en.WithPersister(pr) en = en.WithPersister(pr)
return en return en
} }
func(f *DefaultSessionHandler) writeError(w http.ResponseWriter, code int, msg string, err error) {
w.Header().Set("X-Vise", msg + ": " + err.Error())
w.Header().Set("Content-Length", "0")
w.WriteHeader(code)
_, err = w.Write([]byte{})
if err != nil {
w.WriteHeader(500)
w.Header().Set("X-Vise", err.Error())
}
return
}
func(f *DefaultSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
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()
ctx = context.WithValue(ctx, "SessionId", sessionId)
pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := getParser(pfp, true)
if err != nil {
f.writeError(w, 500, "flagParser failed with error:", err)
return
}
rs, err := f.getResource(ctx)
if err != nil {
f.writeError(w, 500, "getResource failed with error:", err)
return
}
pr, err := f.getPersister(ctx)
if err != nil {
f.writeError(w, 500, "getPersister failed with error:", err)
return
}
store := f.getUserdataDb(ctx)
dbResource, ok := rs.(*resource.DbResource)
if !ok {
f.writeError(w, 500, "getHandler exited with error:", err)
return
}
hl, err := getHandler(flagParser, dbResource, pr, store)
if err != nil {
f.writeError(w, 500, "getHandler exited with error:", err)
return
}
en := f.getEngine(rs, pr, sessionId)
en = en.WithFirst(hl.Init)
if len(input) == 0 {
r, err = en.Init(ctx)
} else {
r, err = en.Exec(ctx, input)
}
if err != nil {
f.writeError(w, 500, "Engine exec fail", err)
return
}
// _, err = en.Init(ctx)
// if err != nil {
// f.writeError(w, 500, "Engine exec fail", err)
// return
// }
// err = engine.Loop(ctx, en, os.Stdin, os.Stdout)
// if err != nil {
// f.writeError(w, 500, "Loop exec fail", err)
// return
// }
w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain")
_, err = en.WriteResult(ctx, w)
if err != nil {
f.writeError(w, 500, "Write result fail", err)
return
}
_ = r
}
func main() { func main() {
var host string
var port string
var dbDir string var dbDir string
var resourceDir string var resourceDir string
var size uint var size uint
var flagCount uint
var sessionId string var sessionId string
var debug bool var debug bool
flag.StringVar(&host, "h", "127.0.0.1", "http host")
flag.StringVar(&port, "p", "7123", "http port")
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir") flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.BoolVar(&debug, "d", false, "use engine debug output") flag.BoolVar(&debug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output") flag.UintVar(&size, "s", 160, "max size of output")
flag.UintVar(&flagCount, "f", 16, "flag count")
flag.Parse() flag.Parse()
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size) logg.Infof("starting server", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "flagCount", flagCount)
ctx := context.Background() rp := &DefaultRequestParser{}
ctx = context.WithValue(ctx, "SessionId", sessionId) h := NewDefaultSessionHandler(dbDir, resourceDir, rp, uint32(size), uint32(flagCount))
pfp := path.Join(scriptDir, "pp.csv") s := &http.Server{
flagParser, err := getParser(pfp, true) Addr: fmt.Sprintf("%s:%s", host, port),
Handler: h,
}
err := s.ListenAndServe()
if err != nil { if err != nil {
os.Exit(1) fmt.Fprintf(os.Stderr, "Server error: %s", err)
}
cfg := engine.Config{
Root: "root",
SessionId: sessionId,
OutputSize: uint32(size),
FlagCount: uint32(16),
}
rs, err := getResource(resourceDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
pr, err := getPersister(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
store := getUserdataDb(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource)
if !ok {
os.Exit(1)
}
hl, err := getHandler(flagParser, dbResource, pr, store)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
en := getEngine(cfg, rs, pr)
en = en.WithFirst(hl.Init)
if debug {
en = en.WithDebug(nil)
}
_, err = en.Init(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "engine init exited with error: %v\n", err)
os.Exit(1)
}
err = engine.Loop(ctx, en, os.Stdin, os.Stdout)
if err != nil {
fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
} }