805b867651
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>
189 lines
4.6 KiB
Go
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)
|
|
}
|