From 763bf48452f400356ae50a49b60a9faf03d0693f Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Fri, 20 Oct 2023 10:49:42 +0200 Subject: [PATCH 01/18] init --- go.mod | 3 +++ main.go | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 go.mod create mode 100644 main.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4af47db --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/gitcoinco/pina + +go 1.19 diff --git a/main.go b/main.go new file mode 100644 index 0000000..e978d86 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Printf("Hello World\n") +} From 2e50dd656863b1a93296a89a5677d6a25d8303de Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Fri, 20 Oct 2023 11:07:52 +0200 Subject: [PATCH 02/18] add http router and port/public flags --- go.mod | 2 ++ main.go | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4af47db..4f798c5 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/gitcoinco/pina go 1.19 + +require github.com/julienschmidt/httprouter v1.3.0 // indirect diff --git a/main.go b/main.go index e978d86..78c6dba 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,44 @@ package main -import "fmt" +import ( + "flag" + "fmt" + "log" + "net/http" + "os" + + "github.com/julienschmidt/httprouter" +) + +var ( + publicPath string + port int +) + +func init() { + flag.IntVar(&port, "port", 0, "http server port") + flag.StringVar(&publicPath, "public", "", "public path") +} + +func indexHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + fmt.Fprint(w, "Welcome!\n") +} func main() { - fmt.Printf("Hello World\n") + flag.Parse() + if port == 0 || publicPath == "" { + fmt.Println("port and public path flags are mandatory") + flag.Usage() + os.Exit(1) + } + + router := httprouter.New() + router.GET("/", indexHandler) + router.NotFound = http.FileServer(http.Dir(publicPath)) + + binding := fmt.Sprintf(":%d", port) + fmt.Printf("listening: %s\n", binding) + fmt.Printf("public path: %s\n", publicPath) + + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), router)) } From 629d77c0766dfa71bd5fa0f2a32d01a627808925 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Sat, 21 Oct 2023 23:50:08 +0200 Subject: [PATCH 03/18] add initial tests --- go.mod | 5 ++++- go.sum | 4 ++++ handlers_test.go | 23 +++++++++++++++++++++++ main.go | 14 +++++++++----- 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 go.sum create mode 100644 handlers_test.go diff --git a/go.mod b/go.mod index 4f798c5..8dc1bd8 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/gitcoinco/pina go 1.19 -require github.com/julienschmidt/httprouter v1.3.0 // indirect +require ( + github.com/gravityblast/miniassert v0.0.0-20140522125902-bee63581261a + github.com/julienschmidt/httprouter v1.3.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7c61c26 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/gravityblast/miniassert v0.0.0-20140522125902-bee63581261a h1:3xcty4gUzOHD4pqUZQDbS/Xb34susIRg9nmjKR3XM94= +github.com/gravityblast/miniassert v0.0.0-20140522125902-bee63581261a/go.mod h1:tVdF3zmaPraSn1jEeaVFIw4GYDX6fezNB3P9Gk4UpPA= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= diff --git a/handlers_test.go b/handlers_test.go new file mode 100644 index 0000000..8f90af7 --- /dev/null +++ b/handlers_test.go @@ -0,0 +1,23 @@ +package main + +import ( + "io" + "net/http/httptest" + "testing" + + assert "github.com/gravityblast/miniassert" +) + +func TestIndexHandler(t *testing.T) { + router := newRouter("./") + handler, _, _ := router.Lookup("GET", "/") + w := httptest.NewRecorder() + handler(w, nil, nil) + + resp := w.Result() + body, _ := io.ReadAll(resp.Body) + + assert.Equal(t, 200, resp.StatusCode) + assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) + assert.Equal(t, "Hello World", string(body)) +} diff --git a/main.go b/main.go index 78c6dba..a116d3d 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,14 @@ func init() { } func indexHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - fmt.Fprint(w, "Welcome!\n") + fmt.Fprint(w, "Hello World") +} + +func newRouter(publicPath string) *httprouter.Router { + router := httprouter.New() + router.GET("/", indexHandler) + router.NotFound = http.FileServer(http.Dir(publicPath)) + return router } func main() { @@ -32,10 +39,7 @@ func main() { os.Exit(1) } - router := httprouter.New() - router.GET("/", indexHandler) - router.NotFound = http.FileServer(http.Dir(publicPath)) - + router := newRouter(publicPath) binding := fmt.Sprintf(":%d", port) fmt.Printf("listening: %s\n", binding) fmt.Printf("public path: %s\n", publicPath) From e0ce4390eb6b4705b69071c3fa7f86e817018f2e Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Sun, 22 Oct 2023 12:58:16 +0200 Subject: [PATCH 04/18] test served static files --- handlers_test.go | 30 ++++++++++++++++++++++++++++++ main.go | 1 + 2 files changed, 31 insertions(+) diff --git a/handlers_test.go b/handlers_test.go index 8f90af7..3255f93 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -2,7 +2,10 @@ package main import ( "io" + "net/http" "net/http/httptest" + "os" + "path/filepath" "testing" assert "github.com/gravityblast/miniassert" @@ -21,3 +24,30 @@ func TestIndexHandler(t *testing.T) { assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) assert.Equal(t, "Hello World", string(body)) } + +func TestStaticFiles(t *testing.T) { + publicPath := t.TempDir() + ipfsPath := filepath.Join(publicPath, "ipfs") + err := os.Mkdir(ipfsPath, 0755) + if err != nil { + t.Fatal(err) + } + + filePath := filepath.Join(ipfsPath, "test.txt") + err = os.WriteFile(filePath, []byte("Static file example"), 0755) + if err != nil { + t.Fatal(err) + } + + router := newRouter(publicPath) + w := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, "/ipfs/test.txt", nil) + router.ServeHTTP(w, req) + + resp := w.Result() + body, _ := io.ReadAll(resp.Body) + + assert.Equal(t, 200, resp.StatusCode) + assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) + assert.Equal(t, "Static file example", string(body)) +} diff --git a/main.go b/main.go index a116d3d..ac997a2 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,7 @@ func newRouter(publicPath string) *httprouter.Router { router := httprouter.New() router.GET("/", indexHandler) router.NotFound = http.FileServer(http.Dir(publicPath)) + return router } From 2b6406045a4a9a444c8da4f03c2ada05a2e2168e Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Sun, 22 Oct 2023 22:30:45 +0200 Subject: [PATCH 05/18] add pinJSONHandler --- .gitignore | 2 ++ handlers_test.go | 72 ++++++++++++++++++++++++++++++++++++++++-------- main.go | 68 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64a5640 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/pina +/public diff --git a/handlers_test.go b/handlers_test.go index 3255f93..a7d2ad4 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -1,21 +1,39 @@ package main import ( + "bytes" + "encoding/json" "io" + "io/ioutil" + "log" "net/http" "net/http/httptest" "os" "path/filepath" + "strings" "testing" assert "github.com/gravityblast/miniassert" + "github.com/julienschmidt/httprouter" ) +func newTestRouter(t *testing.T) (*httprouter.Router, string) { + publicPath := t.TempDir() + router, err := newRouter(publicPath) + if err != nil { + t.Error(err) + t.FailNow() + } + + return router, filepath.Join(publicPath, "ipfs") +} + func TestIndexHandler(t *testing.T) { - router := newRouter("./") - handler, _, _ := router.Lookup("GET", "/") + router, _ := newTestRouter(t) + w := httptest.NewRecorder() - handler(w, nil, nil) + req := httptest.NewRequest(http.MethodGet, "/", nil) + router.ServeHTTP(w, req) resp := w.Result() body, _ := io.ReadAll(resp.Body) @@ -26,20 +44,13 @@ func TestIndexHandler(t *testing.T) { } func TestStaticFiles(t *testing.T) { - publicPath := t.TempDir() - ipfsPath := filepath.Join(publicPath, "ipfs") - err := os.Mkdir(ipfsPath, 0755) - if err != nil { - t.Fatal(err) - } - + router, ipfsPath := newTestRouter(t) filePath := filepath.Join(ipfsPath, "test.txt") - err = os.WriteFile(filePath, []byte("Static file example"), 0755) + err := os.WriteFile(filePath, []byte("Static file example"), 0755) if err != nil { t.Fatal(err) } - router := newRouter(publicPath) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/ipfs/test.txt", nil) router.ServeHTTP(w, req) @@ -51,3 +62,40 @@ func TestStaticFiles(t *testing.T) { assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) assert.Equal(t, "Static file example", string(body)) } + +func TestPinJSONHandler(t *testing.T) { + router, ipfsPath := newTestRouter(t) + + w := httptest.NewRecorder() + reqBody := bytes.NewBufferString(`{"pinataContent": {"foo": {"bar": "baz"}}}`) + req := httptest.NewRequest(http.MethodPost, "/pinning/pinJSONToIPFS", reqBody) + router.ServeHTTP(w, req) + + resp := w.Result() + + assert.Equal(t, 200, resp.StatusCode) + assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) + + var responseBody PinJSONResponseBody + err := json.NewDecoder(resp.Body).Decode(&responseBody) + if err != nil { + log.Fatal(err) + } + + assert.Equal(t, responseBody.IpfsHash, "foo") + assert.Equal(t, responseBody.PinSize, 10) + assert.NotEqual(t, "", responseBody.Timestamp) + + fileName := filepath.Join(ipfsPath, "test.json") + f, err := os.Open(fileName) + if err != nil { + log.Fatal(err) + } + + content, err := ioutil.ReadAll(f) + if err != nil { + log.Fatal(err) + } + + assert.Equal(t, `{"foo":{"bar":"baz"}}`, strings.TrimSpace(string(content))) +} diff --git a/main.go b/main.go index ac997a2..8c468e1 100644 --- a/main.go +++ b/main.go @@ -1,17 +1,31 @@ package main import ( + "encoding/json" "flag" "fmt" "log" "net/http" "os" + "path/filepath" + "time" "github.com/julienschmidt/httprouter" ) +type PinJSONRequestBody struct { + PinataContent interface{} `json:"pinataContent"` +} + +type PinJSONResponseBody struct { + IpfsHash string `json:"ipfsHash"` + PinSize int `json:"pinSize"` + Timestamp string `json:"timestamp"` +} + var ( publicPath string + ipfsPath string port int ) @@ -19,17 +33,62 @@ func init() { flag.IntVar(&port, "port", 0, "http server port") flag.StringVar(&publicPath, "public", "", "public path") } +func handleError(w http.ResponseWriter, err error) { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, "server error1") +} func indexHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { fmt.Fprint(w, "Hello World") } -func newRouter(publicPath string) *httprouter.Router { +func pinJSONHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + var body PinJSONRequestBody + + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + handleError(w, err) + return + } + + fileName := "test.json" + f, err := os.Create(filepath.Join(ipfsPath, fileName)) + if err != nil { + handleError(w, err) + return + } + defer f.Close() + + err = json.NewEncoder(f).Encode(body.PinataContent) + if err != nil { + handleError(w, err) + return + } + + err = json.NewEncoder(w).Encode(&PinJSONResponseBody{ + IpfsHash: "foo", + PinSize: 10, + Timestamp: time.Now().UTC().Format(time.RFC3339), + }) + + if err != nil { + handleError(w, err) + } +} + +func newRouter(publicPath string) (*httprouter.Router, error) { + ipfsPath = filepath.Join(publicPath, "ipfs") + err := os.MkdirAll(ipfsPath, 0755) + if err != nil { + return nil, err + } + router := httprouter.New() router.GET("/", indexHandler) + router.POST("/pinning/pinJSONToIPFS", pinJSONHandler) router.NotFound = http.FileServer(http.Dir(publicPath)) - return router + return router, nil } func main() { @@ -40,7 +99,10 @@ func main() { os.Exit(1) } - router := newRouter(publicPath) + router, err := newRouter(publicPath) + if err != nil { + log.Fatal(err) + } binding := fmt.Sprintf(":%d", port) fmt.Printf("listening: %s\n", binding) fmt.Printf("public path: %s\n", publicPath) From e39ee0a525708dcc93009b723e4e34aafea99c38 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Sun, 22 Oct 2023 22:36:33 +0200 Subject: [PATCH 06/18] generate real ipfs cid --- go.mod | 16 ++++++++++++++++ go.sum | 35 +++++++++++++++++++++++++++++++++++ handlers_test.go | 7 ++++--- main.go | 47 +++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 98 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 8dc1bd8..b73b587 100644 --- a/go.mod +++ b/go.mod @@ -6,3 +6,19 @@ require ( github.com/gravityblast/miniassert v0.0.0-20140522125902-bee63581261a github.com/julienschmidt/httprouter v1.3.0 ) + +require ( + github.com/ipfs/go-cid v0.4.1 // indirect + github.com/klauspost/cpuid/v2 v2.0.4 // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-multibase v0.0.3 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.0.15 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect +) diff --git a/go.sum b/go.sum index 7c61c26..8a60b18 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,39 @@ github.com/gravityblast/miniassert v0.0.0-20140522125902-bee63581261a h1:3xcty4gUzOHD4pqUZQDbS/Xb34susIRg9nmjKR3XM94= github.com/gravityblast/miniassert v0.0.0-20140522125902-bee63581261a/go.mod h1:tVdF3zmaPraSn1jEeaVFIw4GYDX6fezNB3P9Gk4UpPA= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= +github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/handlers_test.go b/handlers_test.go index a7d2ad4..c914c80 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -82,11 +82,12 @@ func TestPinJSONHandler(t *testing.T) { log.Fatal(err) } - assert.Equal(t, responseBody.IpfsHash, "foo") - assert.Equal(t, responseBody.PinSize, 10) + cid := "bafkreihktyturq4bzrikdjylvvjbrgh5rfigzlydmjoyri3ip6fjbcqddu" + assert.Equal(t, cid, responseBody.IpfsHash) + assert.Equal(t, 10, responseBody.PinSize) assert.NotEqual(t, "", responseBody.Timestamp) - fileName := filepath.Join(ipfsPath, "test.json") + fileName := filepath.Join(ipfsPath, cid) f, err := os.Open(fileName) if err != nil { log.Fatal(err) diff --git a/main.go b/main.go index 8c468e1..26f99a5 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/json" "flag" "fmt" @@ -10,7 +11,10 @@ import ( "path/filepath" "time" + cid "github.com/ipfs/go-cid" "github.com/julienschmidt/httprouter" + mc "github.com/multiformats/go-multicodec" + mh "github.com/multiformats/go-multihash" ) type PinJSONRequestBody struct { @@ -42,31 +46,65 @@ func indexHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { fmt.Fprint(w, "Hello World") } +func bytesToCID(b []byte) (string, error) { + pref := cid.Prefix{ + Version: 1, + Codec: uint64(mc.Raw), + MhType: mh.SHA2_256, + MhLength: -1, // default length + } + + hash, err := pref.Sum(b) + if err != nil { + return "", err + } + + return hash.String(), nil +} + func pinJSONHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var body PinJSONRequestBody + // parse request body err := json.NewDecoder(r.Body).Decode(&body) if err != nil { handleError(w, err) return } - fileName := "test.json" - f, err := os.Create(filepath.Join(ipfsPath, fileName)) + // encode JSON file content + content := bytes.NewBuffer([]byte{}) + err = json.NewEncoder(content).Encode(body.PinataContent) + if err != nil { + handleError(w, err) + return + } + + // generate CID + ipfsHash, err := bytesToCID(content.Bytes()) + if err != nil { + handleError(w, err) + return + } + + // create file using CID as file name + f, err := os.Create(filepath.Join(ipfsPath, ipfsHash)) if err != nil { handleError(w, err) return } defer f.Close() - err = json.NewEncoder(f).Encode(body.PinataContent) + // write JSON content to file + _, err = f.Write(content.Bytes()) if err != nil { handleError(w, err) return } + // encode response body err = json.NewEncoder(w).Encode(&PinJSONResponseBody{ - IpfsHash: "foo", + IpfsHash: ipfsHash, PinSize: 10, Timestamp: time.Now().UTC().Format(time.RFC3339), }) @@ -86,6 +124,7 @@ func newRouter(publicPath string) (*httprouter.Router, error) { router := httprouter.New() router.GET("/", indexHandler) router.POST("/pinning/pinJSONToIPFS", pinJSONHandler) + // router.POST("/pinning/pinFileToIPFS", pinFileHandler) router.NotFound = http.FileServer(http.Dir(publicPath)) return router, nil From 1f6718996ca682a6a70f723668648cd50b026a68 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Sun, 22 Oct 2023 23:38:25 +0200 Subject: [PATCH 07/18] add pinFileHandler --- handlers_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ main.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/handlers_test.go b/handlers_test.go index c914c80..418d3dd 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -3,11 +3,14 @@ package main import ( "bytes" "encoding/json" + "fmt" "io" "io/ioutil" "log" + "mime/multipart" "net/http" "net/http/httptest" + "net/textproto" "os" "path/filepath" "strings" @@ -100,3 +103,54 @@ func TestPinJSONHandler(t *testing.T) { assert.Equal(t, `{"foo":{"bar":"baz"}}`, strings.TrimSpace(string(content))) } + +func TestPinFileHandler(t *testing.T) { + router, _ := newTestRouter(t) + + body := new(bytes.Buffer) + writer := multipart.NewWriter(body) + // writer.WriteField("file", "Uploaded content") + + // Create the file part with an invalid file extension + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`, "file", "uploaded.txt")) + h.Set("Content-Type", "text/plain") + part, _ := writer.CreatePart(h) + part.Write([]byte("Uploaded content")) + writer.Close() + // Prepare and send the HTTP request + + w := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodPost, "/pinning/pinFileToIPFS", body) + req.Header.Add("Content-Type", writer.FormDataContentType()) + router.ServeHTTP(w, req) + + resp := w.Result() + + assert.Equal(t, 200, resp.StatusCode) + assert.Equal(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) + + var responseBody PinJSONResponseBody + err := json.NewDecoder(resp.Body).Decode(&responseBody) + if err != nil { + log.Fatal(err) + } + + cid := "bafkreifqrpvngn6k2q6qahrm2oawbtrsoucxi7xtxehydodbzgnky6eiem" + assert.Equal(t, cid, responseBody.IpfsHash) + assert.Equal(t, 10, responseBody.PinSize) + assert.NotEqual(t, "", responseBody.Timestamp) + + fileName := filepath.Join(ipfsPath, cid) + f, err := os.Open(fileName) + if err != nil { + log.Fatal(err) + } + + content, err := ioutil.ReadAll(f) + if err != nil { + log.Fatal(err) + } + + assert.Equal(t, "Uploaded content", strings.TrimSpace(string(content))) +} diff --git a/main.go b/main.go index 26f99a5..3e8cbc9 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "encoding/json" "flag" "fmt" + "io/ioutil" "log" "net/http" "os" @@ -114,6 +115,58 @@ func pinJSONHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) } } +func pinFileHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + r.ParseMultipartForm(10 << 20) // max 10MB + + // parse uploaded file + file, _, err := r.FormFile("file") + if err != nil { + handleError(w, err) + return + } + defer file.Close() + + // read file content + content, err := ioutil.ReadAll(file) + if err != nil { + handleError(w, err) + return + } + + // generate CID + ipfsHash, err := bytesToCID(content) + if err != nil { + handleError(w, err) + return + } + + // create file using CID as file name + f, err := os.Create(filepath.Join(ipfsPath, ipfsHash)) + if err != nil { + handleError(w, err) + return + } + defer f.Close() + + // write uploadded file content to file + _, err = f.Write(content) + if err != nil { + handleError(w, err) + return + } + + // encode response body + err = json.NewEncoder(w).Encode(&PinJSONResponseBody{ + IpfsHash: ipfsHash, + PinSize: 10, + Timestamp: time.Now().UTC().Format(time.RFC3339), + }) + + if err != nil { + handleError(w, err) + } +} + func newRouter(publicPath string) (*httprouter.Router, error) { ipfsPath = filepath.Join(publicPath, "ipfs") err := os.MkdirAll(ipfsPath, 0755) @@ -124,7 +177,7 @@ func newRouter(publicPath string) (*httprouter.Router, error) { router := httprouter.New() router.GET("/", indexHandler) router.POST("/pinning/pinJSONToIPFS", pinJSONHandler) - // router.POST("/pinning/pinFileToIPFS", pinFileHandler) + router.POST("/pinning/pinFileToIPFS", pinFileHandler) router.NotFound = http.FileServer(http.Dir(publicPath)) return router, nil From dee1c00bab048851f753af3c1073c5491f3a13ca Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Sun, 22 Oct 2023 23:42:54 +0200 Subject: [PATCH 08/18] add handleUpload --- main.go | 78 +++++++++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/main.go b/main.go index 3e8cbc9..8430f86 100644 --- a/main.go +++ b/main.go @@ -63,44 +63,24 @@ func bytesToCID(b []byte) (string, error) { return hash.String(), nil } -func pinJSONHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - var body PinJSONRequestBody - - // parse request body - err := json.NewDecoder(r.Body).Decode(&body) - if err != nil { - handleError(w, err) - return - } - - // encode JSON file content - content := bytes.NewBuffer([]byte{}) - err = json.NewEncoder(content).Encode(body.PinataContent) - if err != nil { - handleError(w, err) - return - } - +func handleUpload(w http.ResponseWriter, r *http.Request, content []byte) error { // generate CID - ipfsHash, err := bytesToCID(content.Bytes()) + ipfsHash, err := bytesToCID(content) if err != nil { - handleError(w, err) - return + return err } // create file using CID as file name f, err := os.Create(filepath.Join(ipfsPath, ipfsHash)) if err != nil { - handleError(w, err) - return + return err } defer f.Close() - // write JSON content to file - _, err = f.Write(content.Bytes()) + // write uploadded file content to file + _, err = f.Write(content) if err != nil { - handleError(w, err) - return + return err } // encode response body @@ -110,58 +90,52 @@ func pinJSONHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) Timestamp: time.Now().UTC().Format(time.RFC3339), }) - if err != nil { - handleError(w, err) - } + return err } -func pinFileHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - r.ParseMultipartForm(10 << 20) // max 10MB +func pinJSONHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + var body PinJSONRequestBody - // parse uploaded file - file, _, err := r.FormFile("file") + // parse request body + err := json.NewDecoder(r.Body).Decode(&body) if err != nil { handleError(w, err) return } - defer file.Close() - // read file content - content, err := ioutil.ReadAll(file) + // encode JSON file content + content := bytes.NewBuffer([]byte{}) + err = json.NewEncoder(content).Encode(body.PinataContent) if err != nil { handleError(w, err) return } - // generate CID - ipfsHash, err := bytesToCID(content) + err = handleUpload(w, r, content.Bytes()) if err != nil { handleError(w, err) - return } +} - // create file using CID as file name - f, err := os.Create(filepath.Join(ipfsPath, ipfsHash)) +func pinFileHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + r.ParseMultipartForm(10 << 20) // max 10MB + + // parse uploaded file + file, _, err := r.FormFile("file") if err != nil { handleError(w, err) return } - defer f.Close() + defer file.Close() - // write uploadded file content to file - _, err = f.Write(content) + // read file content + content, err := ioutil.ReadAll(file) if err != nil { handleError(w, err) return } - // encode response body - err = json.NewEncoder(w).Encode(&PinJSONResponseBody{ - IpfsHash: ipfsHash, - PinSize: 10, - Timestamp: time.Now().UTC().Format(time.RFC3339), - }) - + err = handleUpload(w, r, content) if err != nil { handleError(w, err) } From d357475f7d2ef36c68f8f888a0be42bb2d674a2e Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Mon, 23 Oct 2023 09:57:46 +0200 Subject: [PATCH 09/18] add authentication --- handlers_test.go | 2 ++ main.go | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/handlers_test.go b/handlers_test.go index 418d3dd..fb0402c 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -72,6 +72,7 @@ func TestPinJSONHandler(t *testing.T) { w := httptest.NewRecorder() reqBody := bytes.NewBufferString(`{"pinataContent": {"foo": {"bar": "baz"}}}`) req := httptest.NewRequest(http.MethodPost, "/pinning/pinJSONToIPFS", reqBody) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", AUTH_TOKEN)) router.ServeHTTP(w, req) resp := w.Result() @@ -122,6 +123,7 @@ func TestPinFileHandler(t *testing.T) { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/pinning/pinFileToIPFS", body) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", AUTH_TOKEN)) req.Header.Add("Content-Type", writer.FormDataContentType()) router.ServeHTTP(w, req) diff --git a/main.go b/main.go index 8430f86..e68536b 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "time" cid "github.com/ipfs/go-cid" @@ -18,6 +19,8 @@ import ( mh "github.com/multiformats/go-multihash" ) +const AUTH_TOKEN = "development-token" + type PinJSONRequestBody struct { PinataContent interface{} `json:"pinataContent"` } @@ -40,7 +43,7 @@ func init() { } func handleError(w http.ResponseWriter, err error) { w.WriteHeader(http.StatusInternalServerError) - fmt.Fprint(w, "server error1") + fmt.Fprint(w, "server error") } func indexHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { @@ -141,6 +144,19 @@ func pinFileHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) } } +func authWrapper(next httprouter.Handle) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) { + authorization := r.Header.Get("Authorization") + token := strings.TrimSpace(strings.Replace(authorization, "Bearer", "", 1)) + if token != AUTH_TOKEN { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, fmt.Sprintf("access denied, you are not using the development auth token: %s", AUTH_TOKEN)) + return + } + next(w, r, params) + } +} + func newRouter(publicPath string) (*httprouter.Router, error) { ipfsPath = filepath.Join(publicPath, "ipfs") err := os.MkdirAll(ipfsPath, 0755) @@ -150,8 +166,8 @@ func newRouter(publicPath string) (*httprouter.Router, error) { router := httprouter.New() router.GET("/", indexHandler) - router.POST("/pinning/pinJSONToIPFS", pinJSONHandler) - router.POST("/pinning/pinFileToIPFS", pinFileHandler) + router.POST("/pinning/pinJSONToIPFS", authWrapper(pinJSONHandler)) + router.POST("/pinning/pinFileToIPFS", authWrapper(pinFileHandler)) router.NotFound = http.FileServer(http.Dir(publicPath)) return router, nil From a8ead83201465fba57f35997b88940ee461c9de2 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Mon, 23 Oct 2023 10:05:17 +0200 Subject: [PATCH 10/18] add README --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6f554a5 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# Piña 🍍 + +Piña is a clone of the [Pinata](https://www.pinata.cloud/) API, +**exclusively designed for local development environments** to streamline your development process and minimize +the need for direct usage of Pinata's services during development. + +## API + +``` +get /ipfs/{CID} +post /pinning/pinJSONToIPFS +post /pinning/pinFileToIPFS +``` + +### Test + +`go test` + +### Run + +`go build && ./pina -port 8000 -public ./public` + +### Run in docker + +``` +make docker-build +make docker-run +``` From 13fa9af5d85eda4499a5761bc6f7a6a88162f512 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Mon, 23 Oct 2023 10:10:28 +0200 Subject: [PATCH 11/18] add Docker files --- .dockerignore | 2 ++ Dockerfile | 13 +++++++++++++ Makefile | 22 ++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Makefile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9a93045 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +/public +/bin diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7cb490a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.21.3-alpine3.18 + +COPY . /app +WORKDIR /app + +RUN mkdir /app/bin +RUN mkdir /app/public + +RUN CGO_ENABLED=0 GOOS=linux go build -o /app/bin/🍍 + +EXPOSE 8000 + +CMD /app/bin/🍍 -port 8000 -public /app/public diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6b856d1 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +.PHONY: docker-build docker-run docker-kill docker-stop docker-logs docker-deploy-contracts docker-all + +IMAGE_NAME=pina +CONTAINER_NAME=pina + +docker-all: docker-kill docker-build docker-run + +docker-build: + docker build . -t $(IMAGE_NAME) --no-cache --progress=plain + +docker-run: + docker run --name $(CONTAINER_NAME) --rm -d -p 127.0.0.1:8000:8000/tcp $(IMAGE_NAME) + +docker-kill: + -docker kill $(CONTAINER_NAME) + +docker-stop: + docker stop $(CONTAINER_NAME) + +docker-logs: + docker logs -f $(CONTAINER_NAME) + From 79d7fc8dff8127decb11ac35b2f33e6e4ea08f65 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Mon, 23 Oct 2023 10:15:35 +0200 Subject: [PATCH 12/18] update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f554a5..dc550ee 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,13 @@ post /pinning/pinJSONToIPFS post /pinning/pinFileToIPFS ``` -### Test +### Test and Build -`go test` +``` +git clone git@github.com:gitcoinco/pina.git +go test +go build +``` ### Run From 89ad1a66e096b9880bd54b3ceccfcc23e8064b3d Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Mon, 23 Oct 2023 23:34:43 +0200 Subject: [PATCH 13/18] add docker action --- .github/workflows/docker-image.yml | 53 ++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..a3dc7ec --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,53 @@ +name: Create and publish a Docker image + +on: + push: + branches: + - '**' + pull_request: + branches: + - "**" + + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + From 86a3af735ac3a41c9ba45a686820d85fe9021780 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Tue, 24 Oct 2023 00:54:42 +0200 Subject: [PATCH 14/18] build From a04ad837f5f7e9968e4e444c12da33149cd0524e Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Tue, 24 Oct 2023 01:34:40 +0200 Subject: [PATCH 15/18] add default CORS handler --- go.mod | 1 + go.sum | 2 ++ main.go | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b73b587..0006d16 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.0.15 // indirect github.com/multiformats/go-varint v0.0.6 // indirect + github.com/rs/cors v1.10.1 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/sys v0.1.0 // indirect ) diff --git a/go.sum b/go.sum index 8a60b18..d6f0672 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2d github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= diff --git a/main.go b/main.go index e68536b..587c8cc 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( "github.com/julienschmidt/httprouter" mc "github.com/multiformats/go-multicodec" mh "github.com/multiformats/go-multihash" + "github.com/rs/cors" ) const AUTH_TOKEN = "development-token" @@ -189,5 +190,6 @@ func main() { fmt.Printf("listening: %s\n", binding) fmt.Printf("public path: %s\n", publicPath) - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), router)) + handler := cors.Default().Handler(router) + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), handler)) } From fb8b55a6777ba415ef6b558ca4de6442105fe00c Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Tue, 24 Oct 2023 02:33:56 +0200 Subject: [PATCH 16/18] add logger --- main.go | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index 587c8cc..85fa630 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,14 @@ import ( const AUTH_TOKEN = "development-token" +var ( + publicPath string + ipfsPath string + port int + + logger = log.New(os.Stderr, "", log.Ltime) +) + type PinJSONRequestBody struct { PinataContent interface{} `json:"pinataContent"` } @@ -32,11 +40,25 @@ type PinJSONResponseBody struct { Timestamp string `json:"timestamp"` } -var ( - publicPath string - ipfsPath string - port int -) +type WrappedResponseWriter struct { + http.ResponseWriter + lastStatusCode int +} + +func (w *WrappedResponseWriter) WriteHeader(statusCode int) { + w.lastStatusCode = statusCode + w.ResponseWriter.WriteHeader(statusCode) +} + +type LogHandler struct { + handler http.Handler +} + +func (l *LogHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ww := &WrappedResponseWriter{w, 200} + l.handler.ServeHTTP(ww, r) + logger.Printf("[%s] %s (%d)", r.Method, r.URL.Path, ww.lastStatusCode) +} func init() { flag.IntVar(&port, "port", 0, "http server port") @@ -187,9 +209,9 @@ func main() { log.Fatal(err) } binding := fmt.Sprintf(":%d", port) - fmt.Printf("listening: %s\n", binding) - fmt.Printf("public path: %s\n", publicPath) + logger.Printf("listening: %s\n", binding) + logger.Printf("public path: %s\n", publicPath) handler := cors.Default().Handler(router) - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), handler)) + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), &LogHandler{handler})) } From 57e8c66e1d36a95fc13dfde41241bf4fca3fb9c6 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Tue, 24 Oct 2023 11:02:42 +0200 Subject: [PATCH 17/18] log errors and written file paths --- main.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 85fa630..f2e45c0 100644 --- a/main.go +++ b/main.go @@ -64,8 +64,10 @@ func init() { flag.IntVar(&port, "port", 0, "http server port") flag.StringVar(&publicPath, "public", "", "public path") } + func handleError(w http.ResponseWriter, err error) { w.WriteHeader(http.StatusInternalServerError) + logger.Printf("error: %+v", err) fmt.Fprint(w, "server error") } @@ -97,7 +99,9 @@ func handleUpload(w http.ResponseWriter, r *http.Request, content []byte) error } // create file using CID as file name - f, err := os.Create(filepath.Join(ipfsPath, ipfsHash)) + filePath := filepath.Join(ipfsPath, ipfsHash) + logger.Printf("writing to file %s", filePath) + f, err := os.Create(filePath) if err != nil { return err } @@ -212,6 +216,6 @@ func main() { logger.Printf("listening: %s\n", binding) logger.Printf("public path: %s\n", publicPath) - handler := cors.Default().Handler(router) + handler := cors.New(cors.Options{Logger: logger, AllowedHeaders: []string{"*"}}).Handler(router) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), &LogHandler{handler})) } From bc6ffa701fa974c72903d4c37995850d164527ba Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Tue, 24 Oct 2023 11:11:57 +0200 Subject: [PATCH 18/18] pinata responses starts with uppercase char --- main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index f2e45c0..8adcf36 100644 --- a/main.go +++ b/main.go @@ -35,9 +35,9 @@ type PinJSONRequestBody struct { } type PinJSONResponseBody struct { - IpfsHash string `json:"ipfsHash"` - PinSize int `json:"pinSize"` - Timestamp string `json:"timestamp"` + IpfsHash string `json:"IpfsHash"` + PinSize int `json:"PinSize"` + Timestamp string `json:"Timestamp"` } type WrappedResponseWriter struct {