Skip to content

Commit

Permalink
Added: configuration and endpoints for pinata
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanSerikov authored and m-kus committed Dec 3, 2020
1 parent d82ecbf commit a179a51
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 35 deletions.
4 changes: 4 additions & 0 deletions build/compiler/dev/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ api:
operations:
non_durable: true
auto_deleted: true
pinata:
key: ${PINATA_KEY}
secret_key: ${PINATA_SECRET_KEY}
timeout_seconds: 10

compiler:
project_name: compiler
Expand Down
1 change: 1 addition & 0 deletions cmd/api/handlers/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func NewContext(cfg config.Config) (*Context, error) {
config.WithConfigCopy(cfg),
config.WithContractsInterfaces(),
config.WithRabbit(cfg.RabbitMQ, cfg.API.ProjectName, cfg.API.MQ),
config.WithPinata(cfg.API.Pinata),
)

return &Context{
Expand Down
61 changes: 61 additions & 0 deletions cmd/api/handlers/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package handlers

import (
"bytes"
"fmt"
"io/ioutil"
"net/http"

"github.com/gin-gonic/gin"
)

const metadataBytesLimit = 65536

// UploadMetadata -
func (ctx *Context) UploadMetadata(c *gin.Context) {
if c.Request.Body == nil {
c.JSON(http.StatusBadRequest, nil)
return
}

body, err := ioutil.ReadAll(c.Request.Body)
if handleError(c, err, http.StatusBadRequest) {
return
}

if len(body) > metadataBytesLimit {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("exceeded max upload limit of %d bytes", metadataBytesLimit)})
return
}

response, err := ctx.Pinata.PinJSONToIPFS(bytes.NewBuffer(body))
if handleError(c, err, http.StatusBadRequest) {
return
}

c.JSON(http.StatusOK, MetadataResponse{Hash: response.IpfsHash})
}

// ListMetadata -
func (ctx *Context) ListMetadata(c *gin.Context) {
list, err := ctx.Pinata.PinList()
if handleError(c, err, http.StatusInternalServerError) {
return
}

c.JSON(http.StatusOK, list)
}

// DeleteMetadata -
func (ctx *Context) DeleteMetadata(c *gin.Context) {
var req metadataRequest
if err := c.BindJSON(&req); handleError(c, err, http.StatusBadRequest) {
return
}

if err := ctx.Pinata.UnPin(req.Hash); handleError(c, err, http.StatusBadRequest) {
return
}

c.JSON(http.StatusOK, gin.H{"message": "metadata was successfully deleted"})
}
4 changes: 4 additions & 0 deletions cmd/api/handlers/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,7 @@ type resolveDomainRequest struct {
Name string `form:"name" binding:"omitempty"`
Address string `form:"address" binding:"omitempty"`
}

type metadataRequest struct {
Hash string `json:"hash" binding:"required"`
}
5 changes: 5 additions & 0 deletions cmd/api/handlers/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,8 @@ type DomainsResponse struct {
type CountResponse struct {
Count int64 `json:"count"`
}

// MetadataResponse -
type MetadataResponse struct {
Hash string `json:"hash"`
}
7 changes: 7 additions & 0 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ func (api *app) makeRouter() {
}
}

metadata := v1.Group("metadata")
{
metadata.POST("upload", api.Context.UploadMetadata)
metadata.GET("list", api.Context.ListMetadata)
metadata.DELETE("delete", api.Context.DeleteMetadata)
}

