ipfs-cluster/api/types.go
Hector Sanjuan 1e87fccf0e
Merge pull request #257 from te0d/feat/add-peer-identifier
Added Hostname Property to Configuration
2017-12-04 14:25:49 +01:00

482 lines
13 KiB
Go

// Package api holds declarations for types used in ipfs-cluster APIs to make
// them re-usable across differen tools. This include RPC API "Serial[izable]"
// versions for types. The Go API uses natives types, while RPC API,
// REST APIs etc use serializable types (i.e. json format). Converstion methods
// exists between types.
//
// Note that all conversion methods ignore any parsing errors. All values must
// be validated first before initializing any of the types defined here.
package api
import (
"time"
cid "github.com/ipfs/go-cid"
peer "github.com/libp2p/go-libp2p-peer"
protocol "github.com/libp2p/go-libp2p-protocol"
ma "github.com/multiformats/go-multiaddr"
)
// TrackerStatus values
const (
// IPFSStatus should never take this value
TrackerStatusBug = iota
// The cluster node is offline or not responding
TrackerStatusClusterError
// An error occurred pinning
TrackerStatusPinError
// An error occurred unpinning
TrackerStatusUnpinError
// The IPFS daemon has pinned the item
TrackerStatusPinned
// The IPFS daemon is currently pinning the item
TrackerStatusPinning
// The IPFS daemon is currently unpinning the item
TrackerStatusUnpinning
// The IPFS daemon is not pinning the item
TrackerStatusUnpinned
// The IPFS deamon is not pinning the item but it is being tracked
TrackerStatusRemote
)
// TrackerStatus represents the status of a tracked Cid in the PinTracker
type TrackerStatus int
var trackerStatusString = map[TrackerStatus]string{
TrackerStatusBug: "bug",
TrackerStatusClusterError: "cluster_error",
TrackerStatusPinError: "pin_error",
TrackerStatusUnpinError: "unpin_error",
TrackerStatusPinned: "pinned",
TrackerStatusPinning: "pinning",
TrackerStatusUnpinning: "unpinning",
TrackerStatusUnpinned: "unpinned",
TrackerStatusRemote: "remote",
}
// String converts a TrackerStatus into a readable string.
func (st TrackerStatus) String() string {
return trackerStatusString[st]
}
// TrackerStatusFromString parses a string and returns the matching
// TrackerStatus value.
func TrackerStatusFromString(str string) TrackerStatus {
for k, v := range trackerStatusString {
if v == str {
return k
}
}
return TrackerStatusBug
}
// IPFSPinStatus values
const (
IPFSPinStatusBug = iota
IPFSPinStatusError
IPFSPinStatusDirect
IPFSPinStatusRecursive
IPFSPinStatusIndirect
IPFSPinStatusUnpinned
)
// IPFSPinStatus represents the status of a pin in IPFS (direct, recursive etc.)
type IPFSPinStatus int
// IPFSPinStatusFromString parses a string and returns the matching
// IPFSPinStatus.
func IPFSPinStatusFromString(t string) IPFSPinStatus {
// TODO: This is only used in the http_connector to parse
// ipfs-daemon-returned values. Maybe it should be extended.
switch {
case t == "indirect":
return IPFSPinStatusIndirect
case t == "direct":
return IPFSPinStatusDirect
case t == "recursive":
return IPFSPinStatusRecursive
default:
return IPFSPinStatusBug
}
}
// IsPinned returns true if the status is Direct or Recursive
func (ips IPFSPinStatus) IsPinned() bool {
return ips == IPFSPinStatusDirect || ips == IPFSPinStatusRecursive
}
// GlobalPinInfo contains cluster-wide status information about a tracked Cid,
// indexed by cluster peer.
type GlobalPinInfo struct {
Cid *cid.Cid
PeerMap map[peer.ID]PinInfo
}
// GlobalPinInfoSerial is the serializable version of GlobalPinInfo.
type GlobalPinInfoSerial struct {
Cid string `json:"cid"`
PeerMap map[string]PinInfoSerial `json:"peer_map"`
}
// ToSerial converts a GlobalPinInfo to its serializable version.
func (gpi GlobalPinInfo) ToSerial() GlobalPinInfoSerial {
s := GlobalPinInfoSerial{}
s.Cid = gpi.Cid.String()
s.PeerMap = make(map[string]PinInfoSerial)
for k, v := range gpi.PeerMap {
s.PeerMap[peer.IDB58Encode(k)] = v.ToSerial()
}
return s
}
// ToGlobalPinInfo converts a GlobalPinInfoSerial to its native version.
func (gpis GlobalPinInfoSerial) ToGlobalPinInfo() GlobalPinInfo {
c, _ := cid.Decode(gpis.Cid)
gpi := GlobalPinInfo{
Cid: c,
PeerMap: make(map[peer.ID]PinInfo),
}
for k, v := range gpis.PeerMap {
p, _ := peer.IDB58Decode(k)
gpi.PeerMap[p] = v.ToPinInfo()
}
return gpi
}
// PinInfo holds information about local pins.
type PinInfo struct {
Cid *cid.Cid
Peer peer.ID
Status TrackerStatus
TS time.Time
Error string
}
// PinInfoSerial is a serializable version of PinInfo.
// information is marked as
type PinInfoSerial struct {
Cid string `json:"cid"`
Peer string `json:"peer"`
Status string `json:"status"`
TS string `json:"timestamp"`
Error string `json:"error"`
}
// ToSerial converts a PinInfo to its serializable version.
func (pi PinInfo) ToSerial() PinInfoSerial {
return PinInfoSerial{
Cid: pi.Cid.String(),
Peer: peer.IDB58Encode(pi.Peer),
Status: pi.Status.String(),
TS: pi.TS.UTC().Format(time.RFC3339),
Error: pi.Error,
}
}
// ToPinInfo converts a PinInfoSerial to its native version.
func (pis PinInfoSerial) ToPinInfo() PinInfo {
c, _ := cid.Decode(pis.Cid)
p, _ := peer.IDB58Decode(pis.Peer)
ts, _ := time.Parse(time.RFC3339, pis.TS)
return PinInfo{
Cid: c,
Peer: p,
Status: TrackerStatusFromString(pis.Status),
TS: ts,
Error: pis.Error,
}
}
// Version holds version information
type Version struct {
Version string `json:"Version"`
}
// IPFSID is used to store information about the underlying IPFS daemon
type IPFSID struct {
ID peer.ID
Addresses []ma.Multiaddr
Error string
}
// IPFSIDSerial is the serializable IPFSID for RPC requests
type IPFSIDSerial struct {
ID string `json:"id"`
Addresses MultiaddrsSerial `json:"addresses"`
Error string `json:"error"`
}
// ToSerial converts IPFSID to a go serializable object
func (id *IPFSID) ToSerial() IPFSIDSerial {
return IPFSIDSerial{
ID: peer.IDB58Encode(id.ID),
Addresses: MultiaddrsToSerial(id.Addresses),
Error: id.Error,
}
}
// ToIPFSID converts an IPFSIDSerial to IPFSID
func (ids *IPFSIDSerial) ToIPFSID() IPFSID {
id := IPFSID{}
if pID, err := peer.IDB58Decode(ids.ID); err == nil {
id.ID = pID
}
id.Addresses = ids.Addresses.ToMultiaddrs()
id.Error = ids.Error
return id
}
// ID holds information about the Cluster peer
type ID struct {
ID peer.ID
Addresses []ma.Multiaddr
ClusterPeers []peer.ID
ClusterPeersAddresses []ma.Multiaddr
Version string
Commit string
RPCProtocolVersion protocol.ID
Error string
IPFS IPFSID
Peername string
//PublicKey crypto.PubKey
}
// IDSerial is the serializable ID counterpart for RPC requests
type IDSerial struct {
ID string `json:"id"`
Addresses MultiaddrsSerial `json:"addresses"`
ClusterPeers []string `json:"cluster_peers"`
ClusterPeersAddresses MultiaddrsSerial `json:"cluster_peers_addresses"`
Version string `json:"version"`
Commit string `json:"commit"`
RPCProtocolVersion string `json:"rpc_protocol_version"`
Error string `json:"error"`
IPFS IPFSIDSerial `json:"ipfs"`
Peername string `json:"peername"`
//PublicKey []byte
}
// ToSerial converts an ID to its Go-serializable version
func (id ID) ToSerial() IDSerial {
//var pkey []byte
//if id.PublicKey != nil {
// pkey, _ = id.PublicKey.Bytes()
//}
peers := make([]string, len(id.ClusterPeers), len(id.ClusterPeers))
for i, p := range id.ClusterPeers {
peers[i] = peer.IDB58Encode(p)
}
return IDSerial{
ID: peer.IDB58Encode(id.ID),
//PublicKey: pkey,
Addresses: MultiaddrsToSerial(id.Addresses),
ClusterPeers: peers,
ClusterPeersAddresses: MultiaddrsToSerial(id.ClusterPeersAddresses),
Version: id.Version,
Commit: id.Commit,
RPCProtocolVersion: string(id.RPCProtocolVersion),
Error: id.Error,
IPFS: id.IPFS.ToSerial(),
Peername: id.Peername,
}
}
// ToID converts an IDSerial object to ID.
// It will ignore any errors when parsing the fields.
func (ids IDSerial) ToID() ID {
id := ID{}
p, _ := peer.IDB58Decode(ids.ID)
id.ID = p
//if pkey, err := crypto.UnmarshalPublicKey(ids.PublicKey); err == nil {
// id.PublicKey = pkey
//}
peers := make([]peer.ID, len(ids.ClusterPeers), len(ids.ClusterPeers))
for i, p := range ids.ClusterPeers {
peers[i], _ = peer.IDB58Decode(p)
}
id.Addresses = ids.Addresses.ToMultiaddrs()
id.ClusterPeers = peers
id.ClusterPeersAddresses = ids.ClusterPeersAddresses.ToMultiaddrs()
id.Version = ids.Version
id.Commit = ids.Commit
id.RPCProtocolVersion = protocol.ID(ids.RPCProtocolVersion)
id.Error = ids.Error
id.IPFS = ids.IPFS.ToIPFSID()
id.Peername = ids.Peername
return id
}
// MultiaddrSerial is a Multiaddress in a serializable form
type MultiaddrSerial string
// MultiaddrsSerial is an array of Multiaddresses in serializable form
type MultiaddrsSerial []MultiaddrSerial
// MultiaddrToSerial converts a Multiaddress to its serializable form
func MultiaddrToSerial(addr ma.Multiaddr) MultiaddrSerial {
return MultiaddrSerial(addr.String())
}
// ToMultiaddr converts a serializable Multiaddress to its original type.
// All errors are ignored.
func (addrS MultiaddrSerial) ToMultiaddr() ma.Multiaddr {
a, _ := ma.NewMultiaddr(string(addrS))
return a
}
// MultiaddrsToSerial converts a slice of Multiaddresses to its
// serializable form.
func MultiaddrsToSerial(addrs []ma.Multiaddr) MultiaddrsSerial {
addrsS := make([]MultiaddrSerial, len(addrs), len(addrs))
for i, a := range addrs {
addrsS[i] = MultiaddrToSerial(a)
}
return addrsS
}
// ToMultiaddrs converts MultiaddrsSerial back to a slice of Multiaddresses
func (addrsS MultiaddrsSerial) ToMultiaddrs() []ma.Multiaddr {
addrs := make([]ma.Multiaddr, len(addrsS), len(addrsS))
for i, addrS := range addrsS {
addrs[i] = addrS.ToMultiaddr()
}
return addrs
}
// Pin is an argument that carries a Cid. It may carry more things in the
// future.
type Pin struct {
Cid *cid.Cid
Name string
Allocations []peer.ID
ReplicationFactor int
}
// PinCid is a shorcut to create a Pin only with a Cid.
func PinCid(c *cid.Cid) Pin {
return Pin{
Cid: c,
}
}
// PinSerial is a serializable version of Pin
type PinSerial struct {
Cid string `json:"cid"`
Name string `json:"name"`
Allocations []string `json:"allocations"`
Everywhere bool `json:"everywhere,omitempty"` // legacy
ReplicationFactor int `json:"replication_factor"`
}
// ToSerial converts a Pin to PinSerial.
func (pin Pin) ToSerial() PinSerial {
lenAllocs := len(pin.Allocations)
allocs := make([]string, lenAllocs, lenAllocs)
for i, p := range pin.Allocations {
allocs[i] = peer.IDB58Encode(p)
}
return PinSerial{
Cid: pin.Cid.String(),
Name: pin.Name,
Allocations: allocs,
ReplicationFactor: pin.ReplicationFactor,
}
}
// ToPin converts a PinSerial to its native form.
func (pins PinSerial) ToPin() Pin {
c, _ := cid.Decode(pins.Cid)
lenAllocs := len(pins.Allocations)
allocs := make([]peer.ID, lenAllocs, lenAllocs)
for i, p := range pins.Allocations {
allocs[i], _ = peer.IDB58Decode(p)
}
// legacy format management
if pins.ReplicationFactor == 0 && pins.Everywhere {
pins.ReplicationFactor = -1
}
return Pin{
Cid: c,
Name: pins.Name,
Allocations: allocs,
ReplicationFactor: pins.ReplicationFactor,
}
}
// Metric transports information about a peer.ID. It is used to decide
// pin allocations by a PinAllocator. IPFS cluster is agnostic to
// the Value, which should be interpreted by the PinAllocator.
type Metric struct {
Name string
Peer peer.ID // filled-in by Cluster.
Value string
Expire string // RFC3339Nano
Valid bool // if the metric is not valid it will be discarded
}
// SetTTL sets Metric to expire after the given seconds
func (m *Metric) SetTTL(seconds int) {
d := time.Duration(seconds) * time.Second
m.SetTTLDuration(d)
}
// SetTTLDuration sets Metric to expire after the given time.Duration
func (m *Metric) SetTTLDuration(d time.Duration) {
exp := time.Now().Add(d)
m.Expire = exp.UTC().Format(time.RFC3339Nano)
}
// GetTTL returns the time left before the Metric expires
func (m *Metric) GetTTL() time.Duration {
if m.Expire == "" {
return 0
}
exp, err := time.Parse(time.RFC3339Nano, m.Expire)
if err != nil {
panic(err)
}
return exp.Sub(time.Now())
}
// Expired returns if the Metric has expired
func (m *Metric) Expired() bool {
if m.Expire == "" {
return true
}
exp, err := time.Parse(time.RFC3339Nano, m.Expire)
if err != nil {
panic(err)
}
return time.Now().After(exp)
}
// Discard returns if the metric not valid or has expired
func (m *Metric) Discard() bool {
return !m.Valid || m.Expired()
}
// Alert carries alerting information about a peer. WIP.
type Alert struct {
Peer peer.ID
MetricName string
}
// Error can be used by APIs to return errors.
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
}
// Error implements the error interface and returns the error's message.
func (e Error) Error() string {
return e.Message
}