mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-01 10:56:31 +08:00
improve (static): attempt at statically compile everything - revamp
This commit is contained in:
@ -234,7 +234,9 @@ func FileCat(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
if contentLength != -1 {
|
||||
header.Set("Content-Length", fmt.Sprintf("%d", contentLength))
|
||||
}
|
||||
if header.Get("Content-Type") == "" {
|
||||
header.Set("Content-Type", GetMimeType(req.URL.Query().Get("path")))
|
||||
}
|
||||
if header.Get("Content-Security-Policy") == "" {
|
||||
header.Set("Content-Security-Policy", "default-src 'none'; img-src 'self'; style-src 'unsafe-inline'")
|
||||
}
|
||||
|
||||
@ -1,40 +1,15 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_image_light"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_backblaze"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_dav"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_mysql"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_security_scanner"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_security_svg"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"os"
|
||||
"path/filepath"
|
||||
plg "plugin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ex, _ := os.Executable()
|
||||
pPath := filepath.Join(filepath.Dir(ex), PLUGIN_PATH)
|
||||
|
||||
file, err := os.Open(pPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err := file.Readdir(0)
|
||||
for i:=0; i < len(files); i++ {
|
||||
name := files[i].Name()
|
||||
if strings.HasPrefix(name, ".") {
|
||||
continue
|
||||
}
|
||||
Log.Debug("Load plugin: '%s'", name)
|
||||
p, err := plg.Open(pPath + "/" + name)
|
||||
if err != nil {
|
||||
Log.Warning("Can't load plugin: %s => %v", name, err)
|
||||
continue
|
||||
}
|
||||
fn, err := p.Lookup("Init")
|
||||
if err != nil {
|
||||
Log.Warning("Can't register plugin: %s => %v", name, err)
|
||||
continue
|
||||
}
|
||||
if obj, ok := fn.(func(config *Configuration)); ok {
|
||||
obj(&Config)
|
||||
}
|
||||
}
|
||||
Log.Debug("Plugin loader")
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package plg_backend_backblaze
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -38,7 +38,7 @@ type BackblazeError struct {
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func Init(config *Configuration) {
|
||||
func init() {
|
||||
Backend.Register("backblaze", Backblaze{})
|
||||
BackblazeCache = NewAppCache()
|
||||
cachePath := filepath.Join(GetCurrentDir(), BackblazeCachePath)
|
||||
|
||||
@ -1,10 +1,4 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
* Compilation
|
||||
* ===========
|
||||
* go build -buildmode=plugin -o dist/data/plugin/backend_dav.so server/plugin/plg_backend_dav/index.go
|
||||
*/
|
||||
package plg_backend_dav
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
@ -28,7 +22,7 @@ const (
|
||||
CALDAV string = "caldav"
|
||||
)
|
||||
|
||||
func Init(config *Configuration) {
|
||||
func init() {
|
||||
DavCache = NewAppCache(2, 1)
|
||||
Backend.Register(CARDDAV, Dav{})
|
||||
Backend.Register(CALDAV, Dav{})
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package plg_backend_mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
@ -20,7 +20,7 @@ type Mysql struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func Init(config *Configuration) {
|
||||
func init() {
|
||||
Backend.Register("mysql", Mysql{})
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
go build -buildmode=plugin -o ../../../dist/data/plugin/image.so index.go
|
||||
18
server/plugin/plg_image_light/deps/README.md
Normal file
18
server/plugin/plg_image_light/deps/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
plg_image_light rely on a few libraries for:
|
||||
- image transcoding: libtranscode.a: a library build on top of of libraw
|
||||
- image resizing: libresize.a: a library built on top of libvips
|
||||
|
||||
To create the libraries to be used by Filestash:
|
||||
./create_libtranscode.sh
|
||||
./create_libresize.sh
|
||||
|
||||
To test the libraries are working fine:
|
||||
```
|
||||
# libtranscode:
|
||||
gcc -Wall -c src/libtranscode_test.c
|
||||
gcc -o main_transcode.bin libtranscode_test.o -lm -lgomp -llcms2 -lstdc++ -L. -l:libtranscode.a
|
||||
|
||||
# libresize:
|
||||
gcc -Wall -c src/libresize_test.c `pkg-config --cflags glib-2.0`
|
||||
gcc -o main_resize.bin libresize_test.o -lm -lgmodule-2.0 -lgobject-2.0 -lglib-2.0 -L. -l:libresize.a
|
||||
```
|
||||
88
server/plugin/plg_image_light/deps/create_libresize.sh
Executable file
88
server/plugin/plg_image_light/deps/create_libresize.sh
Executable file
@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
# This script is run like this:
|
||||
# docker run --name debian -ti -v /home/:/home/ debian bash
|
||||
# cd /path/to/this/script
|
||||
# ./create_libresize.sh
|
||||
set -e
|
||||
|
||||
################################################
|
||||
# Tooling
|
||||
apt update
|
||||
apt install -y curl make gcc g++ xz-utils pkg-config python3-pip autoconf libtool unzip python-setuptools cmake git
|
||||
pip3 install --user meson ninja
|
||||
export PATH=~/.local/bin:$PATH
|
||||
|
||||
################################################
|
||||
# Stage 1: Get libvips and its dependencies + recompile for less headaches
|
||||
INITIAL_PATH=`pwd`
|
||||
mkdir -p /tmp/filestash/libresize/tmp
|
||||
cd /tmp/filestash/libresize
|
||||
apt install -y libvips-dev
|
||||
cd tmp
|
||||
curl -L -X GET https://github.com/libvips/libvips/releases/download/v8.7.0/vips-8.7.0.tar.gz > libvips.tar.gz
|
||||
tar -zxf libvips.tar.gz
|
||||
cd vips-8.7.0/
|
||||
./configure --enable-static --without-magick --without-lcms --without-OpenEXR --without-nifti --without-pdfium --without-rsvg --without-matio --without-libwebp --without-cfitsio --without-zlib --without-poppler --without-pangoft2 --enable-introspection=no --without-openslide
|
||||
make -j 8
|
||||
make install
|
||||
cd $INITIAL_PATH
|
||||
|
||||
################################################
|
||||
# Stage 2: Create our own library as a static build
|
||||
gcc -Wall -c src/libresize.c `pkg-config --cflags glib-2.0`
|
||||
ar rcs libresize.a libresize.o
|
||||
rm *.o
|
||||
|
||||
################################################
|
||||
# Stage 3: Gather and assemble all the bits and pieces together
|
||||
#ar x /tmp/libresize.a
|
||||
ar x /usr/local/lib/libvips.a
|
||||
|
||||
ar x /usr/lib/x86_64-linux-gnu/libz.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libbz2.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libjpeg.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libgif.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libdl.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libicui18n.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libthread.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libgsf-1.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libicuuc.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libicudata.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/liblzma.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libfreetype.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/liblqr-1.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libfftw3.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libfontconfig.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libXext.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libSM.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/liblXt.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libX11.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libgomp.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/liborc-0.4.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libltdl.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/librt.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libharfbuzz.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libgraphite2.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libexpat.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libgio-2.0.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libpng16.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libpixman-1.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libxcb.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libjbig.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libexif.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libxcb-shm
|
||||
ar x /usr/lib/x86_64-linux-gnu/libxcb-render
|
||||
ar x /usr/lib/x86_64-linux-gnu/libXrender
|
||||
ar x /usr/lib/x86_64-linux-gnu/libpcre.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libhdf5.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libresolv
|
||||
ar x /usr/lib/x86_64-linux-gnu/libXau
|
||||
ar x /usr/lib/x86_64-linux-gnu/libXdmcp
|
||||
ar x /usr/lib/x86_64-linux-gnu/libtiff.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libIlmThread.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libpoppler.a
|
||||
|
||||
ar rcs libresize.a *.o
|
||||
rm *.o *.ao
|
||||
29
server/plugin/plg_image_light/deps/create_libtranscode.sh
Executable file
29
server/plugin/plg_image_light/deps/create_libtranscode.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# This script is run like this:
|
||||
# docker run --name debian -ti -v /home/:/home/ debian bash
|
||||
# cd /path/to/this/script
|
||||
# ./create_libresize.sh
|
||||
set -e
|
||||
|
||||
################################################
|
||||
# Tooling
|
||||
apt update
|
||||
apt install -y curl make gcc g++ xz-utils pkg-config python3-pip autoconf libtool unzip python-setuptools cmake git
|
||||
pip3 install --user meson ninja
|
||||
export PATH=~/.local/bin:$PATH
|
||||
|
||||
################################################
|
||||
# Stage 1: Get libraw and its dependencies
|
||||
apt install libraw-dev
|
||||
|
||||
################################################
|
||||
# Stage 2: Create our own library as a static build
|
||||
gcc -Wall -c src/libtranscode.c
|
||||
|
||||
################################################
|
||||
# Stage 3: Gather and assemble all the bits and pieces together
|
||||
ar x /usr/lib/x86_64-linux-gnu/libraw.a
|
||||
ar x /usr/lib/x86_64-linux-gnu/libjpeg.a
|
||||
|
||||
ar rcs libtranscode.a *.o
|
||||
rm *.o *.ao
|
||||
@ -1,16 +1,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vips/vips.h>
|
||||
|
||||
int resizer_init(const int ncpu){
|
||||
if(VIPS_INIT("filestash")){
|
||||
return 1;
|
||||
}
|
||||
vips_concurrency_set(1);
|
||||
vips_cache_set_max(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resizer_process(const char *input, const char *output, int size, int crop, int quality, int exif){
|
||||
int image_resize(const char *filename, void **buf, size_t *len, int size, int crop, int quality, int exif){
|
||||
VipsImage *img;
|
||||
int err;
|
||||
|
||||
@ -21,7 +12,7 @@ int resizer_process(const char *input, const char *output, int size, int crop, i
|
||||
|
||||
if(crop == VIPS_INTERESTING_CENTRE){
|
||||
// Generate a thumbnails: a square picture crop in the center
|
||||
err = vips_thumbnail(input, &img, size,
|
||||
err = vips_thumbnail(filename, &img, size,
|
||||
"size", VIPS_SIZE_BOTH,
|
||||
"auto_rotate", TRUE,
|
||||
"crop", VIPS_INTERESTING_CENTRE,
|
||||
@ -29,7 +20,7 @@ int resizer_process(const char *input, const char *output, int size, int crop, i
|
||||
);
|
||||
}else{
|
||||
// normal resize of an image with libvips
|
||||
err = vips_thumbnail(input, &img, size,
|
||||
err = vips_thumbnail(filename, &img, size,
|
||||
"size", VIPS_SIZE_DOWN,
|
||||
"auto_rotate", TRUE,
|
||||
"crop", VIPS_INTERESTING_NONE,
|
||||
@ -40,7 +31,15 @@ int resizer_process(const char *input, const char *output, int size, int crop, i
|
||||
return err;
|
||||
}
|
||||
|
||||
err = vips_jpegsave(img, output, NULL);
|
||||
err = vips_jpegsave_buffer(img, buf, len, "Q", quality, "strip", exif, NULL);
|
||||
g_object_unref(img);
|
||||
return err;
|
||||
}
|
||||
|
||||
void __attribute__ ((constructor)) initLibrary(void) {
|
||||
VIPS_INIT("imagevips");
|
||||
vips_cache_set_max(0);
|
||||
}
|
||||
void __attribute__ ((destructor)) cleanUpLibrary(void) {
|
||||
vips_shutdown();
|
||||
}
|
||||
4
server/plugin/plg_image_light/deps/src/libresize.h
Normal file
4
server/plugin/plg_image_light/deps/src/libresize.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <stdio.h>
|
||||
#include <vips/vips.h>
|
||||
|
||||
int image_resize(const char *filename, void **buf, size_t *len, int size, int crop, int quality, int exif);
|
||||
29
server/plugin/plg_image_light/deps/src/libresize_test.c
Normal file
29
server/plugin/plg_image_light/deps/src/libresize_test.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "libresize.h"
|
||||
|
||||
double benchmark_image_resize(int n, const char*input);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(argc != 2){
|
||||
printf("missing argument: need a path to an image\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("=> benchmark %s: %.2fms\n", argv[1], benchmark_image_resize(20, argv[1]));
|
||||
}
|
||||
|
||||
double benchmark_image_resize(int n, const char* input) {
|
||||
double total = 0;
|
||||
void *buffer;
|
||||
size_t len;
|
||||
|
||||
int i = 0;
|
||||
for(i=0; i<n; i++){
|
||||
clock_t begin = clock();
|
||||
image_resize(input, &buffer, &len, 200, 1, 90, 0);
|
||||
clock_t end = clock();
|
||||
total += (double)(end - begin) / CLOCKS_PER_SEC * 1000;
|
||||
}
|
||||
return total / n;
|
||||
}
|
||||
@ -1,14 +1,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <libraw/libraw.h>
|
||||
|
||||
int save_thumbnail(const char *filename, libraw_data_t *raw){
|
||||
int err;
|
||||
err = libraw_dcraw_thumb_writer(raw, filename);
|
||||
libraw_close(raw);
|
||||
return err;
|
||||
}
|
||||
int save_thumbnail(const char *filename, libraw_data_t *raw);
|
||||
|
||||
int raw_process(const char* filename, int min_width){
|
||||
int image_transcode_compute(const char* filename, int min_width) {
|
||||
int err;
|
||||
libraw_data_t *raw;
|
||||
int thumbnail_working = 0;
|
||||
@ -65,3 +60,10 @@ int raw_process(const char* filename, int min_width){
|
||||
libraw_close(raw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int save_thumbnail(const char *filename, libraw_data_t *raw){
|
||||
int err;
|
||||
err = libraw_dcraw_thumb_writer(raw, filename);
|
||||
libraw_close(raw);
|
||||
return err;
|
||||
}
|
||||
4
server/plugin/plg_image_light/deps/src/libtranscode.h
Normal file
4
server/plugin/plg_image_light/deps/src/libtranscode.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <libraw/libraw.h>
|
||||
|
||||
int image_transcode_compute(const char* filename, int min_width);
|
||||
25
server/plugin/plg_image_light/deps/src/libtranscode_test.c
Normal file
25
server/plugin/plg_image_light/deps/src/libtranscode_test.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "libtranscode.h"
|
||||
|
||||
double benchmark_image_transcode(int n, const char*input);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(argc != 2){
|
||||
printf("missing argument: need a path to an image\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("=> benchmark %s: %.2fms\n", argv[1], benchmark_image_transcode(20, argv[1]));
|
||||
}
|
||||
|
||||
double benchmark_image_transcode(int n, const char* input) {
|
||||
double total = 0;
|
||||
int i = 0;
|
||||
for(i=0; i<n; i++){
|
||||
clock_t begin = clock();
|
||||
image_transcode_compute(input, 200);
|
||||
clock_t end = clock();
|
||||
total += (double)(end - begin) / CLOCKS_PER_SEC * 1000;
|
||||
}
|
||||
return total / n;
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
package main
|
||||
package plg_image_light
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/mickael-kerjean/filestash/server/plugin/plg_image_light/lib"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -12,17 +11,11 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
ImageCachePath = "data/cache/image/"
|
||||
)
|
||||
|
||||
var Config *Configuration
|
||||
|
||||
func Init(conf *Configuration) {
|
||||
Config = conf
|
||||
const ImageCachePath = "data/cache/image/"
|
||||
|
||||
func init() {
|
||||
plugin_enable := func() bool {
|
||||
return conf.Get("features.image.enable_image").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.image.enable_image").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
@ -36,7 +29,7 @@ func Init(conf *Configuration) {
|
||||
plugin_enable()
|
||||
|
||||
thumb_size := func() int {
|
||||
return conf.Get("features.image.thumbnail_size").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.image.thumbnail_size").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
@ -52,7 +45,7 @@ func Init(conf *Configuration) {
|
||||
thumb_size()
|
||||
|
||||
thumb_quality := func() int {
|
||||
return conf.Get("features.image.thumbnail_quality").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.image.thumbnail_quality").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
@ -68,7 +61,7 @@ func Init(conf *Configuration) {
|
||||
thumb_quality()
|
||||
|
||||
thumb_caching := func() int {
|
||||
return conf.Get("features.image.thumbnail_caching").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.image.thumbnail_caching").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
@ -84,7 +77,7 @@ func Init(conf *Configuration) {
|
||||
thumb_caching()
|
||||
|
||||
image_quality := func() int {
|
||||
return conf.Get("features.image.image_quality").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.image.image_quality").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
@ -100,7 +93,7 @@ func Init(conf *Configuration) {
|
||||
image_quality()
|
||||
|
||||
image_caching := func() int {
|
||||
return conf.Get("features.image.image_caching").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.image.image_caching").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
@ -139,9 +132,8 @@ func Init(conf *Configuration) {
|
||||
|
||||
/////////////////////////
|
||||
// Specify transformation
|
||||
transform := &lib.Transform{
|
||||
transform := &Transform{
|
||||
Input: GetAbsolutePath(ImageCachePath + "imagein_" + QuickString(10)),
|
||||
Output: GetAbsolutePath(ImageCachePath + "imageout_" + QuickString(10)),
|
||||
Size: thumb_size(),
|
||||
Crop: true,
|
||||
Quality: thumb_quality(),
|
||||
@ -163,7 +155,7 @@ func Init(conf *Configuration) {
|
||||
|
||||
/////////////////////////////
|
||||
// Insert file in the fs
|
||||
// => lower RAM usage while processing
|
||||
// => impedance matching with something usable by CGO
|
||||
file, err := os.OpenFile(transform.Input, os.O_WRONLY|os.O_CREATE, os.ModePerm)
|
||||
if err != nil {
|
||||
return reader, ErrFilesystemError
|
||||
@ -173,13 +165,12 @@ func Init(conf *Configuration) {
|
||||
reader.Close()
|
||||
defer func() {
|
||||
os.Remove(transform.Input)
|
||||
os.Remove(transform.Output)
|
||||
}()
|
||||
|
||||
/////////////////////////
|
||||
// Transcode RAW image
|
||||
if lib.IsRaw(mType) {
|
||||
if lib.ExtractPreview(transform) == nil {
|
||||
if IsRaw(mType) {
|
||||
if ExtractPreview(transform) == nil {
|
||||
mType = "image/jpeg"
|
||||
(*res).Header().Set("Content-Type", mType)
|
||||
} else {
|
||||
@ -188,11 +179,19 @@ func Init(conf *Configuration) {
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Final stage: resizing
|
||||
// final stage: resizing
|
||||
if mType != "image/jpeg" && mType != "image/png" && mType != "image/gif" && mType != "image/tiff" {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
return lib.CreateThumbnail(transform)
|
||||
return CreateThumbnail(transform)
|
||||
})
|
||||
}
|
||||
|
||||
type Transform struct {
|
||||
Input string
|
||||
Size int
|
||||
Crop bool
|
||||
Quality int
|
||||
Exif bool
|
||||
}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <libraw/libraw.h>
|
||||
|
||||
int raw_process(const char* filename, int min_width);
|
||||
@ -1,62 +0,0 @@
|
||||
package lib
|
||||
|
||||
// #cgo pkg-config: vips
|
||||
// #include <resizer.h>
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
LIBVIPS_INSTALLED = false
|
||||
VIPS_LOCK = &sync.Mutex{}
|
||||
)
|
||||
|
||||
type Transform struct {
|
||||
Input string
|
||||
Output string
|
||||
Size int
|
||||
Crop bool
|
||||
Quality int
|
||||
Exif bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
if C.resizer_init(C.int(runtime.NumCPU())) != 0 {
|
||||
Log.Warning("Can't load libvips")
|
||||
return
|
||||
}
|
||||
LIBVIPS_INSTALLED = true
|
||||
}
|
||||
|
||||
func CreateThumbnail(t *Transform) (io.ReadCloser, error) {
|
||||
if LIBVIPS_INSTALLED == false {
|
||||
return nil, NewError("Libvips not installed", 501)
|
||||
}
|
||||
filenameInput := C.CString(t.Input)
|
||||
defer C.free(unsafe.Pointer(filenameInput))
|
||||
|
||||
filenameOutput := C.CString(t.Output)
|
||||
defer C.free(unsafe.Pointer(filenameOutput))
|
||||
|
||||
VIPS_LOCK.Lock()
|
||||
if C.resizer_process(filenameInput, filenameOutput, C.int(t.Size), boolToCInt(t.Crop), C.int(t.Quality), boolToCInt(t.Exif)) != 0 {
|
||||
return nil, NewError("", 500)
|
||||
}
|
||||
VIPS_LOCK.Unlock()
|
||||
return os.OpenFile(t.Output, os.O_RDONLY, os.ModePerm)
|
||||
}
|
||||
|
||||
func boolToCInt(val bool) C.int {
|
||||
if val == false {
|
||||
return C.int(0)
|
||||
}
|
||||
return C.int(1)
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <vips/vips.h>
|
||||
|
||||
int resizer_init(const int ncpu);
|
||||
|
||||
int resizer_process(const char *input, const char *output, int size, int crop, int quality, int exif);
|
||||
39
server/plugin/plg_image_light/lib_resize.go
Normal file
39
server/plugin/plg_image_light/lib_resize.go
Normal file
@ -0,0 +1,39 @@
|
||||
package plg_image_light
|
||||
// #cgo pkg-config:glib-2.0
|
||||
// #cgo CFLAGS: -I./deps/src
|
||||
// #cgo LDFLAGS: -lm -lgmodule-2.0 -lgobject-2.0 -lglib-2.0 -ldl -L./deps -l:libresize.a
|
||||
// #include "libresize.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var VIPS_LOCK = semaphore.NewWeighted(int64(10))
|
||||
|
||||
func CreateThumbnail(t *Transform) (io.ReadCloser, error) {
|
||||
VIPS_LOCK.Acquire(context.Background(), 1)
|
||||
defer VIPS_LOCK.Release(1)
|
||||
|
||||
filename := C.CString(t.Input)
|
||||
defer C.free(unsafe.Pointer(filename))
|
||||
var buffer unsafe.Pointer
|
||||
len := C.size_t(0)
|
||||
if C.image_resize(filename, &buffer, &len, C.int(t.Size), boolToCInt(t.Crop), C.int(t.Quality), boolToCInt(t.Exif)) != 0 {
|
||||
return nil, NewError("", 500)
|
||||
}
|
||||
buf := C.GoBytes(buffer, C.int(len))
|
||||
C.g_free(C.gpointer(buffer))
|
||||
return NewReadCloserFromBytes(buf), nil
|
||||
}
|
||||
|
||||
func boolToCInt(val bool) C.int {
|
||||
if val == false {
|
||||
return C.int(0)
|
||||
}
|
||||
return C.int(1)
|
||||
}
|
||||
@ -1,18 +1,17 @@
|
||||
package lib
|
||||
|
||||
// #cgo pkg-config: libraw
|
||||
// #include <raw.h>
|
||||
// #include <stdlib.h>
|
||||
package plg_image_light
|
||||
// #cgo CFLAGS: -I./deps/src
|
||||
// #cgo LDFLAGS: -lm -lgomp -llcms2 -lstdc++ -L./deps -l:libtranscode.a
|
||||
// #include "libtranscode.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/sync/semaphore"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"math/rand"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const LIBRAW_MEMORY_ERROR = -1
|
||||
var LIBRAW_LOCK = semaphore.NewWeighted(int64(5))
|
||||
|
||||
func IsRaw(mType string) bool {
|
||||
switch mType {
|
||||
@ -46,20 +45,14 @@ func IsRaw(mType string) bool {
|
||||
}
|
||||
|
||||
func ExtractPreview(t *Transform) error {
|
||||
filename := C.CString(t.Input)
|
||||
err := C.raw_process(filename, C.int(t.Size))
|
||||
if err == LIBRAW_MEMORY_ERROR {
|
||||
// libraw acts weird sometimes and I couldn't
|
||||
// find a way to increase its available memory :(
|
||||
r := rand.Intn(2000) + 500
|
||||
time.Sleep(time.Duration(r) * time.Millisecond)
|
||||
C.free(unsafe.Pointer(filename))
|
||||
return ExtractPreview(t)
|
||||
} else if err != 0 {
|
||||
C.free(unsafe.Pointer(filename))
|
||||
return NewError("", 500)
|
||||
}
|
||||
LIBRAW_LOCK.Acquire(context.Background(), 1)
|
||||
defer LIBRAW_LOCK.Release(1)
|
||||
|
||||
C.free(unsafe.Pointer(filename))
|
||||
filename := C.CString(t.Input)
|
||||
defer C.free(unsafe.Pointer(filename))
|
||||
|
||||
if err := C.image_transcode_compute(filename, C.int(t.Size)); err != 0 {
|
||||
return ErrNotValid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
// This plugins attempt to crash http scanners used by script kiddies
|
||||
package main
|
||||
package plg_security_scanner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -16,8 +15,8 @@ var (
|
||||
billionsOfLol *bytes.Buffer
|
||||
)
|
||||
|
||||
func Init(config *Configuration) {
|
||||
if plugin_enable := config.Get("features.protection.enable").Schema(func(f *FormElement) *FormElement{
|
||||
func init() {
|
||||
if plugin_enable := Config.Get("features.protection.enable").Schema(func(f *FormElement) *FormElement{
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package plg_security_svg
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
@ -8,9 +8,9 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func Init(conf *Configuration) {
|
||||
func init() {
|
||||
disable_svg := func() bool {
|
||||
return conf.Get("features.protection.disable_svg").Schema(func(f *FormElement) *FormElement {
|
||||
return Config.Get("features.protection.disable_svg").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user