repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

commit
ca79cbc
parent
eeae06c
author
Antonio Mika
date
2022-08-31 21:24:07 +0000 UTC
Work on optimizing imgs.sh
8 files changed,  +122, -79
M go.mod
M go.sum
M Makefile
+1, -1
1@@ -18,7 +18,7 @@ css:
2 .PHONY: css
3 
4 lint:
5-	docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:latest golangci-lint run -E goimports -E godot
6+	docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:latest bash -c 'apt-get update > /dev/null 2>&1 && apt-get install -y libwebp-dev > /dev/null 2>&1; golangci-lint run -E goimports -E godot'
7 .PHONY: lint
8 
9 bp-setup:
M filehandlers/imgs/handler.go
+1, -1
1@@ -15,7 +15,7 @@ import (
2 	"git.sr.ht/~erock/pico/wish/cms/util"
3 	"git.sr.ht/~erock/pico/wish/send/utils"
4 	"github.com/gliderlabs/ssh"
5-	"github.com/scottleedavis/go-exif-remove"
6+	exifremove "github.com/scottleedavis/go-exif-remove"
7 	"golang.org/x/exp/slices"
8 )
9 
M filehandlers/imgs/img.go
+3, -1
 1@@ -1,7 +1,9 @@
 2 package uploadimgs
 3 
 4 import (
 5+	"bytes"
 6 	"fmt"
 7+	"io"
 8 	"strings"
 9 
10 	"git.sr.ht/~erock/pico/db"
11@@ -40,7 +42,7 @@ func (h *UploadImgHandler) metaImg(data *PostMetaData) error {
12 	if err != nil {
13 		return err
14 	}
15-	fname, err := h.Storage.PutFile(bucket, data.Filename, []byte(data.Text))
16+	fname, err := h.Storage.PutFile(bucket, data.Filename, io.NopCloser(bytes.NewReader([]byte(data.Text))))
17 	if err != nil {
18 		return err
19 	}
M go.mod
+19, -14
 1@@ -7,7 +7,7 @@ go 1.19
 2 
 3 require (
 4 	github.com/alecthomas/chroma v0.10.0
 5-	github.com/antoniomika/go-rsync-receiver v0.0.0-20220825041817-0387edc9afb7
 6+	github.com/antoniomika/go-rsync-receiver v0.0.0-20220825051444-e2df2a87b439
 7 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
 8 	github.com/charmbracelet/bubbles v0.13.0
 9 	github.com/charmbracelet/bubbletea v0.22.1
10@@ -20,7 +20,7 @@ require (
11 	github.com/lib/pq v1.10.6
12 	github.com/matryer/is v1.4.0
13 	github.com/microcosm-cc/bluemonday v1.0.19
14-	github.com/minio/minio-go/v7 v7.0.34
15+	github.com/minio/minio-go/v7 v7.0.35
16 	github.com/muesli/reflow v0.3.0
17 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
18 	github.com/pkg/sftp v1.13.5
19@@ -29,8 +29,8 @@ require (
20 	github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
21 	github.com/yuin/goldmark-meta v1.1.0
22 	go.uber.org/zap v1.23.0
23-	golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503
24-	golang.org/x/exp v0.0.0-20220823124025-807a23277127
25+	golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
26+	golang.org/x/exp v0.0.0-20220827204233-334a2380cb91
27 )
28 
29 require (
30@@ -44,20 +44,25 @@ require (
31 	github.com/charmbracelet/keygen v0.3.0 // indirect
32 	github.com/containerd/console v1.0.3 // indirect
33 	github.com/dlclark/regexp2 v1.7.0 // indirect
34-	github.com/dsoprea/go-exif v0.0.0-20190901173045-3ce78807c90f // indirect
35-	github.com/dsoprea/go-jpeg-image-structure v0.0.0-20190422055009-d6f9ba25cf48 // indirect
36-	github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 // indirect
37-	github.com/dsoprea/go-png-image-structure v0.0.0-20190624104353-c9b28dcdc5c8 // indirect
38+	github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b // indirect
39+	github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b // indirect
40+	github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 // indirect
41+	github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836 // indirect
42+	github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
43+	github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect
44+	github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect
45+	github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e // indirect
46 	github.com/dustin/go-humanize v1.0.0 // indirect
47-	github.com/go-errors/errors v1.0.1 // indirect
48-	github.com/golang/geo v0.0.0-20190812012225-f41920e961ce // indirect
49+	github.com/go-errors/errors v1.4.2 // indirect
50+	github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
51+	github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
52 	github.com/golang/protobuf v1.5.2 // indirect
53 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
54 	github.com/google/uuid v1.3.0 // indirect
55 	github.com/gorilla/css v1.0.0 // indirect
56 	github.com/json-iterator/go v1.1.12 // indirect
57 	github.com/klauspost/compress v1.15.9 // indirect
58-	github.com/klauspost/cpuid/v2 v2.1.0 // indirect
59+	github.com/klauspost/cpuid/v2 v2.1.1 // indirect
60 	github.com/kr/fs v0.1.0 // indirect
61 	github.com/kr/pretty v0.3.0 // indirect
62 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
63@@ -83,11 +88,11 @@ require (
64 	github.com/sirupsen/logrus v1.9.0 // indirect
65 	go.uber.org/atomic v1.10.0 // indirect
66 	go.uber.org/multierr v1.8.0 // indirect
67-	golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c // indirect
68-	golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 // indirect
69+	golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect
70+	golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
71 	golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
72 	golang.org/x/text v0.3.7 // indirect
73 	google.golang.org/protobuf v1.28.1 // indirect
74-	gopkg.in/ini.v1 v1.66.6 // indirect
75+	gopkg.in/ini.v1 v1.67.0 // indirect
76 	gopkg.in/yaml.v2 v2.4.0 // indirect
77 )
M go.sum
+55, -22
  1@@ -44,8 +44,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
  2 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
  3 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
  4 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
  5-github.com/antoniomika/go-rsync-receiver v0.0.0-20220825041817-0387edc9afb7 h1:CECWxPqxYAwjlUQxEeuaqnjlTsOsaAMfu6f27xHswm0=
  6-github.com/antoniomika/go-rsync-receiver v0.0.0-20220825041817-0387edc9afb7/go.mod h1:zmqePVIo1hp+WEKxERLLGHJBDOr8/z/T4eFqXgWIw1w=
  7+github.com/antoniomika/go-rsync-receiver v0.0.0-20220825051444-e2df2a87b439 h1:5AjhKkEyKSn81jZXXSX/Mob3hLNUfP4Dyo49vyITQQI=
  8+github.com/antoniomika/go-rsync-receiver v0.0.0-20220825051444-e2df2a87b439/go.mod h1:zmqePVIo1hp+WEKxERLLGHJBDOr8/z/T4eFqXgWIw1w=
  9 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
 10 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
 11 github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
 12@@ -91,14 +91,35 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 13 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 14 github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
 15 github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 16-github.com/dsoprea/go-exif v0.0.0-20190901173045-3ce78807c90f h1:vqfYiZ+xF0xJvl9SZ1kovmMgKjaGZIz/Hn8JDQdyd9A=
 17 github.com/dsoprea/go-exif v0.0.0-20190901173045-3ce78807c90f/go.mod h1:DmMpU91/Ax6BAwoRkjgRCr2rmgEgS4tsmatfV7M+U+c=
 18-github.com/dsoprea/go-jpeg-image-structure v0.0.0-20190422055009-d6f9ba25cf48 h1:9zARagUAxQJjibcDy+0+koUMR6sbX38L49Bk2Vni628=
 19+github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b h1:hoVHc4m/v8Al8mbWyvKJWr4Z37yM4QUSVh/NY6A5Sbc=
 20+github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs=
 21+github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
 22+github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
 23+github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b h1:8lVRnnni9zebcpjkrEXrEyxFpRWG/oTpWc2Y3giKomE=
 24+github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b/go.mod h1:oKrjk2kb3rAR5NbtSTLUMvMSbc+k8ZosI3MaVH47noc=
 25+github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
 26+github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
 27+github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
 28+github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 h1:YDRiMEm32T60Kpm35YzOK9ZHgjsS1Qrid+XskNcsdp8=
 29+github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
 30 github.com/dsoprea/go-jpeg-image-structure v0.0.0-20190422055009-d6f9ba25cf48/go.mod h1:H1hAaFyv9cRV1ywoHvaqVoNSThBvWZ0JarRBcV+FSnE=
 31-github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y=
 32+github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836 h1:OHRfKIVRz2XrhZ6A7fJKHLoKky1giN+VUgU2npF0BvE=
 33+github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836/go.mod h1:6+tQXZ+I62x13UZ+hemLVoZIuq/usVzvau7bqwUo9P0=
 34 github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
 35-github.com/dsoprea/go-png-image-structure v0.0.0-20190624104353-c9b28dcdc5c8 h1:SVQfy5rBFZXzvGkU2MZ0RzpS912/1sJrEJ+FMmeaC9U=
 36+github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
 37+github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
 38+github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
 39+github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
 40+github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d h1:dg6UMHa50VI01WuPWXPbNJpO8QSyvIF5T5n2IZiqX3A=
 41+github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
 42 github.com/dsoprea/go-png-image-structure v0.0.0-20190624104353-c9b28dcdc5c8/go.mod h1:Bf0nmcDFFRQBjZwr9qY6c0zTxKQa+Q8YWZmlYxXGxY0=
 43+github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d h1:8+qI8ant/vZkNSsbwSjIR6XJfWcDVTg/qx/3pRUUZNA=
 44+github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d/go.mod h1:yTR3tKgyk20phAFg6IE9ulMA5NjEDD2wyx+okRFLVtw=
 45+github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
 46+github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e h1:ojqYA1mU6LuRm8XzrVOvyfb000y59cbUcu6Wt8sFSAs=
 47+github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e/go.mod h1:KVK+/Hul09ujXAGq+42UBgCTnXkiJZRnLYdURGjQUwo=
 48+github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
 49 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 50 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 51 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 52@@ -107,8 +128,11 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
 53 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 54 github.com/gliderlabs/ssh v0.3.4 h1:+AXBtim7MTKaLVPgvE+3mhewYRawNLTd+jEEz/wExZw=
 55 github.com/gliderlabs/ssh v0.3.4/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914=
 56-github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
 57 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 58+github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
 59+github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
 60+github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
 61+github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 62 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 63 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 64 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 65@@ -121,9 +145,15 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 66 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 67 github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 68 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 69+github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
 70+github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
 71+github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
 72 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 73-github.com/golang/geo v0.0.0-20190812012225-f41920e961ce h1:rqIKPpIcEgiNn0KYNFYD34TbMO86l4woyhNzSP+Oegs=
 74 github.com/golang/geo v0.0.0-20190812012225-f41920e961ce/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 75+github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 76+github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 77+github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
 78+github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 79 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 80 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 81 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 82@@ -188,6 +218,7 @@ github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBba
 83 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 84 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 85 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 86+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 87 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 88 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 89 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 90@@ -203,8 +234,8 @@ github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQan
 91 github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
 92 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 93 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 94-github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
 95-github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 96+github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
 97+github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 98 github.com/kolesa-team/go-webp v1.0.1 h1:Btojkbzr6tt10zJ40xlbSfJeHFiNn0aR7H03QUqmMoI=
 99 github.com/kolesa-team/go-webp v1.0.1/go.mod h1:oMvdivD6K+Q5qIIkVC2w4k2ZUnI1H+MyP7inwgWq9aA=
100 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
101@@ -241,8 +272,8 @@ github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P
102 github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
103 github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
104 github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
105-github.com/minio/minio-go/v7 v7.0.34 h1:JMfS5fudx1mN6V2MMNyCJ7UMrjEzZzIvMgfkWc1Vnjk=
106-github.com/minio/minio-go/v7 v7.0.34/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
107+github.com/minio/minio-go/v7 v7.0.35 h1:JuPPxWLdxQmNLSaS8AWZnO5HBadeI1xg6FGrEELQEVU=
108+github.com/minio/minio-go/v7 v7.0.35/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
109 github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
110 github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
111 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
112@@ -362,8 +393,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
113 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
114 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
115 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
116-golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 h1:vJ2V3lFLg+bBhgroYuRfyN583UzVveQmIXjc8T/y3to=
117-golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
118+golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
119+golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
120 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
121 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
122 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
123@@ -374,8 +405,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
124 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
125 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
126 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
127-golang.org/x/exp v0.0.0-20220823124025-807a23277127 h1:S4NrSKDfihhl3+4jSTgwoIevKxX9p7Iv9x++OEIptDo=
128-golang.org/x/exp v0.0.0-20220823124025-807a23277127/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
129+golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
130+golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
131 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
132 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
133 golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
134@@ -419,6 +450,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
135 golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
136 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
137 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
138+golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
139 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
140 golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
141 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
142@@ -432,8 +464,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
143 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
144 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
145 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
146-golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes=
147-golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
148+golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
149+golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
150 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
151 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
152 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
153@@ -495,8 +527,8 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc
154 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
155 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
156 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
157-golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 h1:TyKJRhyo17yWxOMCTHKWrc5rddHORMlnZ/j57umaUd8=
158-golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
159+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
160+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
161 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
162 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
163 golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
164@@ -639,12 +671,13 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
165 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
166 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
167 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
168-gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
169-gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
170+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
171+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
172 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
173 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
174 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
175 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
176+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
177 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
178 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
179 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
M imgs/api.go
+24, -22
  1@@ -8,12 +8,16 @@ import (
  2 	gif "image/gif"
  3 	jpeg "image/jpeg"
  4 	png "image/png"
  5+	"io"
  6 	"net/http"
  7 	"net/url"
  8 	"strconv"
  9 	"strings"
 10 	"time"
 11 
 12+	"net/http/pprof"
 13+	_ "net/http/pprof"
 14+
 15 	"git.sr.ht/~erock/pico/db"
 16 	"git.sr.ht/~erock/pico/db/postgres"
 17 	"git.sr.ht/~erock/pico/imgs/storage"
 18@@ -210,8 +214,7 @@ type ImgOptimizer struct {
 19 	Dimes      string
 20 }
 21 
 22-func (h *ImgOptimizer) GetImage(contents []byte, mimeType string) (image.Image, error) {
 23-	r := bytes.NewReader(contents)
 24+func (h *ImgOptimizer) GetImage(r io.Reader, mimeType string) (image.Image, error) {
 25 	switch mimeType {
 26 	case "image/png":
 27 		return png.Decode(r)
 28@@ -275,14 +278,15 @@ type SubImager interface {
 29 	SubImage(r image.Rectangle) image.Image
 30 }
 31 
 32-func (h *ImgOptimizer) Process(contents []byte, mimeType string) ([]byte, error) {
 33+func (h *ImgOptimizer) Process(contents io.Reader, writer io.Writer, mimeType string) error {
 34 	if !h.Optimized {
 35-		return contents, nil
 36+		_, err := io.Copy(writer, contents)
 37+		return err
 38 	}
 39 
 40 	img, err := h.GetImage(contents, mimeType)
 41 	if err != nil {
 42-		return []byte{}, err
 43+		return err
 44 	}
 45 
 46 	nextImg := img
 47@@ -295,19 +299,10 @@ func (h *ImgOptimizer) Process(contents []byte, mimeType string) ([]byte, error)
 48 		h.Quality,
 49 	)
 50 	if err != nil {
 51-		return []byte{}, err
 52-	}
 53-
 54-	output := &bytes.Buffer{}
 55-	err = webp.Encode(output, nextImg, options)
 56-	if err != nil {
 57-		return []byte{}, err
 58+		return err
 59 	}
 60 
 61-	if mimeType == "image/png" {
 62-		fmt.Println(output)
 63-	}
 64-	return output.Bytes(), nil
 65+	return webp.Encode(writer, nextImg, options)
 66 }
 67 
 68 func NewImgOptimizer(logger *zap.SugaredLogger, optimized bool, dimes string) *ImgOptimizer {
 69@@ -362,12 +357,14 @@ func imgHandler(w http.ResponseWriter, h *ImgHandler) {
 70 		http.Error(w, err.Error(), http.StatusInternalServerError)
 71 		return
 72 	}
 73+
 74 	contents, err := h.Storage.GetFile(bucket, post.Filename)
 75 	if err != nil {
 76 		h.Logger.Infof("file not found %s/%s", h.Username, post.Filename)
 77 		http.Error(w, err.Error(), http.StatusInternalServerError)
 78 		return
 79 	}
 80+	defer contents.Close()
 81 
 82 	if h.Img.Optimized {
 83 		w.Header().Add("Content-Type", "image/webp")
 84@@ -375,12 +372,7 @@ func imgHandler(w http.ResponseWriter, h *ImgHandler) {
 85 		w.Header().Add("Content-Type", post.MimeType)
 86 	}
 87 
 88-	contentsProc, err := h.Img.Process(contents, strings.TrimSpace(post.MimeType))
 89-	if err != nil {
 90-		h.Logger.Error(err)
 91-	}
 92-
 93-	_, err = w.Write(contentsProc)
 94+	err = h.Img.Process(contents, w, strings.TrimSpace(post.MimeType))
 95 	if err != nil {
 96 		h.Logger.Error(err)
 97 	}
 98@@ -788,6 +780,16 @@ func createMainRoutes(staticRoutes []shared.Route) []shared.Route {
 99 		shared.NewRoute("GET", "/help", shared.CreatePageHandler("html/help.page.tmpl")),
100 		shared.NewRoute("GET", "/transparency", transparencyHandler),
101 		shared.NewRoute("GET", "/check", shared.CheckHandler),
102+		shared.NewRoute("GET", "/debug/pprof/(.*)", pprof.Index),
103+		shared.NewRoute("GET", "/debug/pprof/cmdline", pprof.Cmdline),
104+		shared.NewRoute("GET", "/debug/pprof/profile", pprof.Profile),
105+		shared.NewRoute("GET", "/debug/pprof/symbol", pprof.Symbol),
106+		shared.NewRoute("GET", "/debug/pprof/trace", pprof.Trace),
107+		shared.NewRoute("POST", "/debug/pprof/(.*)", pprof.Index),
108+		shared.NewRoute("POST", "/debug/pprof/cmdline", pprof.Cmdline),
109+		shared.NewRoute("POST", "/debug/pprof/profile", pprof.Profile),
110+		shared.NewRoute("POST", "/debug/pprof/symbol", pprof.Symbol),
111+		shared.NewRoute("POST", "/debug/pprof/trace", pprof.Trace),
112 	}
113 
114 	routes = append(
M imgs/storage/minio.go
+5, -11
 1@@ -1,7 +1,6 @@
 2 package storage
 3 
 4 import (
 5-	"bytes"
 6 	"context"
 7 	"errors"
 8 	"fmt"
 9@@ -67,22 +66,17 @@ func (s *StorageMinio) UpsertBucket(name string) (Bucket, error) {
10 	return bucket, nil
11 }
12 
13-func (s *StorageMinio) GetFile(bucket Bucket, fname string) ([]byte, error) {
14+func (s *StorageMinio) GetFile(bucket Bucket, fname string) (io.ReadCloser, error) {
15 	obj, err := s.Client.GetObject(context.TODO(), bucket.Name, fname, minio.GetObjectOptions{})
16 	if err != nil {
17-		return []byte{}, err
18-	}
19-
20-	dat, err := io.ReadAll(obj)
21-	if err != nil {
22-		return []byte{}, err
23+		return nil, err
24 	}
25 
26-	return dat, nil
27+	return obj, nil
28 }
29 
30-func (s *StorageMinio) PutFile(bucket Bucket, fname string, contents []byte) (string, error) {
31-	info, err := s.Client.PutObject(context.TODO(), bucket.Name, fname, bytes.NewReader(contents), int64(len(contents)), minio.PutObjectOptions{})
32+func (s *StorageMinio) PutFile(bucket Bucket, fname string, contents io.ReadCloser) (string, error) {
33+	info, err := s.Client.PutObject(context.TODO(), bucket.Name, fname, contents, -1, minio.PutObjectOptions{})
34 	if err != nil {
35 		return "", err
36 	}
M imgs/storage/storage.go
+14, -7
 1@@ -2,6 +2,7 @@ package storage
 2 
 3 import (
 4 	"fmt"
 5+	"io"
 6 	"os"
 7 	"path"
 8 )
 9@@ -15,8 +16,8 @@ type ObjectStorage interface {
10 	GetBucket(name string) (Bucket, error)
11 	UpsertBucket(name string) (Bucket, error)
12 
13-	GetFile(bucket Bucket, fname string) ([]byte, error)
14-	PutFile(bucket Bucket, fname string, contents []byte) (string, error)
15+	GetFile(bucket Bucket, fname string) (io.ReadCloser, error)
16+	PutFile(bucket Bucket, fname string, contents io.ReadCloser) (string, error)
17 	DeleteFile(bucket Bucket, fname string) error
18 }
19 
20@@ -67,18 +68,24 @@ func (s *StorageFS) UpsertBucket(name string) (Bucket, error) {
21 	return bucket, nil
22 }
23 
24-func (s *StorageFS) GetFile(bucket Bucket, fname string) ([]byte, error) {
25-	dat, err := os.ReadFile(path.Join(bucket.Path, fname))
26+func (s *StorageFS) GetFile(bucket Bucket, fname string) (io.ReadCloser, error) {
27+	dat, err := os.Open(path.Join(bucket.Path, fname))
28 	if err != nil {
29-		return []byte{}, err
30+		return nil, err
31 	}
32 
33 	return dat, nil
34 }
35 
36-func (s *StorageFS) PutFile(bucket Bucket, fname string, contents []byte) (string, error) {
37+func (s *StorageFS) PutFile(bucket Bucket, fname string, contents io.ReadCloser) (string, error) {
38 	loc := path.Join(bucket.Path, fname)
39-	err := os.WriteFile(loc, contents, 0644)
40+	f, err := os.OpenFile(loc, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
41+	if err != nil {
42+		return "", err
43+	}
44+	defer f.Close()
45+
46+	_, err = io.Copy(f, contents)
47 	if err != nil {
48 		return "", err
49 	}