add http filesystem
This commit is contained in:
parent
3857968441
commit
5707adb88c
|
@ -104,7 +104,9 @@ func Geerate(app *types.Applicetion) (err error) {
|
||||||
}
|
}
|
||||||
writer.Reset()
|
writer.Reset()
|
||||||
}
|
}
|
||||||
|
if err = writeFile(shortName+".go", []byte("package "+shortName)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = scanDir(protoDir, "third_party", func(filename string) error {
|
err = scanDir(protoDir, "third_party", func(filename string) error {
|
||||||
if fp, openerr := protoDir.Open(filename); openerr != nil {
|
if fp, openerr := protoDir.Open(filename); openerr != nil {
|
||||||
return openerr
|
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"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.nobla.cn/golang/aeus/metadata"
|
"git.nobla.cn/golang/aeus/metadata"
|
||||||
"git.nobla.cn/golang/aeus/middleware"
|
"git.nobla.cn/golang/aeus/middleware"
|
||||||
|
@ -25,6 +27,7 @@ type Server struct {
|
||||||
engine *gin.Engine
|
engine *gin.Engine
|
||||||
once sync.Once
|
once sync.Once
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
|
fs *filesystem
|
||||||
middlewares []middleware.Middleware
|
middlewares []middleware.Middleware
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +90,26 @@ func (s *Server) Use(middlewares ...middleware.Middleware) {
|
||||||
s.middlewares = append(s.middlewares, middlewares...)
|
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 {
|
func (s *Server) requestInterceptor() gin.HandlerFunc {
|
||||||
return func(ginCtx *gin.Context) {
|
return func(ginCtx *gin.Context) {
|
||||||
ctx := ginCtx.Request.Context()
|
ctx := ginCtx.Request.Context()
|
||||||
|
@ -158,6 +181,7 @@ func (s *Server) Start(ctx context.Context) (err error) {
|
||||||
if err = s.createListener(); err != nil {
|
if err = s.createListener(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s.engine.NoRoute(s.notFoundHandle)
|
||||||
s.opts.logger.Info(ctx, "http server listen on: %s", s.uri.Host)
|
s.opts.logger.Info(ctx, "http server listen on: %s", s.uri.Host)
|
||||||
if s.opts.certFile != "" && s.opts.keyFile != "" {
|
if s.opts.certFile != "" && s.opts.keyFile != "" {
|
||||||
s.uri.Scheme = "https"
|
s.uri.Scheme = "https"
|
||||||
|
|
Loading…
Reference in New Issue