chore (refactoring): migrate journal to pkg/journal

This commit is contained in:
MickaelK
2026-09-14 21:51:07 +10:00
parent a81dfea428
commit c16b06db9f
12 changed files with 116 additions and 76 deletions
+5 -2
View File
@@ -16,8 +16,10 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/env"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/mime"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
)
var (
@@ -54,7 +56,7 @@ func FileCat(ctx *App, res http.ResponseWriter, req *http.Request) {
MaxAge: -1,
Path: "/",
})
if CanRead(ctx) == false {
if permissions.CanRead(ctx) == false {
Log.Debug("cat::permission 'permission denied'")
SendErrorResult(res, ErrPermissionDenied)
return
@@ -308,4 +310,5 @@ func FileCat(ctx *App, res http.ResponseWriter, req *http.Request) {
io.CopyBuffer(res, file, *buf)
}
file.Close()
journal.Send(ctx, req, "cat", path)
}
+11 -8
View File
@@ -12,8 +12,10 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
)
type FileInfo struct {
@@ -26,8 +28,8 @@ type FileInfo struct {
}
func FileLs(ctx *App, res http.ResponseWriter, req *http.Request) {
if CanRead(ctx) == false {
if CanUpload(ctx) == false {
if permissions.CanRead(ctx) == false {
if permissions.CanUpload(ctx) == false {
Log.Debug("ls::permission 'permission denied'")
SendErrorResult(res, ErrPermissionDenied)
return
@@ -73,7 +75,7 @@ func FileLs(ctx *App, res http.ResponseWriter, req *http.Request) {
}
ctx.Context = context.WithValue(ctx.Context, "AUDIT", nil)
}
if CanEdit(ctx) == false {
if permissions.CanEdit(ctx) == false {
perms.CanCreateFile = NewBool(false)
perms.CanCreateDirectory = NewBool(false)
perms.CanRename = NewBool(false)
@@ -81,14 +83,14 @@ func FileLs(ctx *App, res http.ResponseWriter, req *http.Request) {
perms.CanDelete = NewBool(false)
perms.CanUpload = NewBool(false)
}
if CanUpload(ctx) == false {
if permissions.CanUpload(ctx) == false {
perms.CanCreateDirectory = NewBool(false)
perms.CanRename = NewBool(false)
perms.CanMove = NewBool(false)
perms.CanDelete = NewBool(false)
perms.CanUpload = NewBool(false)
}
if CanShare(ctx) == false {
if permissions.CanShare(ctx) == false {
perms.CanShare = NewBool(false)
}
@@ -135,7 +137,8 @@ func FileLs(ctx *App, res http.ResponseWriter, req *http.Request) {
res.Header().Set("Etag", etagValue)
if etagValue != "" && req.Header.Get("If-None-Match") == etagValue {
res.WriteHeader(http.StatusNotModified)
return
} else {
SendSuccessResultsWithMetadata(res, files, perms)
}
SendSuccessResultsWithMetadata(res, files, perms)
journal.Send(ctx, req, "ls", path)
}
+5 -3
View File
@@ -6,11 +6,13 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
)
func FileMkdir(ctx *App, res http.ResponseWriter, req *http.Request) {
if CanUpload(ctx) == false {
if permissions.CanUpload(ctx) == false {
Log.Debug("mkdir::permission 'permission denied'")
SendErrorResult(res, NewError("Permission denied", 403))
return
@@ -38,5 +40,5 @@ func FileMkdir(ctx *App, res http.ResponseWriter, req *http.Request) {
return
}
SendSuccessResult(res, nil)
EventWatch(ctx, req, "mkdir", path)
journal.Send(ctx, req, "mkdir", path)
}
+5 -3
View File
@@ -6,11 +6,13 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
)
func FileMv(ctx *App, res http.ResponseWriter, req *http.Request) {
if CanEdit(ctx) == false {
if permissions.CanEdit(ctx) == false {
Log.Debug("mv::permission 'permission denied'")
SendErrorResult(res, NewError("Permission denied", 403))
return
@@ -49,5 +51,5 @@ func FileMv(ctx *App, res http.ResponseWriter, req *http.Request) {
return
}
SendSuccessResult(res, nil)
EventWatch(ctx, req, "mv", from, to)
journal.Send(ctx, req, "mv", from, to)
}
+5 -3
View File
@@ -6,11 +6,13 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
)
func FileRm(ctx *App, res http.ResponseWriter, req *http.Request) {
if CanEdit(ctx) == false {
if permissions.CanEdit(ctx) == false {
Log.Debug("rm::permission 'permission denied'")
SendErrorResult(res, NewError("Permission denied", 403))
return
@@ -38,5 +40,5 @@ func FileRm(ctx *App, res http.ResponseWriter, req *http.Request) {
return
}
SendSuccessResult(res, nil)
EventWatch(ctx, req, "rm", path)
journal.Send(ctx, req, "rm", path)
}
+6 -4
View File
@@ -17,8 +17,10 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
)
func FileSave(ctx *App, res http.ResponseWriter, req *http.Request) {
@@ -39,8 +41,8 @@ func FileSave(ctx *App, res http.ResponseWriter, req *http.Request) {
return
}
if CanEdit(ctx) == false {
if CanUpload(ctx) == false {
if permissions.CanEdit(ctx) == false {
if permissions.CanUpload(ctx) == false {
Log.Debug("files::save action=permission_upload err=permission_denied")
SendErrorResult(res, ErrPermissionDenied)
return
@@ -88,7 +90,7 @@ func FileSave(ctx *App, res http.ResponseWriter, req *http.Request) {
SendErrorResult(res, ErrNotImplemented)
return
}
EventWatch(ctx, req, "save", path)
journal.Send(ctx, req, "save", path)
}
func handlerClassic(ctx *App, res http.ResponseWriter, req *http.Request, path string, h http.Header) {
+5 -3
View File
@@ -6,11 +6,13 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
)
func FileTouch(ctx *App, res http.ResponseWriter, req *http.Request) {
if CanUpload(ctx) == false {
if permissions.CanUpload(ctx) == false {
Log.Debug("touch::permission 'permission denied'")
SendErrorResult(res, NewError("Permission denied", 403))
return
@@ -38,5 +40,5 @@ func FileTouch(ctx *App, res http.ResponseWriter, req *http.Request) {
return
}
SendSuccessResult(res, nil)
EventWatch(ctx, req, "touch", path)
journal.Send(ctx, req, "touch", path)
}
+30
View File
@@ -0,0 +1,30 @@
package journal
import (
"time"
"strings"
"net/http"
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
)
func Send(ctx *App, req *http.Request, op string, path string, target ...string) {
t := time.Now()
go func() {
cVal := fileop{
Kind: "fs",
Operation: op,
Path: path,
Target: strings.Join(target, ","),
Time: t.UTC(),
StorageID: GenerateID(ctx.Session),
UserAgent: req.Header.Get("User-Agent"),
}
gate.L.Lock()
journal.Value = cVal
journal = journal.Next()
gate.Broadcast()
gate.L.Unlock()
}()
}
@@ -1,12 +1,10 @@
package files
package journal
import (
"container/ring"
"encoding/json"
"fmt"
"net/http"
"strings"
"sync"
"time"
. "github.com/mickael-kerjean/filestash/server/pkg/core"
@@ -14,30 +12,7 @@ import (
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
)
var (
journal = ring.New(5000)
gate = sync.NewCond(&sync.Mutex{})
)
func init() {
t := time.Now().UTC()
for i := 0; i < journal.Len(); i++ {
journal.Value = mutation{Time: t}
journal = journal.Next()
}
}
type mutation struct {
Operation string `json:"operation"`
Path string `json:"path"`
Target string `json:"target,omitempty"`
Echo bool `json:"echo"`
StorageID string `json:"-"`
Time time.Time `json:"-"`
UserAgent string `json:"-"`
}
func FileWatch(ctx *App, res http.ResponseWriter, req *http.Request) {
func Handler(ctx *App, res http.ResponseWriter, req *http.Request) {
flusher, ok := res.(http.Flusher)
if !ok {
SendErrorResult(res, NewError("streaming not supported", 500))
@@ -66,9 +41,9 @@ func FileWatch(ctx *App, res http.ResponseWriter, req *http.Request) {
} else if firstRun == false {
gate.Wait()
}
changes := make([]mutation, 0, 10)
changes := make([]fileop, 0, 10)
for i, len, curr := 0, journal.Len(), journal.Prev(); i < len; i, curr = i+1, curr.Prev() {
el := curr.Value.(mutation)
el := curr.Value.(fileop)
if el.Time.Before(checkpoint) || el.Time.Equal(checkpoint) {
break
}
@@ -84,28 +59,9 @@ func FileWatch(ctx *App, res http.ResponseWriter, req *http.Request) {
for i := len(changes); i > 0; i-- {
el := changes[i-1]
data, _ := json.Marshal(el)
fmt.Fprintf(res, "id: %s\nevent: mutation\ndata: %s\n\n", el.Time.Format(time.RFC3339Nano), data)
fmt.Fprintf(res, "id: %s\nevent: %s\ndata: %s\n\n", el.Time.Format(time.RFC3339Nano), el.Kind, data)
checkpoint = changes[0].Time
}
flusher.Flush()
}
}
func EventWatch(ctx *App, req *http.Request, op string, path string, target ...string) {
t := time.Now()
go func() {
cVal := mutation{
Operation: op,
Path: path,
Target: strings.Join(target, ","),
Time: t.UTC(),
StorageID: GenerateID(ctx.Session),
UserAgent: req.Header.Get("User-Agent"),
}
gate.L.Lock()
journal.Value = cVal
journal = journal.Next()
gate.Broadcast()
gate.L.Unlock()
}()
}
+20
View File
@@ -0,0 +1,20 @@
package journal
import (
"container/ring"
"sync"
"time"
)
var (
journal = ring.New(5000)
gate = sync.NewCond(&sync.Mutex{})
)
func init() {
t := time.Now().UTC()
for i := 0; i < journal.Len(); i++ {
journal.Value = fileop{Time: t}
journal = journal.Next()
}
}
+16
View File
@@ -0,0 +1,16 @@
package journal
import (
"time"
)
type fileop struct {
Kind string `json:"-"`
Operation string `json:"operation"`
Path string `json:"path"`
Target string `json:"target,omitempty"`
Echo bool `json:"echo"`
StorageID string `json:"-"`
Time time.Time `json:"-"`
UserAgent string `json:"-"`
}
+3 -1
View File
@@ -14,6 +14,7 @@ import (
"github.com/mickael-kerjean/filestash/server/pkg/admin"
"github.com/mickael-kerjean/filestash/server/pkg/files"
"github.com/mickael-kerjean/filestash/server/pkg/journal"
"github.com/mickael-kerjean/filestash/server/pkg/frontend"
"github.com/mickael-kerjean/filestash/server/pkg/session"
"github.com/mickael-kerjean/filestash/server/pkg/share"
@@ -71,7 +72,6 @@ func Build(r *mux.Router) {
router.HandleFunc("/rm", NewMiddlewareChain(files.FileRm, middlewares)).Methods("POST")
router.HandleFunc("/mkdir", NewMiddlewareChain(files.FileMkdir, middlewares)).Methods("POST")
router.HandleFunc("/touch", NewMiddlewareChain(files.FileTouch, middlewares)).Methods("POST")
router.HandleFunc("/watch", NewMiddlewareChain(files.FileWatch, middlewares)).Methods("GET")
middlewares = []Middleware{ApiHeaders, SecureHeaders, SecureOrigin, SessionStart, LoggedInOnly, PluginInjector}
router.HandleFunc("/search", NewMiddlewareChain(files.FileSearch, middlewares)).Methods("GET")
@@ -114,6 +114,8 @@ func Build(r *mux.Router) {
r.HandleFunc(WithBase("/favicon.ico"), NewMiddlewareChain(frontend.ServeFavicon, middlewares)).Methods("GET")
// Other endpoints
middlewares = []Middleware{ApiHeaders, SecureHeaders, SessionStart, LoggedInOnly}
r.HandleFunc(WithBase("/api/watch"), NewMiddlewareChain(journal.Handler, middlewares)).Methods("GET")
middlewares = []Middleware{ApiHeaders, PluginInjector, PublicCORS}
r.HandleFunc(WithBase("/report"), NewMiddlewareChain(frontend.ReportHandler, middlewares)).Methods("POST", "OPTIONS")
middlewares = []Middleware{IndexHeaders, SecureHeaders, PluginInjector}