oauth := v1.Group("oauth/:provider")
{
oauth.GET("login", api.Context.OauthLogin)
Expand Down
4 changes: 4 additions & 0 deletions configs/development.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ api:
operations:
non_durable: true
auto_deleted: true
pinata:
key: ${PINATA_KEY}
secret_key: ${PINATA_SECRET_KEY}
timeout_seconds: 10

compiler:
project_name: compiler
Expand Down
4 changes: 4 additions & 0 deletions configs/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ api:
operations:
non_durable: true
auto_deleted: true
pinata:
key: ${PINATA_KEY}
secret_key: ${PINATA_SECRET_KEY}
timeout_seconds: 10

compiler:
project_name: compiler
Expand Down
4 changes: 4 additions & 0 deletions configs/sandbox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ api:
operations:
non_durable: true
auto_deleted: true
pinata:
key: ${PINATA_KEY}
secret_key: ${PINATA_SECRET_KEY}
timeout_seconds: 10

indexer:
project_name: indexer
Expand Down
4 changes: 4 additions & 0 deletions configs/you.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ api:
operations:
non_durable: true
auto_deleted: true
pinata:
key: ${PINATA_KEY}
secret_key: ${PINATA_SECRET_KEY}
timeout_seconds: 10

compiler:
project_name: compiler
Expand Down
28 changes: 18 additions & 10 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ type Config struct {
Domains TezosDomainsConfig `yaml:"domains"`

API struct {
ProjectName string `yaml:"project_name"`
Bind string `yaml:"bind"`
SwaggerHost string `yaml:"swagger_host"`
CorsEnabled bool `yaml:"cors_enabled"`
OAuthEnabled bool `yaml:"oauth_enabled"`
SentryEnabled bool `yaml:"sentry_enabled"`
SeedEnabled bool `yaml:"seed_enabled"`
Seed SeedConfig `yaml:"seed"`
Networks []string `yaml:"networks"`
MQ MQConfig `yaml:"mq"`
ProjectName string `yaml:"project_name"`
Bind string `yaml:"bind"`
SwaggerHost string `yaml:"swagger_host"`
CorsEnabled bool `yaml:"cors_enabled"`
OAuthEnabled bool `yaml:"oauth_enabled"`
SentryEnabled bool `yaml:"sentry_enabled"`
SeedEnabled bool `yaml:"seed_enabled"`
Seed SeedConfig `yaml:"seed"`
Networks []string `yaml:"networks"`
MQ MQConfig `yaml:"mq"`
Pinata PinataConfig `yaml:"pinata"`
} `yaml:"api"`

Compiler struct {
Expand Down Expand Up @@ -183,6 +184,13 @@ type QueueParams struct {
// TezosDomainsConfig -
type TezosDomainsConfig map[string]string

// PinataConfig -
type PinataConfig struct {
Key string `yaml:"key"`
SecretKey string `yaml:"secret_key"`
TimeoutSeconds int `yaml:"timeout_seconds"`
}

// LoadDefaultConfig -
func LoadDefaultConfig() (Config, error) {
configurations := map[string]string{
Expand Down
2 changes: 2 additions & 0 deletions internal/config/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/baking-bad/bcdhub/internal/elastic"
"github.com/baking-bad/bcdhub/internal/mq"
"github.com/baking-bad/bcdhub/internal/noderpc"
"github.com/baking-bad/bcdhub/internal/pinata"
"github.com/baking-bad/bcdhub/internal/tzkt"
"github.com/pkg/errors"
)
Expand All @@ -20,6 +21,7 @@ type Context struct {
AWS *aws.Client
RPC map[string]noderpc.INode
TzKTServices map[string]tzkt.Service
Pinata pinata.Service

Config Config
SharePath string
Expand Down
8 changes: 8 additions & 0 deletions internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/baking-bad/bcdhub/internal/elastic"
"github.com/baking-bad/bcdhub/internal/mq"
"github.com/baking-bad/bcdhub/internal/noderpc"
"github.com/baking-bad/bcdhub/internal/pinata"
"github.com/baking-bad/bcdhub/internal/tzkt"
)

Expand Down Expand Up @@ -149,3 +150,10 @@ func WithDomains(cfg TezosDomainsConfig) ContextOption {
ctx.Domains = cfg
}
}

// WithPinata -
func WithPinata(cfg PinataConfig) ContextOption {
return func(ctx *Context) {
ctx.Pinata = pinata.New(cfg.Key, cfg.SecretKey, time.Second*time.Duration(cfg.TimeoutSeconds))
}
}
74 changes: 49 additions & 25 deletions internal/pinata/pinata.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const baseURL = "https://api.pinata.cloud/"
type Service interface {
PinList() (PinList, error)
PinJSONToIPFS(data io.Reader) (PinJSONResponse, error)
UnPin(hash string) error
}

// Pinata -
Expand All @@ -40,33 +41,71 @@ func New(key, secretKey string, timeout time.Duration) *Pinata {
// PinList - https://pinata.cloud/documentation#PinList
func (p *Pinata) PinList() (PinList, error) {
var ret PinList
return ret, p.request("GET", "data/pinList", nil, make(map[string]string), &ret)
response, err := p.request("GET", "data/pinList", nil, make(map[string]string))
if err != nil {
return ret, err
}
defer response.Body.Close()

if response.StatusCode == http.StatusOK {
return ret, json.NewDecoder(response.Body).Decode(&ret)
}

data, err := ioutil.ReadAll(response.Body)
if err != nil {
return ret, err
}

return ret, fmt.Errorf("%s", string(data))
}

// PinJSONToIPFS - https://pinata.cloud/documentation#PinJSONToIPFS
func (p *Pinata) PinJSONToIPFS(body io.Reader) (PinJSONResponse, error) {
func (p *Pinata) PinJSONToIPFS(data io.Reader) (PinJSONResponse, error) {
var ret PinJSONResponse
return ret, p.request("POST", "pinning/pinJSONToIPFS", body, make(map[string]string), &ret)
response, err := p.request("POST", "pinning/pinJSONToIPFS", data, make(map[string]string))
if err != nil {
return ret, err
}
defer response.Body.Close()

if response.StatusCode == http.StatusOK {
return ret, json.NewDecoder(response.Body).Decode(&ret)
}

b, err := ioutil.ReadAll(response.Body)
if err != nil {
return ret, err
}

return ret, fmt.Errorf("%s", string(b))
}

// UnPin - https://pinata.cloud/documentation#Unpin
func (p *Pinata) UnPin(hash string) error {
var ret interface{}
if err := p.request("DELETE", fmt.Sprintf("pinning/unpin/%s", hash), nil, make(map[string]string), &ret); err != nil {
response, err := p.request("DELETE", fmt.Sprintf("pinning/unpin/%s", hash), nil, make(map[string]string))
if err != nil {
return err
}
defer response.Body.Close()

fmt.Println(ret.(string))
if response.StatusCode == http.StatusOK {
return nil
}

data, err := ioutil.ReadAll(response.Body)
if err != nil {
return err
}

return nil
return fmt.Errorf("%s", string(data))
}

func (p *Pinata) request(method, endpoint string, body io.Reader, params map[string]string, response interface{}) error {
func (p *Pinata) request(method, endpoint string, body io.Reader, params map[string]string) (*http.Response, error) {
url := helpers.URLJoin(baseURL, endpoint)

req, err := http.NewRequest(method, url, body)
if err != nil {
return fmt.Errorf("request http.NewRequest error %w", err)
return nil, fmt.Errorf("request http.NewRequest error %w", err)
}

q := req.URL.Query()
Expand All @@ -79,20 +118,5 @@ func (p *Pinata) request(method, endpoint string, body io.Reader, params map[str
req.Header.Add("pinata_api_key", p.apiKey)
req.Header.Add("pinata_secret_api_key", p.apiSecretKey)

resp, err := p.client.Do(req)
if err != nil {
return fmt.Errorf("pinata request error %s %s %v %w", method, endpoint, params, err)
}
defer resp.Body.Close()

if resp.StatusCode == http.StatusOK {
return json.NewDecoder(resp.Body).Decode(response)
}

data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}

return fmt.Errorf("%s", string(data))
return p.client.Do(req)
}

0 comments on commit a179a51

Please sign in to comment.