diff --git a/pkg/api/api.go b/pkg/api/api.go index 0b0d5b1..88ec288 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -25,8 +25,7 @@ func New(token string) *API { func (api *API) EnableCors(fn http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - w.Header().Add("Access-Control-Allow-Origin", "http://localhost:8001") // todo: configurable port - w.Header().Add("Access-Control-Allow-Credentials", "true") + w.Header().Add("Access-Control-Allow-Origin", "*") w.Header().Add("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") diff --git a/pkg/dashboard/dashboard.go b/pkg/dashboard/dashboard.go index 72f06b2..fd38fd6 100644 --- a/pkg/dashboard/dashboard.go +++ b/pkg/dashboard/dashboard.go @@ -1,36 +1,82 @@ package dashboard import ( + "fmt" + "html/template" "net/http" + "strings" log "github.com/sirupsen/logrus" ) // Dashboard is the http server responsible for serving the static Dashboard files type Dashboard struct { + port string + rootDir string + apiPort string + apiScheme string + apiVersion string } // New is a factory function creating a new Dashboard instance func New() *Dashboard { - return &Dashboard{} + const webRootDir = "./web/static" // Todo: needs to work in containerized environment + const webPort = "8001" // Todo: make configurable? + const apiPort = "8080" // Todo: make configurable? + + return &Dashboard{ + apiPort: apiPort, + apiScheme: "http", + apiVersion: "v1", + rootDir: webRootDir, + port: webPort, + } } // Start the Dashboard and serve over HTTP -func (dashboard *Dashboard) Start() error { +func (d *Dashboard) Start() error { go func() { - runHTTPServer() + d.runHTTPServer() }() return nil } -func runHTTPServer() { +func (d *Dashboard) templatedHttpHandler(h http.Handler) http.HandlerFunc { + const apiUrlTemplate = "%s://%s:%s/%s/" + indexTemplate, err := template.ParseFiles(d.rootDir + "/index.html") + if err != nil { + log.Error("Error when parsing index template") + log.Error(err) + return nil + } + + return func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + hostName := strings.Split(r.Host, ":")[0] + apiUrl := fmt.Sprintf(apiUrlTemplate, d.apiScheme, hostName, d.apiPort, d.apiVersion) + err = indexTemplate.Execute(w, struct{ ApiUrl string }{ + ApiUrl: apiUrl, + }) + if err != nil { + log.Error("Error when executing index template") + log.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + } else { + h.ServeHTTP(w, r) + } + } +} + +func (d *Dashboard) getHandler() http.Handler { + return d.templatedHttpHandler(http.FileServer(http.Dir(d.rootDir))) +} + +func (d *Dashboard) runHTTPServer() { serveMux := http.NewServeMux() - serveMux.Handle("/", getHandler()) + serveMux.Handle("/", d.getHandler()) log.Debug("Starting http dashboard server") - log.Fatal(http.ListenAndServe(":8001", serveMux)) -} - -func getHandler() http.Handler { - return http.FileServer(http.Dir("./web/static")) + log.Fatal(http.ListenAndServe(":"+d.port, serveMux)) } diff --git a/web/static/api.js b/web/static/api.js index 0640df8..bcfb7e7 100644 --- a/web/static/api.js +++ b/web/static/api.js @@ -1,6 +1,15 @@ +function getEmbeddedVariable(variableName) { + const value = document.body.getAttribute(`data-${variableName}`); + if (value === null) { + throw new Error(`No ${variableName} embedded variable detected`); + } + + return value; +} + const apiFactory = () => { - const baseUrl = "http://localhost:8080/v1"; + const apiBasePath = getEmbeddedVariable("apipath"); let token = ""; const headers = () => ({ @@ -9,15 +18,15 @@ const apiFactory = () => { const logIn = async (password, remember) => { token = password; - const response = await fetch(baseUrl + "/list", { - credentials: "include", + const response = await fetch(apiBasePath + "list", { headers: headers() }); if (response.ok) { if (remember === true) { - localStorage.setItem("token", password); + localStorage.setItem("token", token); } + return true; } @@ -27,11 +36,10 @@ const apiFactory = () => { const checkLogin = async () => { const token = localStorage.getItem("token"); - if (token) { - const isLoggedIn = await logIn(token); - return isLoggedIn; + return await logIn(token); } + return false; }; @@ -40,8 +48,7 @@ const apiFactory = () => { }; const list = async () => { - const response = await fetch(baseUrl + "/list", { - credentials: "include", + const response = await fetch(apiBasePath + "list", { headers: headers() }); const data = await response.json(); @@ -52,9 +59,8 @@ const apiFactory = () => { const requestData = { ContainerId: containerId }; - const response = await fetch(baseUrl + "/check", { + const response = await fetch(apiBasePath + "check", { method: "POST", - credentials: "include", headers: { ...headers(), "Content-Type": "application/json", @@ -66,14 +72,13 @@ const apiFactory = () => { }; const update = async (images) => { - let updateUrl = new URL(baseUrl + "/update"); + let updateUrl = new URL(apiBasePath + "/update"); if (images instanceof Array) { images.map(image => updateUrl.searchParams.append("image", image)); } const response = await fetch(updateUrl.toString(), { - credentials: "include", headers: headers(), }); diff --git a/web/static/index.html b/web/static/index.html index 987a1ae..dd68e01 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -16,7 +16,7 @@ -
+