github.com/hzck/speedroute@v0.0.0-20201115191102-403b7d0e443f/main_old.txt (about) 1 // Package main creates the web server. 2 package main 3 4 import ( 5 "encoding/json" 6 "io/ioutil" 7 "log" 8 "net/http" 9 "os" 10 "strings" 11 "sync" 12 "time" 13 14 "github.com/gorilla/mux" 15 16 a "github.com/hzck/speedroute/algorithm" 17 p "github.com/hzck/speedroute/parser" 18 ) 19 20 var mutex = &sync.Mutex{} 21 22 type iIOUtil interface { 23 ReadDir(dirname string) ([]string, error) 24 } 25 26 type iFileSystem interface { 27 Create(name string) (iFile, error) 28 IsNotExist(err error) bool 29 Remove(name string) error 30 Stat(name string) (os.FileInfo, error) 31 } 32 33 type iFile interface { 34 Close() error 35 WriteString(s string) (int, error) 36 } 37 38 type iFileInfo interface { 39 Name() string 40 } 41 42 type ioutilFS struct{} 43 44 func (ioutilFS) ReadDir(dirname string) ([]string, error) { 45 readDir, err := ioutil.ReadDir(dirname) 46 if err != nil { 47 return nil, err 48 } 49 fileInfos := make([]iFileInfo, len(readDir)) 50 for i, v := range readDir { 51 fileInfos[i] = v 52 } 53 return extractNames(fileInfos), nil 54 } 55 56 func extractNames(readDir []iFileInfo) []string { 57 list := make([]string, len(readDir)) 58 for i := range list { 59 file := readDir[i].Name() 60 list[i] = file[0 : len(file)-5] 61 } 62 return list 63 } 64 65 type osFile struct { 66 file *os.File 67 } 68 69 func (ref *osFile) WriteString(s string) (int, error) { 70 return ref.file.WriteString(s) 71 } 72 73 func (ref *osFile) Close() error { 74 return ref.file.Close() 75 } 76 77 type osFS struct{} 78 79 func (osFS) Create(name string) (iFile, error) { 80 f, err := os.Create(name) 81 if err != nil { 82 return nil, err 83 } 84 return &osFile{f}, nil 85 } 86 87 func (osFS) IsNotExist(err error) bool { 88 return os.IsNotExist(err) 89 } 90 91 func (osFS) Remove(name string) error { 92 return os.Remove(name) 93 } 94 95 func (osFS) Stat(name string) (os.FileInfo, error) { 96 return os.Stat(name) 97 } 98 99 func main2() { 100 // Creating logfile 101 f, err := os.OpenFile("logfile", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 102 if err != nil { 103 panic(err) 104 } 105 defer func() { 106 if closeErr := f.Close(); closeErr != nil && err == nil { 107 panic(closeErr) 108 } 109 }() 110 log.SetOutput(f) 111 112 log.Println("### Server started ###") 113 fs := osFS{} 114 io := ioutilFS{} 115 r := mux.NewRouter() 116 r.HandleFunc("/create/{id:[A-Za-z0-9-_]+}/{pw:.*}", createGraphHandler(fs)).Methods("POST") 117 r.HandleFunc("/graphs", listGraphsHandler(io)).Methods("GET") 118 r.HandleFunc("/graph/{id:[A-Za-z0-9-_]+}", getGraphHandler(fs)).Methods("GET") 119 r.HandleFunc("/graph/{id:[A-Za-z0-9-_]+}/{pw:.*}", saveGraphHandler(fs)).Methods("POST") 120 r.PathPrefix("/").Handler(http.FileServer(http.Dir("public"))) 121 122 log.Println(http.ListenAndServe(":8001", r)) 123 } 124 125 func createFile(fs iFileSystem, filename, fileContent string) (httpStatus int, err error) { 126 file, err := fs.Create(filename) 127 if err != nil { 128 log.Println(err) 129 return http.StatusInternalServerError, err 130 } 131 defer func() { 132 if closeErr := file.Close(); closeErr != nil && err == nil { 133 log.Println(closeErr) 134 httpStatus = http.StatusInternalServerError 135 err = closeErr 136 return 137 } 138 }() 139 _, err = file.WriteString(fileContent) 140 if err != nil { 141 log.Println(err) 142 removeErr := fs.Remove(filename) 143 if removeErr != nil { 144 log.Println(removeErr) 145 } 146 return http.StatusInternalServerError, err 147 } 148 return http.StatusCreated, nil 149 } 150 151 func createGraphHandler(fs iFileSystem) http.HandlerFunc { 152 return func(w http.ResponseWriter, r *http.Request) { 153 filename := "graphs/" + mux.Vars(r)["id"] + ".json" 154 if _, err := fs.Stat(filename); fs.IsNotExist(err) { 155 fileContent := "{}" 156 newGraph, err := ioutil.ReadAll(r.Body) 157 if err != nil { 158 log.Println(err) 159 w.WriteHeader(http.StatusInternalServerError) 160 return 161 } 162 if len(newGraph) > 0 { 163 fileContent, err = p.LivesplitXMLtoJSON(string(newGraph)) 164 if err != nil { 165 w.WriteHeader(http.StatusBadRequest) 166 return 167 } 168 } 169 httpStatus, err := createFile(fs, filename, fileContent) 170 if err == nil { 171 pwFilename := "passwords/" + mux.Vars(r)["id"] + ".txt" 172 httpStatus, err = createFile(fs, pwFilename, mux.Vars(r)["pw"]) 173 if err != nil { 174 removeErr := fs.Remove(filename) 175 if removeErr != nil { 176 log.Println(removeErr) 177 } 178 } 179 } 180 w.WriteHeader(httpStatus) 181 return 182 } 183 w.WriteHeader(http.StatusConflict) 184 } 185 } 186 187 func getGraphHandler(fs iFileSystem) http.HandlerFunc { 188 return func(w http.ResponseWriter, r *http.Request) { 189 filename := "graphs/" + mux.Vars(r)["id"] + ".json" 190 if _, err := fs.Stat(filename); fs.IsNotExist(err) { 191 log.Println(err) 192 w.WriteHeader(http.StatusNotFound) 193 return 194 } 195 content, err := ioutil.ReadFile(filename) 196 if err != nil { 197 log.Println(err) 198 w.WriteHeader(http.StatusInternalServerError) 199 return 200 } 201 w.Header().Set("Content-Type", "application/json") 202 _, err = w.Write(content) 203 if err != nil { 204 log.Println(err) 205 w.WriteHeader(http.StatusInternalServerError) 206 } 207 } 208 } 209 210 func saveGraphHandler(fs iFileSystem) http.HandlerFunc { 211 return func(w http.ResponseWriter, r *http.Request) { 212 filename := "graphs/" + mux.Vars(r)["id"] + ".json" 213 if _, err := fs.Stat(filename); fs.IsNotExist(err) { 214 w.WriteHeader(http.StatusNotFound) 215 return 216 } 217 pwFilename := "passwords/" + mux.Vars(r)["id"] + ".txt" 218 if _, err := fs.Stat(pwFilename); fs.IsNotExist(err) { 219 w.WriteHeader(http.StatusNotFound) 220 return 221 } 222 pw, _ := ioutil.ReadFile(pwFilename) 223 if strings.Compare(string(pw), mux.Vars(r)["pw"]) != 0 { 224 w.WriteHeader(http.StatusUnauthorized) 225 return 226 } 227 newGraph, err := ioutil.ReadAll(r.Body) 228 if err != nil { 229 log.Println(err) 230 w.WriteHeader(http.StatusInternalServerError) 231 return 232 } 233 err = ioutil.WriteFile(filename, newGraph, 0600) 234 if err != nil { 235 log.Println(err) 236 w.WriteHeader(http.StatusInternalServerError) 237 return 238 } 239 240 graph, err := p.CreateGraphFromFile(filename) 241 if err != nil { 242 log.Println(err) 243 w.WriteHeader(http.StatusInternalServerError) 244 return 245 } 246 247 // Potential bottleneck draining memory, making sure only one graph is routed at any moment. 248 // Should add timing in log if it takes > 1s? 10s? 249 mutex.Lock() 250 start := time.Now() 251 result := a.Route(graph) 252 log.Printf("%s taking %s\n", filename, time.Since(start)) 253 mutex.Unlock() 254 js, err := p.CreateJSONFromRoutedPath(result) 255 w.Header().Set("Content-Type", "application/json") 256 if err != nil { 257 log.Println(err) 258 w.WriteHeader(http.StatusInternalServerError) 259 return 260 } 261 _, err = w.Write(js) 262 if err != nil { 263 log.Println(err) 264 w.WriteHeader(http.StatusInternalServerError) 265 return 266 } 267 } 268 } 269 270 func listGraphsHandler(io iIOUtil) http.HandlerFunc { 271 return func(w http.ResponseWriter, r *http.Request) { 272 graphs, err := io.ReadDir("graphs") 273 if err != nil { 274 log.Println(err) 275 w.WriteHeader(http.StatusInternalServerError) 276 return 277 } 278 js, err := json.Marshal(graphs) 279 if err != nil { 280 log.Println(err) 281 w.WriteHeader(http.StatusInternalServerError) 282 return 283 } 284 w.Header().Set("Content-Type", "application/json") 285 _, err = w.Write(js) 286 if err != nil { 287 log.Println(err) 288 w.WriteHeader(http.StatusInternalServerError) 289 return 290 } 291 } 292 }