mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-11-01 02:43:35 +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() { | ||||
| 	if this.path == nil { | ||||
| 		Log.Error("Config error") | ||||
| 		return | ||||
| 	} | ||||
| 	if gjson.Valid(this.json) == false { | ||||
| 		Log.Error("Config error") | ||||
| 		return | ||||
| 	} | ||||
| 	if f, err := os.OpenFile(configPath, os.O_WRONLY|os.O_CREATE, os.ModePerm); err == nil { | ||||
|  | ||||
| @ -3,6 +3,7 @@ package common | ||||
| const ( | ||||
| 	APP_VERSION = "v0.3" | ||||
| 	CONFIG_PATH = "data/config/" | ||||
| 	PLUGIN_PATH = "data/plugin/" | ||||
| 	COOKIE_NAME_AUTH = "auth" | ||||
| 	COOKIE_NAME_PROOF = "proof" | ||||
| 	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 | ||||
|  | ||||
| type Plugin struct { | ||||
| 	Type     string | ||||
| 	Call     interface{} | ||||
| 	Priority int | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| type Register struct{} | ||||
| type Get struct{} | ||||
|  | ||||
| var Hooks = struct { | ||||
| 	Get Get | ||||
| 	Register Register | ||||
| }{ | ||||
| 	Get: Get{}, | ||||
| 	Register: Register{}, | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	PROCESS_FILE_CONTENT_BEFORE_SEND = "PROCESS_FILE_CONTENT_BEFORE_SEND" | ||||
| ) | ||||
| var process_file_content_before_send []func(io.Reader, *App, *http.ResponseWriter, *http.Request) (io.Reader, error) | ||||
| 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 ( | ||||
| 	. "github.com/mickael-kerjean/nuage/server/common" | ||||
| 	"github.com/mickael-kerjean/nuage/server/model" | ||||
| 	"github.com/mickael-kerjean/nuage/server/plugin" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"path/filepath" | ||||
| @ -114,10 +113,7 @@ func FileCat(ctx App, res http.ResponseWriter, req *http.Request) { | ||||
| 	mType := GetMimeType(req.URL.Query().Get("path")) | ||||
| 	res.Header().Set("Content-Type", mType) | ||||
|  | ||||
| 	for _, obj := range plugin.ProcessFileContentBeforeSend() { | ||||
| 		if obj == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 	for _, obj := range Hooks.Get.ProcessFileContentBeforeSend() { | ||||
| 		if file, err = obj(file, &ctx, &res, req); err != nil { | ||||
| 			SendErrorResult(res, err) | ||||
| 			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/" | ||||
| ) | ||||
|  | ||||
| func Register(conf *Config) []Plugin { | ||||
| 	conf.Get("plugins.transcoder.image.enable").Default(true) | ||||
| func Init(conf *Config) { | ||||
| 	plugin_enable := conf.Get("transcoder.image.enable").Default(true).Bool() | ||||
|  | ||||
| 	cachePath := filepath.Join(GetCurrentDir(), ImageCachePath) | ||||
| 	os.RemoveAll(cachePath) | ||||
| 	os.MkdirAll(cachePath, os.ModePerm) | ||||
|  | ||||
| 	return []Plugin{ | ||||
| 		{ | ||||
| 			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 { | ||||
| 	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 | ||||
| 		} | ||||
| 	Log.Debug("Plugin::Image") | ||||
|  | ||||
| 		query := req.URL.Query() | ||||
| 		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 lib.CreateThumbnail(transform) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| @ -1,23 +1,16 @@ | ||||
| package plugin | ||||
|  | ||||
| import ( | ||||
| 	. "github.com/mickael-kerjean/nuage/server/common" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	plg "plugin" | ||||
| 	. "github.com/mickael-kerjean/nuage/server/common" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"net/http" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| const PluginPath = "data/plugin/" | ||||
|  | ||||
| var plugins = make(map[string][]Plugin) | ||||
|  | ||||
| func init() { | ||||
| 	ex, _ := os.Executable() | ||||
| 	pPath := filepath.Join(filepath.Dir(ex), PluginPath) | ||||
| 	pPath := filepath.Join(filepath.Dir(ex), PLUGIN_PATH) | ||||
|  | ||||
| 	file, err := os.Open(pPath) | ||||
| 	if err != nil { | ||||
| @ -28,7 +21,7 @@ func init() { | ||||
| 	c := NewConfig() | ||||
| 	for i:=0; i < len(files); i++ { | ||||
| 		name := files[i].Name() | ||||
| 		if strings.HasPrefix(name, ".") == true { | ||||
| 		if strings.HasPrefix(name, ".") { | ||||
| 			continue | ||||
| 		} | ||||
| 		p, err := plg.Open(pPath + "/" + name) | ||||
| @ -36,32 +29,13 @@ func init() { | ||||
| 			Log.Warning("Can't load plugin: %s => %v", name, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		 | ||||
| 		f, err := p.Lookup("Register") | ||||
| 		fn, err := p.Lookup("Init") | ||||
| 		if err != nil { | ||||
| 			Log.Warning("Can't register plugin: %s => %v", name, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if obj, ok := f.(func(config *Config) []Plugin); ok { | ||||
| 			for _, plg := range 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 | ||||
| 				}) | ||||
| 			} | ||||
| 		if obj, ok := fn.(func(config *Config)); ok { | ||||
| 			obj(c) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| 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
	 Mickael KERJEAN
					Mickael KERJEAN