Skip to content

Commit de61584

Browse files
committed
feat(server): add a basic server
Pending addition of websocket for live reload
1 parent a81f68a commit de61584

File tree

1 file changed

+101
-2
lines changed

1 file changed

+101
-2
lines changed

pkg/alvu/alvu.go

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,108 @@ func (ac *AlvuConfig) StartServer() error {
322322
return nil
323323
}
324324

325-
http.Handle("/", http.FileServer(http.Dir(ac.OutDir)))
325+
normalizedPort := string(ac.PortNumber)
326+
327+
if !strings.HasPrefix(normalizedPort, ":") {
328+
normalizedPort = ":" + normalizedPort
329+
}
330+
331+
http.Handle("/", http.HandlerFunc(ac.ServeHandler))
326332
ac.logger.Info(fmt.Sprintf("Starting Server - %v:%v", "http://localhost", ac.PortNumber))
327-
return http.ListenAndServe(fmt.Sprintf(":%v", ac.PortNumber), nil)
333+
334+
err := http.ListenAndServe(normalizedPort, nil)
335+
if strings.Contains(err.Error(), "address already in use") {
336+
ac.logger.Error("port already in use, use another port with the `-port` flag instead")
337+
return err
338+
}
339+
340+
return nil
341+
}
342+
343+
func (ac *AlvuConfig) ServeHandler(rw http.ResponseWriter, req *http.Request) {
344+
path := req.URL.Path
345+
346+
if path == "/" {
347+
path = filepath.Join(ac.OutDir, "index.html")
348+
http.ServeFile(rw, req, path)
349+
return
350+
}
351+
352+
// check if the requested file already exists
353+
file := filepath.Join(ac.OutDir, path)
354+
info, err := os.Stat(file)
355+
356+
// if not, check if it's a directory
357+
// and if it's a directory, we look for
358+
// a index.html inside the directory to return instead
359+
if err == nil {
360+
if info.Mode().IsDir() {
361+
file = filepath.Join(ac.OutDir, path, "index.html")
362+
_, err := os.Stat(file)
363+
if err != nil {
364+
ac.notFoundHandler(rw, req)
365+
return
366+
}
367+
}
368+
369+
http.ServeFile(rw, req, file)
370+
return
371+
}
372+
373+
// if neither a directory or file was found
374+
// try a secondary case where the file might be missing
375+
// a `.html` extension for cleaner url so append a .html
376+
// to look for the file.
377+
if err != nil {
378+
file := filepath.Join(ac.OutDir, normalizeStaticLookupPath(path))
379+
_, err := os.Stat(file)
380+
381+
if err != nil {
382+
ac.notFoundHandler(rw, req)
383+
return
384+
}
385+
386+
http.ServeFile(rw, req, file)
387+
return
388+
}
389+
390+
ac.notFoundHandler(rw, req)
391+
}
392+
393+
func (ac *AlvuConfig) notFoundHandler(w http.ResponseWriter, r *http.Request) {
394+
var notFoundPageExists bool
395+
filePointer, err := os.Stat(filepath.Join(ac.OutDir, "404.html"))
396+
if err != nil {
397+
if os.IsNotExist(err) {
398+
notFoundPageExists = false
399+
}
400+
}
401+
402+
if filePointer.Size() > 0 {
403+
notFoundPageExists = true
404+
}
405+
406+
if notFoundPageExists {
407+
compiledNotFoundFile := filepath.Join(ac.OutDir, "404.html")
408+
notFoundFile, err := os.ReadFile(compiledNotFoundFile)
409+
if err != nil {
410+
http.Error(w, "404, Page not found....", http.StatusNotFound)
411+
return
412+
}
413+
w.WriteHeader(http.StatusNotFound)
414+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
415+
w.Write(notFoundFile)
416+
return
417+
}
418+
419+
http.Error(w, "404, Page not found....", http.StatusNotFound)
420+
}
421+
422+
func normalizeStaticLookupPath(path string) string {
423+
if strings.HasSuffix(path, ".html") {
424+
return path
425+
}
426+
return path + ".html"
328427
}
329428

330429
func recursiveRead(dir string) (filepaths []string, err error) {

0 commit comments

Comments
 (0)