add http filesystem
This commit is contained in:
parent
3857968441
commit
76197bce6f
|
@ -104,7 +104,9 @@ func Geerate(app *types.Applicetion) (err error) {
|
|||
}
|
||||
writer.Reset()
|
||||
}
|
||||
|
||||
if err = writeFile(shortName+".go", []byte("package "+shortName)); err != nil {
|
||||
return
|
||||
}
|
||||
err = scanDir(protoDir, "third_party", func(filename string) error {
|
||||
if fp, openerr := protoDir.Open(filename); openerr != nil {
|
||||
return openerr
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
filesystem struct {
|
||||
fs http.FileSystem
|
||||
modtime time.Time
|
||||
prefix string
|
||||
indexFile string
|
||||
denyDirectory bool
|
||||
}
|
||||
|
||||
httpFile struct {
|
||||
fp http.File
|
||||
modtime time.Time
|
||||
}
|
||||
|
||||
httpFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode fs.FileMode
|
||||
isDir bool
|
||||
modtime time.Time
|
||||
}
|
||||
)
|
||||
|
||||
func (fi *httpFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
|
||||
func (fi *httpFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
|
||||
func (fi *httpFileInfo) Mode() fs.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
|
||||
func (fi *httpFileInfo) ModTime() time.Time {
|
||||
return fi.modtime
|
||||
}
|
||||
|
||||
func (fi *httpFileInfo) IsDir() bool {
|
||||
return fi.isDir
|
||||
}
|
||||
|
||||
func (fi *httpFileInfo) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (file *httpFile) Close() error {
|
||||
return file.fp.Close()
|
||||
}
|
||||
|
||||
func (file *httpFile) Read(p []byte) (n int, err error) {
|
||||
return file.fp.Read(p)
|
||||
}
|
||||
|
||||
func (file *httpFile) Seek(offset int64, whence int) (int64, error) {
|
||||
return file.fp.Seek(offset, whence)
|
||||
}
|
||||
|
||||
func (file *httpFile) Readdir(count int) ([]fs.FileInfo, error) {
|
||||
return file.fp.Readdir(count)
|
||||
}
|
||||
|
||||
func (file *httpFile) Stat() (fs.FileInfo, error) {
|
||||
fi, err := file.fp.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newFileInfo(fi, file.modtime), nil
|
||||
}
|
||||
|
||||
func (fs *filesystem) DenyAccessDirectory() {
|
||||
fs.denyDirectory = true
|
||||
}
|
||||
|
||||
func (fs *filesystem) SetPrefix(prefix string) {
|
||||
if prefix != "" {
|
||||
if prefix[0] != '/' {
|
||||
prefix = "/" + prefix
|
||||
}
|
||||
prefix = strings.TrimRight(prefix, "/")
|
||||
fs.prefix = prefix
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *filesystem) SetIndexFile(indexFile string) {
|
||||
fs.indexFile = indexFile
|
||||
}
|
||||
|
||||
func (fs *filesystem) Open(name string) (http.File, error) {
|
||||
var (
|
||||
needRetry bool
|
||||
)
|
||||
if name == "" || name == "/" {
|
||||
needRetry = true
|
||||
}
|
||||
if fs.prefix != "" {
|
||||
if !strings.HasPrefix(name, fs.prefix) {
|
||||
name = path.Join(fs.prefix, name)
|
||||
}
|
||||
}
|
||||
fp, err := fs.fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fs.denyDirectory {
|
||||
state, err := fp.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state.IsDir() {
|
||||
if needRetry {
|
||||
if fs.indexFile != "" {
|
||||
return fs.Open(path.Join(name, fs.indexFile))
|
||||
}
|
||||
}
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
}
|
||||
return &httpFile{fp: fp, modtime: fs.modtime}, nil
|
||||
}
|
||||
|
||||
func newFS(modtime time.Time, fs http.FileSystem) *filesystem {
|
||||
return &filesystem{
|
||||
fs: fs,
|
||||
modtime: modtime,
|
||||
}
|
||||
}
|
||||
|
||||
func newFileInfo(fi fs.FileInfo, modtime time.Time) *httpFileInfo {
|
||||
return &httpFileInfo{
|
||||
name: fi.Name(),
|
||||
size: fi.Size(),
|
||||
mode: fi.Mode(),
|
||||
isDir: fi.IsDir(),
|
||||
modtime: modtime,
|
||||
}
|
||||
}
|
||||
|
||||
func FileSystem(s fs.FS) http.FileSystem {
|
||||
return http.FS(s)
|
||||
}
|
|
@ -6,7 +6,9 @@ import (
|
|||
"net/http"
|
||||
"net/http/pprof"
|
||||
"net/url"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.nobla.cn/golang/aeus/metadata"
|
||||
"git.nobla.cn/golang/aeus/middleware"
|
||||
|
@ -25,6 +27,7 @@ type Server struct {
|
|||
engine *gin.Engine
|
||||
once sync.Once
|
||||
listener net.Listener
|
||||
fs *filesystem
|
||||
middlewares []middleware.Middleware
|
||||
}
|
||||
|
||||
|
@ -87,6 +90,26 @@ func (s *Server) Use(middlewares ...middleware.Middleware) {
|
|||
s.middlewares = append(s.middlewares, middlewares...)
|
||||
}
|
||||
|
||||
func (s *Server) Webroot(prefix string, fs http.FileSystem) {
|
||||
s.fs = newFS(time.Now(), fs)
|
||||
s.fs.SetPrefix(prefix)
|
||||
s.fs.DenyAccessDirectory()
|
||||
s.fs.SetIndexFile("/index.html")
|
||||
}
|
||||
|
||||
func (s *Server) notFoundHandle(ctx *gin.Context) {
|
||||
if s.fs != nil && ctx.Request.Method == http.MethodGet {
|
||||
uri := path.Clean(ctx.Request.URL.Path)
|
||||
if fp, err := s.fs.Open(uri); err == nil {
|
||||
http.ServeContent(ctx.Writer, ctx.Request, path.Base(uri), s.fs.modtime, fp)
|
||||
fp.Close()
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.JSON(http.StatusNotFound, newResponse(errors.NotFound, "Not Found", nil))
|
||||
}
|
||||
|
||||
func (s *Server) requestInterceptor() gin.HandlerFunc {
|
||||
return func(ginCtx *gin.Context) {
|
||||
ctx := ginCtx.Request.Context()
|
||||
|
@ -158,6 +181,7 @@ func (s *Server) Start(ctx context.Context) (err error) {
|
|||
if err = s.createListener(); err != nil {
|
||||
return
|
||||
}
|
||||
s.engine.NoRoute(s.notFoundHandle)
|
||||
s.opts.logger.Info(ctx, "http server listen on: %s", s.uri.Host)
|
||||
if s.opts.certFile != "" && s.opts.keyFile != "" {
|
||||
s.uri.Scheme = "https"
|
||||
|
|
Loading…
Reference in New Issue