K-EXPLORER: add embed ui mode

This commit is contained in:
niusmallnan 2021-04-16 14:17:08 +08:00
parent 8c327e08ad
commit 327be56d3a
6 changed files with 170 additions and 52 deletions

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/rancher/steve
go 1.13
go 1.16
replace (
github.com/crewjam/saml => github.com/rancher/saml v0.0.0-20180713225824-ce1532152fde

97
pkg/ui/embed.go Normal file
View File

@ -0,0 +1,97 @@
// +build embed
package ui
import (
"embed"
"io"
"io/fs"
"net/http"
"path/filepath"
"strings"
"github.com/sirupsen/logrus"
)
// content holds our static web server content.
//go:embed ui/*
var staticContent embed.FS
type fsFunc func(name string) (fs.File, error)
func (f fsFunc) Open(name string) (fs.File, error) {
return f(name)
}
func pathExist(path string) bool {
path = formatPath(path)
_, err := staticContent.Open(path)
return err == nil
}
func openFile(path string) (fs.File, error) {
path = formatPath(path)
file, err := staticContent.Open(path)
if err != nil {
logrus.Errorf("openEmbedFile %s err: %v", path, err)
}
return file, err
}
func formatPath(path string) string {
// To replace _nuxt/_cluster/...
// For embed, If a pattern names a directory,
// all files in the subtree rooted at that directory are embedded (recursively),
// except that files with names beginning with . or _ are excluded.
return strings.ReplaceAll(path, "_", "")
}
func serveEmbed(basePath string) http.Handler {
handler := fsFunc(func(name string) (fs.File, error) {
logrus.Debugf("serveEmbed name: %s", name)
assetPath := filepath.Join(basePath, name)
logrus.Debugf("serveEmbed final path: %s", assetPath)
return openFile(assetPath)
})
return http.FileServer(http.FS(handler))
}
func serveEmbedIndex(basePath string) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
path := filepath.Join(basePath, "dashboard", "index.html")
logrus.Debugf("serveEmbedIndex : %s", path)
f, _ := staticContent.Open(path)
io.Copy(rw, f)
f.Close()
})
}
func (u *Handler) ServeAsset() http.Handler {
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
serveEmbed(u.pathSetting()).ServeHTTP(rw, req)
}))
}
func (u *Handler) ServeFaviconDashboard() http.Handler {
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
serveEmbed(filepath.Join(u.pathSetting(), "dashboard")).ServeHTTP(rw, req)
}))
}
func (u *Handler) IndexFileOnNotFound() http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
path := filepath.Join(u.pathSetting(), req.URL.Path)
if pathExist(path) {
u.ServeAsset().ServeHTTP(rw, req)
} else {
u.IndexFile().ServeHTTP(rw, req)
}
})
}
func (u *Handler) IndexFile() http.Handler {
return u.indexMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
serveEmbedIndex(u.pathSetting()).ServeHTTP(rw, req)
}))
}

42
pkg/ui/external.go Normal file
View File

@ -0,0 +1,42 @@
// +build !embed
package ui
import (
"net/http"
"os"
"path/filepath"
)
func (u *Handler) ServeAsset() http.Handler {
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir(u.pathSetting())).ServeHTTP(rw, req)
}))
}
func (u *Handler) ServeFaviconDashboard() http.Handler {
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir(filepath.Join(u.pathSetting(), "dashboard"))).ServeHTTP(rw, req)
}))
}
func (u *Handler) IndexFileOnNotFound() http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// we ignore directories here because we want those to come from the CDN when running in that mode
if stat, err := os.Stat(filepath.Join(u.pathSetting(), req.URL.Path)); err == nil && !stat.IsDir() {
u.ServeAsset().ServeHTTP(rw, req)
} else {
u.IndexFile().ServeHTTP(rw, req)
}
})
}
func (u *Handler) IndexFile() http.Handler {
return u.indexMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if path, isURL := u.path(); isURL {
_ = serveIndex(rw, path)
} else {
http.ServeFile(rw, req, filepath.Join(path, "index.html"))
}
}))
}

View File

@ -5,14 +5,16 @@ import (
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"sync"
"github.com/rancher/apiserver/pkg/middleware"
"github.com/sirupsen/logrus"
)
const (
defaultPath = "./ui"
)
var (
insecureClient = &http.Client{
Transport: &http.Transport{
@ -24,10 +26,6 @@ var (
}
)
const (
defaultPath = "./ui"
)
type StringSetting func() string
type BoolSetting func() bool
@ -104,17 +102,6 @@ func NewUIHandler(opts *Options) *Handler {
return h
}
func (u *Handler) canDownload(url string) bool {
u.downloadOnce.Do(func() {
if err := serveIndex(ioutil.Discard, url); err == nil {
u.downloadSuccess = true
} else {
logrus.Errorf("Failed to download %s, falling back to packaged UI", url)
}
})
return u.downloadSuccess
}
func (u *Handler) path() (path string, isURL bool) {
switch u.offlineSetting() {
case "dynamic":
@ -132,37 +119,15 @@ func (u *Handler) path() (path string, isURL bool) {
}
}
func (u *Handler) ServeAsset() http.Handler {
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir(u.pathSetting())).ServeHTTP(rw, req)
}))
}
func (u *Handler) ServeFaviconDashboard() http.Handler {
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir(filepath.Join(u.pathSetting(), "dashboard"))).ServeHTTP(rw, req)
}))
}
func (u *Handler) IndexFileOnNotFound() http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// we ignore directories here because we want those to come from the CDN when running in that mode
if stat, err := os.Stat(filepath.Join(u.pathSetting(), req.URL.Path)); err == nil && !stat.IsDir() {
u.ServeAsset().ServeHTTP(rw, req)
func (u *Handler) canDownload(url string) bool {
u.downloadOnce.Do(func() {
if err := serveIndex(ioutil.Discard, url); err == nil {
u.downloadSuccess = true
} else {
u.IndexFile().ServeHTTP(rw, req)
logrus.Errorf("Failed to download %s, falling back to packaged UI", url)
}
})
}
func (u *Handler) IndexFile() http.Handler {
return u.indexMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if path, isURL := u.path(); isURL {
_ = serveIndex(rw, path)
} else {
http.ServeFile(rw, req, filepath.Join(path, "index.html"))
}
}))
return u.downloadSuccess
}
func serveIndex(resp io.Writer, url string) error {

View File

@ -5,10 +5,7 @@ import (
"strings"
"github.com/gorilla/mux"
)
var (
UIOffline = "dynamic"
"github.com/rancher/steve/pkg/version"
)
func New(path string) http.Handler {
@ -20,7 +17,13 @@ func New(path string) http.Handler {
return path
},
Offline: func() string {
return UIOffline
if path != "" {
return "true"
}
return "dynamic"
},
ReleaseSetting: func() bool {
return version.IsRelease()
},
})

View File

@ -1,12 +1,23 @@
package version
import "fmt"
import (
"fmt"
"regexp"
"strings"
)
var (
Version = "dev"
GitCommit = "HEAD"
// K-EXPLORER
releasePattern = regexp.MustCompile("^v[0-9]")
)
func FriendlyVersion() string {
return fmt.Sprintf("%s (%s)", Version, GitCommit)
}
func IsRelease() bool {
return !strings.Contains(Version, "dev") && releasePattern.MatchString(Version)
}