add http filesystem

This commit is contained in:
Yavolte 2025-06-11 10:17:31 +08:00
parent 3857968441
commit 76197bce6f
3 changed files with 180 additions and 1 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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"