ipfs-cluster/ipfscluster-server/main.go
Hector Sanjuan 805b867651 Use go-libp2p-rpc. Tests updated.
The former RPC stuff had become a monster, really hard to have an overview
of the RPC api capabilities and with lots of magic.

go-libp2p-rpc allows to have a clearly defined RPC api which
shows which methods every component can use. A component to perform
remote requests, and the convoluted LeaderRPC, BroadcastRPC methods are
no longer necessary.

Things are much simpler now, less goroutines are needed, the central channel
handling bottleneck is gone, RPC requests are very streamlined in form.

In the future, it would be inmediate to have components living on different
libp2p hosts and it is way clearer how to plug into the advanced cluster rpc
api.

License: MIT
Signed-off-by: Hector Sanjuan <hector@protocol.ai>
2016-12-27 18:19:54 +01:00

189 lines
4.6 KiB
Go

package main
import (
"flag"
"fmt"
"os"
"os/signal"
"os/user"
"path/filepath"
logging "github.com/ipfs/go-log"
ipfscluster "github.com/ipfs/ipfs-cluster"
)
// ProgramName of this application
const programName = `ipfscluster-server`
// Description provides a short summary of the functionality of this tool
var Description = fmt.Sprintf(`
%s runs an IPFS Cluster member (version %s).
A member is a server node which participates in the cluster consensus, follows
a distributed log of pinning and unpinning operations and manages pinning
operations to a configured IPFS daemon.
This server also provides an API for cluster management, an IPFS Proxy API which
forwards requests to IPFS and a number of components for internal communication
using LibP2P.
%s needs a valid configuration to run. This configuration is
independent from IPFS and includes its own LibP2P key-pair. It can be
initialized with -init and its default location is
~/%s/%s.
For feedback, bug reports or any additional information, visit
https://github.com/ipfs/ipfs-cluster.
`,
programName,
ipfscluster.Version,
programName,
DefaultPath,
DefaultConfigFile)
// Default location for the configurations and data
var (
// DefaultPath is initialized to something like ~/.ipfs-cluster/server.json
// and holds all the ipfs-cluster data
DefaultPath = ".ipfs-cluster"
// The name of the configuration file inside DefaultPath
DefaultConfigFile = "server.json"
// The name of the data folder inside DefaultPath
DefaultDataFolder = "data"
)
var (
configPath string
dataPath string
)
// Command line flags
var (
initFlag bool
configFlag string
debugFlag bool
logLevelFlag string
versionFlag bool
)
func init() {
if path := os.Getenv("IPFSCLUSTER_PATH"); path != "" {
DefaultPath = path
} else {
usr, err := user.Current()
if err != nil {
panic("cannot guess the current user")
}
DefaultPath = filepath.Join(
usr.HomeDir,
".ipfs-cluster")
}
configPath = filepath.Join(DefaultPath, DefaultConfigFile)
dataPath = filepath.Join(DefaultPath, DefaultDataFolder)
flag.Usage = func() {
out("Usage: %s [options]\n", programName)
out(Description)
out("Options:\n")
flag.PrintDefaults()
out("\n")
}
flag.BoolVar(&initFlag, "init", false,
"create a default configuration and exit")
flag.StringVar(&configFlag, "config", configPath,
"path to the ipfscluster-server configuration file")
flag.BoolVar(&debugFlag, "debug", false,
"enable full debug logs of ipfs cluster and consensus layers")
flag.StringVar(&logLevelFlag, "loglevel", "info",
"set the loglevel [critical, error, warning, notice, info, debug]")
flag.BoolVar(&versionFlag, "version", false,
fmt.Sprintf("display %s version", programName))
flag.Parse()
configPath = configFlag
setupLogging()
setupDebug()
if versionFlag {
fmt.Println(ipfscluster.Version)
}
if initFlag {
err := initConfig()
checkErr("creating configuration", err)
os.Exit(0)
}
}
func out(m string, a ...interface{}) {
fmt.Fprintf(os.Stderr, m, a...)
}
func main() {
// Catch SIGINT as a way to exit
signalChan := make(chan os.Signal)
signal.Notify(signalChan, os.Interrupt)
cfg, err := loadConfig()
checkErr("loading configuration", err)
api, err := ipfscluster.NewRESTAPI(cfg)
checkErr("creating REST API component", err)
proxy, err := ipfscluster.NewIPFSHTTPConnector(cfg)
checkErr("creating IPFS Connector component", err)
state := ipfscluster.NewMapState()
tracker := ipfscluster.NewMapPinTracker(cfg)
cluster, err := ipfscluster.NewCluster(cfg,
api, proxy, state, tracker)
checkErr("creating IPFS Cluster", err)
// Wait until we are told to exit by a signal
<-signalChan
err = cluster.Shutdown()
checkErr("shutting down IPFS Cluster", err)
os.Exit(0)
}
func checkErr(doing string, err error) {
if err != nil {
out("error %s: %s\n", doing, err)
os.Exit(1)
}
}
func setupLogging() {
logging.SetLogLevel("cluster", logLevelFlag)
logging.SetLogLevel("libp2p-rpc", logLevelFlag)
}
func setupDebug() {
if debugFlag {
logging.SetLogLevel("cluster", "debug")
logging.SetLogLevel("libp2p-raft", "debug")
logging.SetLogLevel("libp2p-rpc", "debug")
ipfscluster.SilentRaft = false
}
}
func initConfig() error {
if _, err := os.Stat(configPath); err == nil {
return fmt.Errorf("%s exists. Try deleting it first", configPath)
}
cfg, err := ipfscluster.NewDefaultConfig()
if err != nil {
return err
}
cfg.ConsensusDataFolder = dataPath
err = os.MkdirAll(DefaultPath, 0700)
err = cfg.Save(configPath)
if err != nil {
return err
}
out("%s configuration written to %s\n",
programName, configPath)
return nil
}
func loadConfig() (*ipfscluster.Config, error) {
return ipfscluster.LoadConfig(configPath)
}