main.go (4922B)
1 // Example: HTTP server wrapper (to be used with manual client). 2 package main 3 4 import ( 5 "context" 6 "flag" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "path" 12 13 "git.defalsify.org/vise.git/engine" 14 "git.defalsify.org/vise.git/persist" 15 "git.defalsify.org/vise.git/resource" 16 "git.defalsify.org/vise.git/logging" 17 fsdb "git.defalsify.org/vise.git/db/fs" 18 ) 19 20 var ( 21 logg logging.Logger = logging.NewVanilla().WithDomain("http") 22 ) 23 24 type LocalHandler struct { 25 sessionId string 26 } 27 28 func NewLocalHandler() *LocalHandler { 29 return &LocalHandler{ 30 sessionId: "", 31 } 32 } 33 34 func(h* LocalHandler) SetSession(sessionId string) { 35 h.sessionId = sessionId 36 } 37 38 func(h* LocalHandler) AddSession(ctx context.Context, sym string, input []byte) (resource.Result, error) { 39 return resource.Result{ 40 Content: h.sessionId + ":" + string(input), 41 }, nil 42 } 43 44 type RequestParser interface { 45 GetSessionId(*http.Request) (string, error) 46 GetInput(*http.Request) ([]byte, error) 47 } 48 49 type DefaultRequestParser struct { 50 } 51 52 func(rp *DefaultRequestParser) GetSessionId(rq *http.Request) (string, error) { 53 v := rq.Header.Get("X-Vise-Session") 54 if v == "" { 55 return "", fmt.Errorf("no session found") 56 } 57 return v, nil 58 } 59 60 func(rp *DefaultRequestParser) GetInput(rq *http.Request) ([]byte, error) { 61 defer rq.Body.Close() 62 v, err := ioutil.ReadAll(rq.Body) 63 if err != nil { 64 return nil, err 65 } 66 return v, nil 67 } 68 69 type DefaultSessionHandler struct { 70 cfgTemplate engine.Config 71 rp RequestParser 72 rs resource.Resource 73 rh *LocalHandler 74 peBase string 75 } 76 77 func NewDefaultSessionHandler(ctx context.Context, persistBase string, resourceBase string, rp RequestParser, outputSize uint32, cacheSize uint32, flagCount uint32) *DefaultSessionHandler { 78 store := fsdb.NewFsDb() 79 err := store.Connect(ctx, resourceBase) 80 if err != nil { 81 panic(err) 82 } 83 rs := resource.NewDbResource(store) 84 rh := NewLocalHandler() 85 rs.AddLocalFunc("echo", rh.AddSession) 86 return &DefaultSessionHandler{ 87 cfgTemplate: engine.Config{ 88 OutputSize: outputSize, 89 Root: "root", 90 FlagCount: flagCount, 91 CacheSize: cacheSize, 92 }, 93 rs: rs, 94 rh: rh, 95 rp: rp, 96 } 97 } 98 99 func(f *DefaultSessionHandler) GetEngine(ctx context.Context, sessionId string) (engine.Engine, error) { 100 cfg := f.cfgTemplate 101 cfg.SessionId = sessionId 102 103 //persistPath := path.Join(f.peBase, sessionId) 104 persistPath := path.Join(f.peBase) 105 if persistPath == "" { 106 persistPath = ".state" 107 } 108 store := fsdb.NewFsDb() 109 err := store.Connect(ctx, persistPath) 110 if err != nil { 111 return nil, err 112 } 113 store.SetSession(cfg.SessionId) 114 f.rh.SetSession(cfg.SessionId) 115 116 pe := persist.NewPersister(store) 117 en := engine.NewEngine(cfg, f.rs) 118 en = en.WithPersister(pe) 119 120 return en, err 121 } 122 123 func(f *DefaultSessionHandler) writeError(w http.ResponseWriter, code int, msg string, err error) { 124 w.Header().Set("X-Vise", msg + ": " + err.Error()) 125 w.Header().Set("Content-Length", "0") 126 w.WriteHeader(code) 127 _, err = w.Write([]byte{}) 128 if err != nil { 129 w.WriteHeader(500) 130 w.Header().Set("X-Vise", err.Error()) 131 } 132 return 133 } 134 135 func(f *DefaultSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 136 var r bool 137 sessionId, err := f.rp.GetSessionId(req) 138 if err != nil { 139 f.writeError(w, 400, "Session missing", err) 140 return 141 } 142 input, err := f.rp.GetInput(req) 143 if err != nil { 144 f.writeError(w, 400, "Input read fail", err) 145 return 146 } 147 ctx := req.Context() 148 en, err := f.GetEngine(ctx, sessionId) 149 if err != nil { 150 f.writeError(w, 400, "Engine start fail", err) 151 return 152 } 153 154 //if len(input) == 0 { 155 // r, err = en.Init(ctx) 156 //} else { 157 r, err = en.Exec(ctx, input) 158 //} 159 if err != nil { 160 f.writeError(w, 500, "Engine exec fail", err) 161 return 162 } 163 w.WriteHeader(200) 164 w.Header().Set("Content-Type", "text/plain") 165 _, err = en.Flush(ctx, w) 166 if err != nil { 167 f.writeError(w, 500, "Write result fail", err) 168 return 169 } 170 err = en.Finish() 171 if err != nil { 172 f.writeError(w, 500, "Engine finish fail", err) 173 return 174 } 175 _ = r 176 } 177 178 func main() { 179 var host string 180 var port string 181 var peDir string 182 var rsDir string 183 var outSize uint 184 var flagCount uint 185 var cacheSize uint 186 flag.StringVar(&rsDir, "r", ".", "resource dir") 187 flag.StringVar(&host, "h", "127.0.0.1", "http host") 188 flag.StringVar(&port, "p", "7123", "http port") 189 flag.StringVar(&peDir, "d", ".state", "persistance dir") 190 flag.UintVar(&flagCount, "f", 0, "flag count") 191 flag.UintVar(&cacheSize, "c", 1024 * 1024, "cache size") 192 flag.UintVar(&outSize, "s", 160, "max size of output") 193 flag.Parse() 194 fmt.Fprintf(os.Stderr, "starting server:\n\tpersistence dir: %s\n\tresource dir: %s\n", rsDir, peDir) 195 196 ctx := context.Background() 197 rp := &DefaultRequestParser{} 198 h := NewDefaultSessionHandler(ctx, peDir, rsDir, rp, uint32(outSize), uint32(cacheSize), uint32(flagCount)) 199 s := &http.Server{ 200 Addr: fmt.Sprintf("%s:%s", host, port), 201 Handler: h, 202 } 203 err := s.ListenAndServe() 204 if err != nil { 205 fmt.Fprintf(os.Stderr, "Server error: %s", err) 206 os.Exit(1) 207 } 208 }