mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-01 10:56:31 +08:00
fix (plugin): extend API for plugins
This commit is contained in:
@ -148,7 +148,12 @@ func (this Config) Interface() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this Config) save() {
|
func (this Config) save() {
|
||||||
|
if this.path == nil {
|
||||||
|
Log.Error("Config error")
|
||||||
|
return
|
||||||
|
}
|
||||||
if gjson.Valid(this.json) == false {
|
if gjson.Valid(this.json) == false {
|
||||||
|
Log.Error("Config error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f, err := os.OpenFile(configPath, os.O_WRONLY|os.O_CREATE, os.ModePerm); err == nil {
|
if f, err := os.OpenFile(configPath, os.O_WRONLY|os.O_CREATE, os.ModePerm); err == nil {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package common
|
|||||||
const (
|
const (
|
||||||
APP_VERSION = "v0.3"
|
APP_VERSION = "v0.3"
|
||||||
CONFIG_PATH = "data/config/"
|
CONFIG_PATH = "data/config/"
|
||||||
|
PLUGIN_PATH = "data/plugin/"
|
||||||
COOKIE_NAME_AUTH = "auth"
|
COOKIE_NAME_AUTH = "auth"
|
||||||
COOKIE_NAME_PROOF = "proof"
|
COOKIE_NAME_PROOF = "proof"
|
||||||
COOKIE_PATH = "/api/"
|
COOKIE_PATH = "/api/"
|
||||||
|
|||||||
21
server/common/debug.go
Normal file
21
server/common/debug.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrintMemUsage() {
|
||||||
|
var m runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&m)
|
||||||
|
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
|
||||||
|
fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
|
||||||
|
fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
|
||||||
|
fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
|
||||||
|
fmt.Printf("\tObjects = %d", m.HeapObjects)
|
||||||
|
fmt.Printf("\tNumGC = %v\n", m.NumGC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bToMb(b uint64) uint64 {
|
||||||
|
return b / 1024 / 1024
|
||||||
|
}
|
||||||
@ -1,11 +1,25 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
type Plugin struct {
|
import (
|
||||||
Type string
|
"io"
|
||||||
Call interface{}
|
"net/http"
|
||||||
Priority int
|
)
|
||||||
|
|
||||||
|
type Register struct{}
|
||||||
|
type Get struct{}
|
||||||
|
|
||||||
|
var Hooks = struct {
|
||||||
|
Get Get
|
||||||
|
Register Register
|
||||||
|
}{
|
||||||
|
Get: Get{},
|
||||||
|
Register: Register{},
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
var process_file_content_before_send []func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error)
|
||||||
PROCESS_FILE_CONTENT_BEFORE_SEND = "PROCESS_FILE_CONTENT_BEFORE_SEND"
|
func (this Register) ProcessFileContentBeforeSend(fn func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error)) {
|
||||||
)
|
process_file_content_before_send = append(process_file_content_before_send, fn)
|
||||||
|
}
|
||||||
|
func (this Get) ProcessFileContentBeforeSend() []func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error) {
|
||||||
|
return process_file_content_before_send
|
||||||
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package ctrl
|
|||||||
import (
|
import (
|
||||||
. "github.com/mickael-kerjean/nuage/server/common"
|
. "github.com/mickael-kerjean/nuage/server/common"
|
||||||
"github.com/mickael-kerjean/nuage/server/model"
|
"github.com/mickael-kerjean/nuage/server/model"
|
||||||
"github.com/mickael-kerjean/nuage/server/plugin"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -114,10 +113,7 @@ func FileCat(ctx App, res http.ResponseWriter, req *http.Request) {
|
|||||||
mType := GetMimeType(req.URL.Query().Get("path"))
|
mType := GetMimeType(req.URL.Query().Get("path"))
|
||||||
res.Header().Set("Content-Type", mType)
|
res.Header().Set("Content-Type", mType)
|
||||||
|
|
||||||
for _, obj := range plugin.ProcessFileContentBeforeSend() {
|
for _, obj := range Hooks.Get.ProcessFileContentBeforeSend() {
|
||||||
if obj == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if file, err = obj(file, &ctx, &res, req); err != nil {
|
if file, err = obj(file, &ctx, &res, req); err != nil {
|
||||||
SendErrorResult(res, err)
|
SendErrorResult(res, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build -buildmode=plugin -o ../../../dist/data/plugin/example.so index.go
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/mickael-kerjean/nuage/server/common"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Register(config *Config) []Plugin {
|
|
||||||
config.Get("plugins.example.foo").Default("bar")
|
|
||||||
|
|
||||||
return []Plugin{
|
|
||||||
{
|
|
||||||
Type: PROCESS_FILE_CONTENT_BEFORE_SEND, // where to hook our plugin in the request lifecycle
|
|
||||||
Call: hook, // actual function we trigger
|
|
||||||
Priority: 5, // determine execution order whilst multiple plugin type
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hook(file io.Reader, ctx *App, res *http.ResponseWriter, req *http.Request) (io.Reader, error){
|
|
||||||
Log.Debug("Plugin::Example")
|
|
||||||
Log.Debug("Conf: plugins.example.foo = '%s'", ctx.Config.Get("plugins.example.foo").String())
|
|
||||||
return file, nil
|
|
||||||
}
|
|
||||||
43
server/plugin/image_heavy/index.go
Normal file
43
server/plugin/image_heavy/index.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
. "github.com/mickael-kerjean/nuage/server/common"
|
||||||
|
"github.com/nfnt/resize"
|
||||||
|
"image/jpeg"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init(config *Config) {
|
||||||
|
plugin_enable := config.Get("transcoder.image.enable").Default(true).Bool()
|
||||||
|
plugin_thumbsize := uint(config.Get("transcoder.image.thumbnail_size").Default(300).Int())
|
||||||
|
|
||||||
|
Hooks.Register.ProcessFileContentBeforeSend(func(reader io.Reader, ctx *App, res *http.ResponseWriter, req *http.Request) (io.Reader, error){
|
||||||
|
if plugin_enable == false {
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
query := req.URL.Query()
|
||||||
|
mType := GetMimeType(query.Get("path"))
|
||||||
|
|
||||||
|
if mType != "image/jpeg" {
|
||||||
|
return reader, nil
|
||||||
|
} else if query.Get("thumbnail") != "true" {
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
(*res).Header().Set("Cache-Control", "max-age=3600")
|
||||||
|
img, err := jpeg.Decode(reader)
|
||||||
|
if err != nil {
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
if obj, ok := reader.(interface{ Close() error }); ok {
|
||||||
|
obj.Close()
|
||||||
|
}
|
||||||
|
img = resize.Resize(plugin_thumbsize, 0, img, resize.Lanczos3)
|
||||||
|
out := bytes.NewBufferString("")
|
||||||
|
jpeg.Encode(out, img, &jpeg.Options{50})
|
||||||
|
return out, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -15,27 +15,17 @@ const (
|
|||||||
ImageCachePath = "data/cache/image/"
|
ImageCachePath = "data/cache/image/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Register(conf *Config) []Plugin {
|
func Init(conf *Config) {
|
||||||
conf.Get("plugins.transcoder.image.enable").Default(true)
|
plugin_enable := conf.Get("transcoder.image.enable").Default(true).Bool()
|
||||||
|
|
||||||
cachePath := filepath.Join(GetCurrentDir(), ImageCachePath)
|
cachePath := filepath.Join(GetCurrentDir(), ImageCachePath)
|
||||||
os.RemoveAll(cachePath)
|
os.RemoveAll(cachePath)
|
||||||
os.MkdirAll(cachePath, os.ModePerm)
|
os.MkdirAll(cachePath, os.ModePerm)
|
||||||
|
|
||||||
return []Plugin{
|
Hooks.Register.ProcessFileContentBeforeSend(func (reader io.Reader, ctx *App, res *http.ResponseWriter, req *http.Request) (io.Reader, error){
|
||||||
{
|
if plugin_enable == false {
|
||||||
Type: PROCESS_FILE_CONTENT_BEFORE_SEND, // where to hook our plugin in the request lifecycle
|
|
||||||
Call: hook, // actual function we trigger
|
|
||||||
Priority: -1, // last plugin to execute
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hook(reader io.Reader, ctx *App, res *http.ResponseWriter, req *http.Request) (io.Reader, error){
|
|
||||||
if ctx.Config.Get("plugins.transcoder.image.enable").Bool() == false {
|
|
||||||
return reader, nil
|
return reader, nil
|
||||||
}
|
}
|
||||||
Log.Debug("Plugin::Image")
|
|
||||||
|
|
||||||
query := req.URL.Query()
|
query := req.URL.Query()
|
||||||
mType := GetMimeType(query.Get("path"))
|
mType := GetMimeType(query.Get("path"))
|
||||||
@ -106,4 +96,5 @@ func hook(reader io.Reader, ctx *App, res *http.ResponseWriter, req *http.Reques
|
|||||||
return reader, nil
|
return reader, nil
|
||||||
}
|
}
|
||||||
return lib.CreateThumbnail(transform)
|
return lib.CreateThumbnail(transform)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,16 @@
|
|||||||
package plugin
|
package plugin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
. "github.com/mickael-kerjean/nuage/server/common"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
plg "plugin"
|
plg "plugin"
|
||||||
. "github.com/mickael-kerjean/nuage/server/common"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"net/http"
|
|
||||||
"io"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const PluginPath = "data/plugin/"
|
|
||||||
|
|
||||||
var plugins = make(map[string][]Plugin)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ex, _ := os.Executable()
|
ex, _ := os.Executable()
|
||||||
pPath := filepath.Join(filepath.Dir(ex), PluginPath)
|
pPath := filepath.Join(filepath.Dir(ex), PLUGIN_PATH)
|
||||||
|
|
||||||
file, err := os.Open(pPath)
|
file, err := os.Open(pPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -28,7 +21,7 @@ func init() {
|
|||||||
c := NewConfig()
|
c := NewConfig()
|
||||||
for i:=0; i < len(files); i++ {
|
for i:=0; i < len(files); i++ {
|
||||||
name := files[i].Name()
|
name := files[i].Name()
|
||||||
if strings.HasPrefix(name, ".") == true {
|
if strings.HasPrefix(name, ".") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p, err := plg.Open(pPath + "/" + name)
|
p, err := plg.Open(pPath + "/" + name)
|
||||||
@ -36,32 +29,13 @@ func init() {
|
|||||||
Log.Warning("Can't load plugin: %s => %v", name, err)
|
Log.Warning("Can't load plugin: %s => %v", name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
fn, err := p.Lookup("Init")
|
||||||
f, err := p.Lookup("Register")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Warning("Can't register plugin: %s => %v", name, err)
|
Log.Warning("Can't register plugin: %s => %v", name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if obj, ok := f.(func(config *Config) []Plugin); ok {
|
if obj, ok := fn.(func(config *Config)); ok {
|
||||||
for _, plg := range obj(c) {
|
obj(c)
|
||||||
plugins[plg.Type] = append(plugins[plg.Type], plg)
|
|
||||||
sort.SliceStable(plugins[plg.Type], func(i, j int) bool {
|
|
||||||
return plugins[plg.Type][i].Priority > plugins[plg.Type][j].Priority
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func ProcessFileContentBeforeSend() []func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error) {
|
|
||||||
fs := plugins[PROCESS_FILE_CONTENT_BEFORE_SEND]
|
|
||||||
ret := make([]func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error), len(fs))
|
|
||||||
for _, p := range fs {
|
|
||||||
if f, ok := p.Call.(func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error)); ok {
|
|
||||||
ret = append(ret, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user