2016-12-02 18:33:39 +00:00
|
|
|
package ipfscluster
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2017-01-24 15:19:23 +00:00
|
|
|
"encoding/base64"
|
2016-12-02 18:33:39 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2016-12-05 15:24:41 +00:00
|
|
|
"net"
|
2016-12-02 18:33:39 +00:00
|
|
|
"net/http"
|
2017-01-23 17:38:59 +00:00
|
|
|
"strconv"
|
2016-12-15 13:07:19 +00:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2016-12-22 10:31:09 +00:00
|
|
|
"time"
|
2016-12-02 18:33:39 +00:00
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
rpc "github.com/hsanjuan/go-libp2p-rpc"
|
2016-12-16 11:40:28 +00:00
|
|
|
cid "github.com/ipfs/go-cid"
|
2016-12-23 18:35:37 +00:00
|
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
2017-01-23 17:38:59 +00:00
|
|
|
ma "github.com/multiformats/go-multiaddr"
|
2016-12-02 18:33:39 +00:00
|
|
|
|
|
|
|
mux "github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
2016-12-22 10:31:09 +00:00
|
|
|
// Server settings
|
|
|
|
var (
|
|
|
|
// maximum duration before timing out read of the request
|
|
|
|
RESTAPIServerReadTimeout = 5 * time.Second
|
|
|
|
// maximum duration before timing out write of the response
|
|
|
|
RESTAPIServerWriteTimeout = 10 * time.Second
|
|
|
|
// server-side the amount of time a Keep-Alive connection will be
|
|
|
|
// kept idle before being reused
|
|
|
|
RESTAPIServerIdleTimeout = 60 * time.Second
|
|
|
|
)
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
// RESTAPI implements an API and aims to provides
|
2016-12-02 18:33:39 +00:00
|
|
|
// a RESTful HTTP API for Cluster.
|
2016-12-16 18:14:45 +00:00
|
|
|
type RESTAPI struct {
|
2016-12-02 18:33:39 +00:00
|
|
|
ctx context.Context
|
2017-01-23 22:58:04 +00:00
|
|
|
apiAddr ma.Multiaddr
|
2016-12-02 18:33:39 +00:00
|
|
|
listenAddr string
|
|
|
|
listenPort int
|
2016-12-23 18:35:37 +00:00
|
|
|
rpcClient *rpc.Client
|
|
|
|
rpcReady chan struct{}
|
2016-12-02 18:33:39 +00:00
|
|
|
router *mux.Router
|
2016-12-05 15:24:41 +00:00
|
|
|
|
|
|
|
listener net.Listener
|
2016-12-09 19:54:46 +00:00
|
|
|
server *http.Server
|
2016-12-05 15:24:41 +00:00
|
|
|
|
2016-12-15 13:07:19 +00:00
|
|
|
shutdownLock sync.Mutex
|
|
|
|
shutdown bool
|
|
|
|
wg sync.WaitGroup
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type route struct {
|
|
|
|
Name string
|
|
|
|
Method string
|
|
|
|
Pattern string
|
|
|
|
HandlerFunc http.HandlerFunc
|
|
|
|
}
|
|
|
|
|
|
|
|
type errorResp struct {
|
|
|
|
Code int `json:"code"`
|
|
|
|
Message string `json:"message"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e errorResp) Error() string {
|
|
|
|
return e.Message
|
|
|
|
}
|
|
|
|
|
|
|
|
type versionResp struct {
|
|
|
|
Version string `json:"version"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type pinResp struct {
|
|
|
|
Pinned string `json:"pinned"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type unpinResp struct {
|
|
|
|
Unpinned string `json:"unpinned"`
|
|
|
|
}
|
|
|
|
|
2016-12-19 17:35:24 +00:00
|
|
|
type statusInfo struct {
|
2017-01-24 00:09:27 +00:00
|
|
|
IPFS string `json:"ipfs"`
|
|
|
|
Error string `json:"error,omitempty"`
|
2016-12-19 17:35:24 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 18:08:46 +00:00
|
|
|
type statusCidResp struct {
|
2016-12-19 17:35:24 +00:00
|
|
|
Cid string `json:"cid"`
|
|
|
|
Status map[string]statusInfo `json:"status"`
|
2016-12-05 14:30:11 +00:00
|
|
|
}
|
|
|
|
|
2017-01-24 15:19:23 +00:00
|
|
|
type idResp struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
PublicKey string `json:"public_key"`
|
|
|
|
Addresses []string `json:"addresses"`
|
|
|
|
Version string `json:"version"`
|
|
|
|
Commit string `json:"commit"`
|
|
|
|
RPCProtocolVersion string `json:"rpc_protocol_version"`
|
|
|
|
}
|
|
|
|
|
2016-12-15 18:08:46 +00:00
|
|
|
type statusResp []statusCidResp
|
2016-12-05 14:30:11 +00:00
|
|
|
|
2016-12-16 21:00:08 +00:00
|
|
|
// NewRESTAPI creates a new object which is ready to be
|
2016-12-02 18:33:39 +00:00
|
|
|
// started.
|
2016-12-16 21:00:08 +00:00
|
|
|
func NewRESTAPI(cfg *Config) (*RESTAPI, error) {
|
2016-12-09 19:54:46 +00:00
|
|
|
ctx := context.Background()
|
2017-01-23 17:38:59 +00:00
|
|
|
|
|
|
|
listenAddr, err := cfg.APIAddr.ValueForProtocol(ma.P_IP4)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
listenPortStr, err := cfg.APIAddr.ValueForProtocol(ma.P_TCP)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
listenPort, err := strconv.Atoi(listenPortStr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-12-05 15:24:41 +00:00
|
|
|
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d",
|
2017-01-23 17:38:59 +00:00
|
|
|
listenAddr, listenPort))
|
2016-12-05 15:24:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-12-09 19:54:46 +00:00
|
|
|
router := mux.NewRouter().StrictSlash(true)
|
2016-12-22 10:31:09 +00:00
|
|
|
s := &http.Server{
|
|
|
|
ReadTimeout: RESTAPIServerReadTimeout,
|
|
|
|
WriteTimeout: RESTAPIServerWriteTimeout,
|
|
|
|
//IdleTimeout: RESTAPIServerIdleTimeout, // TODO: Go 1.8
|
|
|
|
Handler: router,
|
|
|
|
}
|
2016-12-09 19:54:46 +00:00
|
|
|
s.SetKeepAlivesEnabled(true) // A reminder that this can be changed
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
api := &RESTAPI{
|
2016-12-02 18:33:39 +00:00
|
|
|
ctx: ctx,
|
2017-01-23 22:58:04 +00:00
|
|
|
apiAddr: cfg.APIAddr,
|
2017-01-23 17:38:59 +00:00
|
|
|
listenAddr: listenAddr,
|
|
|
|
listenPort: listenPort,
|
2016-12-05 15:24:41 +00:00
|
|
|
listener: l,
|
2016-12-09 19:54:46 +00:00
|
|
|
server: s,
|
2016-12-23 18:35:37 +00:00
|
|
|
rpcReady: make(chan struct{}, 1),
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, route := range api.routes() {
|
|
|
|
router.
|
|
|
|
Methods(route.Method).
|
|
|
|
Path(route.Pattern).
|
|
|
|
Name(route.Name).
|
|
|
|
Handler(route.HandlerFunc)
|
|
|
|
}
|
|
|
|
|
|
|
|
api.router = router
|
2016-12-15 13:07:19 +00:00
|
|
|
api.run()
|
2016-12-02 18:33:39 +00:00
|
|
|
return api, nil
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) routes() []route {
|
2016-12-02 18:33:39 +00:00
|
|
|
return []route{
|
2017-01-24 15:19:23 +00:00
|
|
|
{
|
|
|
|
"ID",
|
|
|
|
"GET",
|
|
|
|
"/id",
|
|
|
|
api.idHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-02 18:33:39 +00:00
|
|
|
"Members",
|
|
|
|
"GET",
|
|
|
|
"/members",
|
|
|
|
api.memberListHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-02 18:33:39 +00:00
|
|
|
"Pins",
|
|
|
|
"GET",
|
|
|
|
"/pins",
|
|
|
|
api.pinListHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-02 18:33:39 +00:00
|
|
|
"Version",
|
|
|
|
"GET",
|
|
|
|
"/version",
|
|
|
|
api.versionHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-02 18:33:39 +00:00
|
|
|
"Pin",
|
|
|
|
"POST",
|
|
|
|
"/pins/{hash}",
|
|
|
|
api.pinHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-02 18:33:39 +00:00
|
|
|
"Unpin",
|
|
|
|
"DELETE",
|
|
|
|
"/pins/{hash}",
|
|
|
|
api.unpinHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-15 18:08:46 +00:00
|
|
|
"Status",
|
|
|
|
"GET",
|
|
|
|
"/status",
|
|
|
|
api.statusHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-15 18:08:46 +00:00
|
|
|
"StatusCid",
|
|
|
|
"GET",
|
|
|
|
"/status/{hash}",
|
|
|
|
api.statusCidHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-15 18:08:46 +00:00
|
|
|
"Sync",
|
|
|
|
"POST",
|
|
|
|
"/status",
|
|
|
|
api.syncHandler,
|
|
|
|
},
|
2017-01-24 11:39:08 +00:00
|
|
|
{
|
2016-12-15 18:08:46 +00:00
|
|
|
"SyncCid",
|
|
|
|
"POST",
|
|
|
|
"/status/{hash}",
|
|
|
|
api.syncCidHandler,
|
|
|
|
},
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) run() {
|
2016-12-15 13:07:19 +00:00
|
|
|
api.wg.Add(1)
|
2016-12-02 18:33:39 +00:00
|
|
|
go func() {
|
2016-12-15 13:07:19 +00:00
|
|
|
defer api.wg.Done()
|
2016-12-09 19:54:46 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
api.ctx = ctx
|
2016-12-23 18:35:37 +00:00
|
|
|
|
|
|
|
<-api.rpcReady
|
|
|
|
|
2017-01-23 22:58:04 +00:00
|
|
|
logger.Infof("REST API: %s", api.apiAddr)
|
2016-12-09 19:54:46 +00:00
|
|
|
err := api.server.Serve(api.listener)
|
2016-12-15 13:07:19 +00:00
|
|
|
if err != nil && !strings.Contains(err.Error(), "closed network connection") {
|
|
|
|
logger.Error(err)
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown stops any API listeners.
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) Shutdown() error {
|
2016-12-15 13:07:19 +00:00
|
|
|
api.shutdownLock.Lock()
|
|
|
|
defer api.shutdownLock.Unlock()
|
|
|
|
|
|
|
|
if api.shutdown {
|
|
|
|
logger.Debug("already shutdown")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-15 13:19:41 +00:00
|
|
|
logger.Info("stopping Cluster API")
|
2016-12-15 13:07:19 +00:00
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
close(api.rpcReady)
|
2016-12-15 13:07:19 +00:00
|
|
|
// Cancel any outstanding ops
|
2016-12-09 19:54:46 +00:00
|
|
|
api.server.SetKeepAlivesEnabled(false)
|
2016-12-05 15:24:41 +00:00
|
|
|
api.listener.Close()
|
2016-12-15 13:07:19 +00:00
|
|
|
|
|
|
|
api.wg.Wait()
|
|
|
|
api.shutdown = true
|
2016-12-02 18:33:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
// SetClient makes the component ready to perform RPC
|
|
|
|
// requests.
|
|
|
|
func (api *RESTAPI) SetClient(c *rpc.Client) {
|
|
|
|
api.rpcClient = c
|
|
|
|
api.rpcReady <- struct{}{}
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
|
2017-01-24 15:19:23 +00:00
|
|
|
func (api *RESTAPI) idHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
idObj := ID{}
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"ID",
|
|
|
|
struct{}{},
|
|
|
|
&idObj)
|
|
|
|
if checkRPCErr(w, err) {
|
|
|
|
pubKey := ""
|
|
|
|
if idObj.PublicKey != nil {
|
|
|
|
keyBytes, err := idObj.PublicKey.Bytes()
|
|
|
|
if err != nil {
|
|
|
|
pubKey = base64.StdEncoding.EncodeToString(keyBytes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
addrs := make([]string, len(idObj.Addresses), len(idObj.Addresses))
|
|
|
|
for i, a := range idObj.Addresses {
|
|
|
|
addrs[i] = a.String()
|
|
|
|
}
|
|
|
|
idResponse := idResp{
|
|
|
|
ID: idObj.ID.Pretty(),
|
|
|
|
PublicKey: pubKey,
|
|
|
|
Addresses: addrs,
|
|
|
|
Version: idObj.Version,
|
|
|
|
Commit: idObj.Commit,
|
|
|
|
RPCProtocolVersion: string(idObj.RPCProtocolVersion),
|
|
|
|
}
|
|
|
|
sendJSONResponse(w, 200, idResponse)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) versionHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-23 18:35:37 +00:00
|
|
|
var v string
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"Version",
|
|
|
|
struct{}{},
|
|
|
|
&v)
|
|
|
|
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-02 18:33:39 +00:00
|
|
|
sendJSONResponse(w, 200, versionResp{v})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) memberListHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-23 18:35:37 +00:00
|
|
|
var peers []peer.ID
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"MemberList",
|
|
|
|
struct{}{},
|
|
|
|
&peers)
|
|
|
|
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-02 18:33:39 +00:00
|
|
|
var strPeers []string
|
2016-12-23 18:35:37 +00:00
|
|
|
for _, p := range peers {
|
2016-12-02 18:33:39 +00:00
|
|
|
strPeers = append(strPeers, p.Pretty())
|
|
|
|
}
|
|
|
|
sendJSONResponse(w, 200, strPeers)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) pinHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-15 18:08:46 +00:00
|
|
|
if c := parseCidOrError(w, r); c != nil {
|
2016-12-23 18:35:37 +00:00
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"Pin",
|
|
|
|
c,
|
|
|
|
&struct{}{})
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-15 18:08:46 +00:00
|
|
|
sendAcceptedResponse(w)
|
|
|
|
}
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
2016-12-02 18:33:39 +00:00
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) unpinHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-15 18:08:46 +00:00
|
|
|
if c := parseCidOrError(w, r); c != nil {
|
2016-12-23 18:35:37 +00:00
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"Unpin",
|
|
|
|
c,
|
|
|
|
&struct{}{})
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-15 18:08:46 +00:00
|
|
|
sendAcceptedResponse(w)
|
|
|
|
}
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) pinListHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-23 18:35:37 +00:00
|
|
|
var pins []string
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"PinList",
|
|
|
|
struct{}{},
|
|
|
|
&pins)
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-23 18:35:37 +00:00
|
|
|
sendJSONResponse(w, 200, pins)
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) statusHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-23 18:35:37 +00:00
|
|
|
var pinInfos []GlobalPinInfo
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"Status",
|
|
|
|
struct{}{},
|
|
|
|
&pinInfos)
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-23 18:35:37 +00:00
|
|
|
sendStatusResponse(w, http.StatusOK, pinInfos)
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) statusCidHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-15 18:08:46 +00:00
|
|
|
if c := parseCidOrError(w, r); c != nil {
|
2016-12-23 18:35:37 +00:00
|
|
|
var pinInfo GlobalPinInfo
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"StatusCid",
|
|
|
|
c,
|
|
|
|
&pinInfo)
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-23 18:35:37 +00:00
|
|
|
sendStatusCidResponse(w, http.StatusOK, pinInfo)
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) syncHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-23 18:35:37 +00:00
|
|
|
var pinInfos []GlobalPinInfo
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"GlobalSync",
|
|
|
|
struct{}{},
|
|
|
|
&pinInfos)
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-23 18:35:37 +00:00
|
|
|
sendStatusResponse(w, http.StatusAccepted, pinInfos)
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 18:14:45 +00:00
|
|
|
func (api *RESTAPI) syncCidHandler(w http.ResponseWriter, r *http.Request) {
|
2016-12-15 18:08:46 +00:00
|
|
|
if c := parseCidOrError(w, r); c != nil {
|
2016-12-23 18:35:37 +00:00
|
|
|
var pinInfo GlobalPinInfo
|
|
|
|
err := api.rpcClient.Call("",
|
|
|
|
"Cluster",
|
|
|
|
"GlobalSyncCid",
|
|
|
|
c,
|
|
|
|
&pinInfo)
|
2017-01-24 15:19:23 +00:00
|
|
|
if checkRPCErr(w, err) {
|
2016-12-23 18:35:37 +00:00
|
|
|
sendStatusCidResponse(w, http.StatusOK, pinInfo)
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
2016-12-02 18:33:39 +00:00
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
func parseCidOrError(w http.ResponseWriter, r *http.Request) *CidArg {
|
2016-12-15 18:08:46 +00:00
|
|
|
vars := mux.Vars(r)
|
|
|
|
hash := vars["hash"]
|
2016-12-23 18:35:37 +00:00
|
|
|
_, err := cid.Decode(hash)
|
2016-12-15 18:08:46 +00:00
|
|
|
if err != nil {
|
|
|
|
sendErrorResponse(w, 400, "error decoding Cid: "+err.Error())
|
|
|
|
return nil
|
|
|
|
}
|
2016-12-23 18:35:37 +00:00
|
|
|
return &CidArg{hash}
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
// checkRPCErr takes care of returning standard error responses if we
|
|
|
|
// pass an error to it. It returns true when everythings OK (no error
|
|
|
|
// was handled), or false otherwise.
|
2017-01-24 15:19:23 +00:00
|
|
|
func checkRPCErr(w http.ResponseWriter, err error) bool {
|
2016-12-23 18:35:37 +00:00
|
|
|
if err != nil {
|
2016-12-02 18:33:39 +00:00
|
|
|
sendErrorResponse(w, 500, err.Error())
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func sendEmptyResponse(w http.ResponseWriter) {
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:28:46 +00:00
|
|
|
func sendAcceptedResponse(w http.ResponseWriter) {
|
|
|
|
w.WriteHeader(http.StatusAccepted)
|
|
|
|
}
|
|
|
|
|
2016-12-02 18:33:39 +00:00
|
|
|
func sendJSONResponse(w http.ResponseWriter, code int, resp interface{}) {
|
|
|
|
w.WriteHeader(code)
|
|
|
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func sendErrorResponse(w http.ResponseWriter, code int, msg string) {
|
|
|
|
errorResp := errorResp{code, msg}
|
2016-12-15 13:19:41 +00:00
|
|
|
logger.Errorf("sending error response: %d: %s", code, msg)
|
2016-12-02 18:33:39 +00:00
|
|
|
sendJSONResponse(w, code, errorResp)
|
|
|
|
}
|
2016-12-15 18:08:46 +00:00
|
|
|
|
2016-12-19 17:35:24 +00:00
|
|
|
func transformPinToStatusCid(p GlobalPinInfo) statusCidResp {
|
|
|
|
s := statusCidResp{}
|
|
|
|
s.Cid = p.Cid.String()
|
|
|
|
s.Status = make(map[string]statusInfo)
|
|
|
|
for k, v := range p.Status {
|
|
|
|
s.Status[k.Pretty()] = statusInfo{
|
2017-01-24 00:09:27 +00:00
|
|
|
IPFS: v.IPFS.String(),
|
|
|
|
Error: v.Error,
|
2016-12-19 17:35:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
func sendStatusResponse(w http.ResponseWriter, code int, data []GlobalPinInfo) {
|
2016-12-15 18:08:46 +00:00
|
|
|
pins := make(statusResp, 0, len(data))
|
2016-12-19 17:35:24 +00:00
|
|
|
|
2016-12-15 18:08:46 +00:00
|
|
|
for _, d := range data {
|
2016-12-19 17:35:24 +00:00
|
|
|
pins = append(pins, transformPinToStatusCid(d))
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
2016-12-20 18:51:13 +00:00
|
|
|
sendJSONResponse(w, code, pins)
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-23 18:35:37 +00:00
|
|
|
func sendStatusCidResponse(w http.ResponseWriter, code int, data GlobalPinInfo) {
|
2016-12-19 17:35:24 +00:00
|
|
|
st := transformPinToStatusCid(data)
|
2016-12-20 18:51:13 +00:00
|
|
|
sendJSONResponse(w, code, st)
|
2016-12-15 18:08:46 +00:00
|
|
|
}
|