diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a90bd610 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.a +*.jnilib +*.o +*.class + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +#misc +p2pclient/java/libp2pd.h +p2pclient/java/p2pd.h diff --git a/Makefile b/Makefile index 74f8ba84..bdf6ef00 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,36 @@ -bin: deps - go install ./... +SHELL := /bin/sh -gx: - go get github.com/whyrusleeping/gx - go get github.com/whyrusleeping/gx-go +include config.mk + +.PHONY : all java-daemon java-client go-client go-daemon deps gx clean +.DEFAULT_GOAL : go-daemon + +all: deps go-daemon go-client go-bindings java-daemon java-client + +java-daemon: + cd $(BDIR) && make $@ + +java-client: + cd $(BDIR) && make $@ + +go-bindings: + cd $(BDIR) && make $@ + +go-client: + cd $(CDIR) && go install ./... + +go-daemon: + cd $(DDIR) && go install ./... deps: gx gx --verbose install --global gx-go rewrite + +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go + +clean: + gx-go uw + cd $(BDIR) && make $@ + diff --git a/bindings/Makefile b/bindings/Makefile new file mode 100644 index 00000000..d4b24568 --- /dev/null +++ b/bindings/Makefile @@ -0,0 +1,46 @@ +SHELL := /bin/sh + +include ../config.mk + +CC = gcc +CFLAGS = -O2 -fPIC +LFLAGS = $(OS_LFLAGS) -shared + +JAVA_HOME = $(shell java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | sed 's/\s*java.home = //' | sed 's/\/jre//') +JAVA_INCLUDES = -I$(JAVA_HOME)/include/$(OS) -I$(JAVA_HOME)/include +CLASS_PATH = . +vpath %.class $(CLASS_PATH) + +DNAME = p2pd +CNAME = p2pc + +.PHONY : java-daemon java-client go-bindings clean + +java-daemon: lib$(DNAME).$(EXT) $(DNAME).class + +java-client: lib$(CNAME).$(EXT) $(CNAME).class + +go-bindings: java-$(DNAME).o java-$(CNAME).o go-p2p.a + $(CC) $(LFLAGS) -o libp2p.$(EXT) $^ + +lib%.$(EXT): java-%.o go-%.a + $(CC) $(LFLAGS) -o $@ $^ + +java-%.o: go-%.a + $(CC) $(CFLAGS) -c java/java-$*.c $(JAVA_INCLUDES) -o $@ + +go-p2p.a: + go build -o $@ -buildmode=c-archive main.go + +go-%.a: + go build -o $@ -buildmode=c-archive ../$*/main.go + +%.class: + cd java/examples && javac $*.java && mv $@ ../../$@ + +clean: + rm -f *.o \ + && rm -f *.a \ + && rm -f *.$(EXT) \ + && rm -f *.class \ + && rm -f *.h diff --git a/bindings/java/examples/p2pc.java b/bindings/java/examples/p2pc.java new file mode 100644 index 00000000..c4bb3332 --- /dev/null +++ b/bindings/java/examples/p2pc.java @@ -0,0 +1,21 @@ +public class p2pc { + private static final String NAME = "p2pc"; + public static native void startClient(String arg1); + static { + try { + + System.loadLibrary ( NAME ) ; + + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load.\n" + e); + System.exit(1); + } + } + public static void main(String[] args) { + String parsedArgs = NAME; + if( args.length > 0 ){ + parsedArgs += "|" + String.join("|", args); + } + startClient(parsedArgs); + } +} \ No newline at end of file diff --git a/bindings/java/examples/p2pd.java b/bindings/java/examples/p2pd.java new file mode 100644 index 00000000..4a55f918 --- /dev/null +++ b/bindings/java/examples/p2pd.java @@ -0,0 +1,22 @@ +public class p2pd { + private static final String NAME = "p2pd"; + public static native void startDaemon(String arg1); + public static native void stopDaemon(); + static { + try { + + System.loadLibrary ( NAME ) ; + + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load.\n" + e); + System.exit(1); + } + } + public static void main(String[] args) { + String parsedArgs = NAME; + if( args.length > 0 ){ + parsedArgs += "|" + String.join("|", args); + } + startDaemon(parsedArgs); + } +} \ No newline at end of file diff --git a/bindings/java/examples/peerDemo.sh b/bindings/java/examples/peerDemo.sh new file mode 100755 index 00000000..552865b3 --- /dev/null +++ b/bindings/java/examples/peerDemo.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +tmux new-session -d -s foo 'p2pd' +tmux split-window -v -t 0 'cd ../../ && java p2pd --sock=/tmp/p2pd2.sock' +tmux split-window -h 'sleep 1 && cd ../../ && java p2pc --pathc=/tmp/p2c2.sock --pathd=/tmp/p2pd2.sock --command=ListenForMessage' +tmux split-window -v -t 1 '/bin/bash' +tmux select-layout tile +tmux rename-window 'the dude abides' +tmux attach-session -d \ No newline at end of file diff --git a/bindings/java/java-p2pc.c b/bindings/java/java-p2pc.c new file mode 100644 index 00000000..ab7f8f17 --- /dev/null +++ b/bindings/java/java-p2pc.c @@ -0,0 +1,15 @@ +#include "java-p2pc.h" +#include "../go-p2pc.h" + +JNIEXPORT void JNICALL Java_p2pc_startClient (JNIEnv *jenv, jclass jcls, jstring jarg1){ + char *arg1 = (char *) 0 ; + (void)jenv; + (void)jcls; + arg1 = 0; + if (jarg1) { + arg1 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg1, 0); + if (!arg1) return ; + } + startClient(arg1); + if (arg1) (*jenv)->ReleaseStringUTFChars(jenv, jarg1, (const char *)arg1); +} \ No newline at end of file diff --git a/bindings/java/java-p2pc.h b/bindings/java/java-p2pc.h new file mode 100644 index 00000000..9ca71345 --- /dev/null +++ b/bindings/java/java-p2pc.h @@ -0,0 +1,14 @@ +#include + +#ifndef _Included_p2pc +#define _Included_p2pc +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL Java_p2pc_startClient (JNIEnv *, jclass, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/bindings/java/java-p2pd.c b/bindings/java/java-p2pd.c new file mode 100644 index 00000000..e13c0f6b --- /dev/null +++ b/bindings/java/java-p2pd.c @@ -0,0 +1,19 @@ +#include "java-p2pd.h" +#include "../go-p2pd.h" + +JNIEXPORT void JNICALL Java_p2pd_startDaemon (JNIEnv *jenv, jclass jcls, jstring jarg1){ + char *arg1 = (char *) 0 ; + (void)jenv; + (void)jcls; + arg1 = 0; + if (jarg1) { + arg1 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg1, 0); + if (!arg1) return ; + } + startDaemon(arg1); + if (arg1) (*jenv)->ReleaseStringUTFChars(jenv, jarg1, (const char *)arg1); +} + +JNIEXPORT void JNICALL Java_p2pd_stopDaemon (JNIEnv *jenv, jclass jcls){ + stopDaemon(); +} \ No newline at end of file diff --git a/bindings/java/java-p2pd.h b/bindings/java/java-p2pd.h new file mode 100644 index 00000000..9f72450a --- /dev/null +++ b/bindings/java/java-p2pd.h @@ -0,0 +1,16 @@ +#include + +#ifndef _Included_p2pd +#define _Included_p2pd +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL Java_p2pd_startDaemon (JNIEnv *, jclass, jstring); + +JNIEXPORT void JNICALL Java_p2pd_stopDaemon (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/bindings/main.go b/bindings/main.go new file mode 100644 index 00000000..4e0d9f80 --- /dev/null +++ b/bindings/main.go @@ -0,0 +1,29 @@ +package main + +import "C" +import ( + p2pd "github.com/libp2p/go-libp2p-daemon" + p2pc "github.com/libp2p/go-libp2p-daemon/p2pclient" +) + +func main() { +} + +//export startClient +func startClient(args *C.char) { + argsGoString := C.GoString(args) + config := p2pc.ProcessArgs(&argsGoString) + p2pc.Start(config) +} + +//export startDaemon +func startDaemon(args *C.char) { + argsGoString := C.GoString(args) + config := p2pd.ProcessArgs(&argsGoString) + p2pd.Start(config) +} + +//export stopDaemon +func stopDaemon() { + p2pd.Stop() +} diff --git a/config.mk b/config.mk new file mode 100644 index 00000000..7248e120 --- /dev/null +++ b/config.mk @@ -0,0 +1,13 @@ +OS = $(shell uname -s | tr '[:upper:]' '[:lower:]') + +ifeq ($(OS), linux) + EXT = so + OS_LFLAGS = +else ifeq ($(OS), darwin) + EXT = dylib + OS_LFLAGS = -mmacosx-version-min=$(shell defaults read loginwindow SystemVersionStampAsString) -framework CoreFoundation -framework Security +endif + +DDIR = p2pd +CDIR = p2pc +BDIR = bindings \ No newline at end of file diff --git a/daemon.go b/daemon.go index d0d13b20..3736bd94 100644 --- a/daemon.go +++ b/daemon.go @@ -4,7 +4,10 @@ import ( "context" "fmt" "net" + "os" + "os/signal" "sync" + "syscall" logging "github.com/ipfs/go-log" libp2p "github.com/libp2p/go-libp2p" @@ -54,6 +57,15 @@ func NewDaemon(ctx context.Context, path string, opts ...libp2p.Option) (*Daemon go d.listen() + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt, syscall.SIGTERM) + go func(ln net.Listener, c chan os.Signal) { + sig := <-c + log.Debugf("Caught signal %s: shutting down.\n", sig) + ln.Close() + os.Exit(0) + }(d.listener, sigc) + return d, nil } diff --git a/p2pc/main.go b/p2pc/main.go new file mode 100644 index 00000000..1cdb19de --- /dev/null +++ b/p2pc/main.go @@ -0,0 +1,21 @@ +package main + +import "C" +import ( + identify "github.com/libp2p/go-libp2p/p2p/protocol/identify" + + p2pc "github.com/libp2p/go-libp2p-daemon/p2pclient" +) + +func main() { + identify.ClientVersion = "p2pc/0.1" + config := p2pc.Initialize() + p2pc.Start(config) +} + +//export startClient +func startClient(args *C.char) { + argsGoString := C.GoString(args) + config := p2pc.ProcessArgs(&argsGoString) + p2pc.Start(config) +} diff --git a/p2pclient/p2pc.go b/p2pclient/p2pc.go new file mode 100644 index 00000000..e1943a44 --- /dev/null +++ b/p2pclient/p2pc.go @@ -0,0 +1,135 @@ +package p2pclient + +import "C" +import ( + "flag" + "fmt" + "io" + "os" + "strings" + + peer "github.com/libp2p/go-libp2p-peer" + multiaddr "github.com/multiformats/go-multiaddr" +) + +// ClientConfig defines the configuration options +type ClientConfig struct { + pathd *string + pathc *string + command *string + args []string +} + +type Command int + +const ( + Identify Command = 0 + Connect Command = 1 + ListenForMessage Command = 2 + SendMessage Command = 3 +) + +func (c Command) String() string { + commands := [...]string{ + "Identify", + "Connect", + "ListenForMessage", + "SendMessage", + } + return commands[c] +} + +func Initialize() ClientConfig { + config := ClientConfig{ + pathd: flag.String("pathd", "/tmp/p2pd.sock", "daemon control socket path"), + pathc: flag.String("pathc", "/tmp/p2pc.sock", "client control socket path"), + command: flag.String("command", "Identify", "command to send to the daemon"), + } + flag.Parse() + config.args = flag.Args() + // delete control socket if it already exists + if _, err := os.Stat(*config.pathc); !os.IsNotExist(err) { + err = os.Remove(*config.pathc) + if err != nil { + log.Fatal(err) + } + } + return config +} + +func Start(config ClientConfig) { + + client, err := NewClient(*config.pathd, *config.pathc) + defer os.Remove(*config.pathc) + + if err != nil { + log.Fatal(err) + } + + switch *config.command { + + case Identify.String(): + id, addrs, err := client.Identify() + if err != nil { + log.Fatal(err) + } + fmt.Printf("Daemon ID: %s\n", id.Pretty()) + fmt.Printf("Peer addresses: %v\n", addrs) + + case Connect.String(): + id, err := peer.IDB58Decode(config.args[0]) + var addrs []multiaddr.Multiaddr + addrs = make([]multiaddr.Multiaddr, len(config.args[1:])) + for i, arg := range config.args[1:] { + addr, _ := multiaddr.NewMultiaddr(arg) + addrs[i] = addr + } + err = client.Connect(id, addrs) + if err != nil { + log.Fatal(err) + } + + pi, err := client.FindPeer(id) + fmt.Printf("ID: %s has multiaddr: %v", pi.ID, pi.Addrs) + + case ListenForMessage.String(): + fmt.Println("Listening...") + protos := []string{"/test"} + done := make(chan struct{}) + client.NewStreamHandler(protos, func(info *StreamInfo, conn io.ReadWriteCloser) { + defer conn.Close() + buf := make([]byte, 1024) + _, err := conn.Read(buf) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(buf)) + done <- struct{}{} + }) + select {} + + case SendMessage.String(): + protos := []string{"/test"} + recipientID, err := peer.IDB58Decode(config.args[0]) + _, conn, err := client.NewStream(recipientID, protos) + if err != nil { + log.Fatal(err) + } + _, err = conn.Write([]byte(config.args[1])) + if err != nil { + log.Fatal(err) + } + + default: + + } +} + +func ProcessArgs(args *string) ClientConfig { + //replace default config options with configs passed from external source + argsArray := strings.Split(*args, "|") + os.Args = argsArray + //call initialize() to get config + config := Initialize() + return config +} diff --git a/p2pd.go b/p2pd.go new file mode 100644 index 00000000..2dd30678 --- /dev/null +++ b/p2pd.go @@ -0,0 +1,176 @@ +package p2pd + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "time" + + libp2p "github.com/libp2p/go-libp2p" + connmgr "github.com/libp2p/go-libp2p-connmgr" + ps "github.com/libp2p/go-libp2p-pubsub" + quic "github.com/libp2p/go-libp2p-quic-transport" +) + +// DaemonConfig defines the configuration options +type DaemonConfig struct { + sock *string + quiet *bool + id *string + bootstrap *bool + bootstrapPeers *string + dht *bool + dhtClient *bool + connMgr *bool + connMgrLo *int + connMgrHi *int + connMgrGrace *int + QUIC *bool + natPortMap *bool + pubsub *bool + pubsubRouter *string + pubsubSign *bool + pubsubSignStrict *bool + gossipsubHeartbeatInterval *int + gossipsubHeartbeatInitialDelay *int + args []string +} + +func Initialize() DaemonConfig { + config := DaemonConfig{ + sock: flag.String("sock", "/tmp/p2pd.sock", "daemon control socket path"), + quiet: flag.Bool("q", false, "be quiet"), + id: flag.String("id", "", "peer identity; private key file"), + bootstrap: flag.Bool("b", false, "connects to bootstrap peers and bootstraps the dht if enabled"), + bootstrapPeers: flag.String("bootstrapPeers", "", "comma separated list of bootstrap peers; defaults to the IPFS DHT peers"), + dht: flag.Bool("dht", true, "Enables the DHT in full node mode"), + dhtClient: flag.Bool("dhtClient", true, "Enables the DHT in client mode"), + connMgr: flag.Bool("connManager", false, "Enables the Connection Manager"), + connMgrLo: flag.Int("connLo", 256, "Connection Manager Low Water mark"), + connMgrHi: flag.Int("connHi", 512, "Connection Manager High Water mark"), + connMgrGrace: flag.Int("connGrace", 120, "Connection Manager grace period (in seconds)"), + QUIC: flag.Bool("quic", false, "Enables the QUIC transport"), + natPortMap: flag.Bool("natPortMap", false, "Enables NAT port mapping"), + pubsub: flag.Bool("pubsub", false, "Enables pubsub"), + pubsubRouter: flag.String("pubsubRouter", "gossipsub", "Specifies the pubsub router implementation"), + pubsubSign: flag.Bool("pubsubSign", true, "Enables pubsub message signing"), + pubsubSignStrict: flag.Bool("pubsubSignStrict", false, "Enables pubsub strict signature verification"), + gossipsubHeartbeatInterval: flag.Int("gossipsubHeartbeatInterval", 0, "Specifies the gossipsub heartbeat interval"), + gossipsubHeartbeatInitialDelay: flag.Int("gossipsubHeartbeatInitialDelay", 0, "Specifies the gossipsub initial heartbeat delay"), + } + flag.Parse() + config.args = flag.Args() + // delete control socket if it already exists + if _, err := os.Stat(*config.sock); !os.IsNotExist(err) { + err = os.Remove(*config.sock) + if err != nil { + log.Fatal(err) + } + } + return config +} + +func Start(config DaemonConfig) { + var opts []libp2p.Option + + if *config.id != "" { + key, err := ReadIdentity(*config.id) + if err != nil { + log.Fatal(err) + } + + opts = append(opts, libp2p.Identity(key)) + } + + if *config.connMgr { + cm := connmgr.NewConnManager(*config.connMgrLo, *config.connMgrHi, time.Duration(*config.connMgrGrace)) + opts = append(opts, libp2p.ConnectionManager(cm)) + } + + if *config.QUIC { + opts = append(opts, + libp2p.DefaultTransports, + libp2p.Transport(quic.NewTransport), + libp2p.ListenAddrStrings( + "/ip4/0.0.0.0/tcp/0", + "/ip4/0.0.0.0/udp/0/quic", + "/ip6/::1/tcp/0", + "/ip6/::1/udp/0/quic", + )) + } + + if *config.natPortMap { + opts = append(opts, libp2p.NATPortMap()) + } + + d, err := NewDaemon(context.Background(), *config.sock, opts...) + if err != nil { + log.Fatal(err) + } + + if *config.pubsub { + if *config.gossipsubHeartbeatInterval > 0 { + ps.GossipSubHeartbeatInterval = time.Duration(*config.gossipsubHeartbeatInterval) + } + + if *config.gossipsubHeartbeatInitialDelay > 0 { + ps.GossipSubHeartbeatInitialDelay = time.Duration(*config.gossipsubHeartbeatInitialDelay) + } + + err = d.EnablePubsub(*config.pubsubRouter, *config.pubsubSign, *config.pubsubSignStrict) + if err != nil { + log.Fatal(err) + } + } + + if *config.dht || *config.dhtClient { + err = d.EnableDHT(*config.dhtClient) + if err != nil { + log.Fatal(err) + } + } + + if *config.bootstrapPeers != "" { + BootstrapPeers = strings.Split(*config.bootstrapPeers, ",") + } + + if *config.bootstrap { + err = d.Bootstrap() + if err != nil { + log.Fatal(err) + } + } + + if !*config.quiet { + fmt.Printf("Control socket: %s\n", *config.sock) + fmt.Printf("Peer ID: %s\n", d.ID().Pretty()) + fmt.Printf("Peer Addrs:\n") + for _, addr := range d.Addrs() { + fmt.Printf("%s\n", addr.String()) + } + if *config.bootstrap && *config.bootstrapPeers != "" { + fmt.Printf("Bootstrap peers:\n") + for _, p := range BootstrapPeers { + fmt.Printf("%s\n", p) + } + } + } + + select {} +} + +func Stop() { + p, _ := os.FindProcess(os.Getpid()) + p.Signal(os.Interrupt) +} + +func ProcessArgs(args *string) DaemonConfig { + //replace default config options with configs passed from external source + argsArray := strings.Split(*args, "|") + os.Args = argsArray + //call initialize() to get config + config := Initialize() + return config +} diff --git a/p2pd/main.go b/p2pd/main.go index d65344cd..3efc0e82 100644 --- a/p2pd/main.go +++ b/p2pd/main.go @@ -1,128 +1,26 @@ package main +import "C" import ( - "context" - "flag" - "fmt" - "log" - "strings" + identify "github.com/libp2p/go-libp2p/p2p/protocol/identify" - libp2p "github.com/libp2p/go-libp2p" - connmgr "github.com/libp2p/go-libp2p-connmgr" p2pd "github.com/libp2p/go-libp2p-daemon" - ps "github.com/libp2p/go-libp2p-pubsub" - quic "github.com/libp2p/go-libp2p-quic-transport" - identify "github.com/libp2p/go-libp2p/p2p/protocol/identify" ) func main() { identify.ClientVersion = "p2pd/0.1" + config := p2pd.Initialize() + p2pd.Start(config) +} - sock := flag.String("sock", "/tmp/p2pd.sock", "daemon control socket path") - quiet := flag.Bool("q", false, "be quiet") - id := flag.String("id", "", "peer identity; private key file") - bootstrap := flag.Bool("b", false, "connects to bootstrap peers and bootstraps the dht if enabled") - bootstrapPeers := flag.String("bootstrapPeers", "", "comma separated list of bootstrap peers; defaults to the IPFS DHT peers") - dht := flag.Bool("dht", false, "Enables the DHT in full node mode") - dhtClient := flag.Bool("dhtClient", false, "Enables the DHT in client mode") - connMgr := flag.Bool("connManager", false, "Enables the Connection Manager") - connMgrLo := flag.Int("connLo", 256, "Connection Manager Low Water mark") - connMgrHi := flag.Int("connHi", 512, "Connection Manager High Water mark") - connMgrGrace := flag.Duration("connGrace", 120, "Connection Manager grace period (in seconds)") - QUIC := flag.Bool("quic", false, "Enables the QUIC transport") - natPortMap := flag.Bool("natPortMap", false, "Enables NAT port mapping") - pubsub := flag.Bool("pubsub", false, "Enables pubsub") - pubsubRouter := flag.String("pubsubRouter", "gossipsub", "Specifies the pubsub router implementation") - pubsubSign := flag.Bool("pubsubSign", true, "Enables pubsub message signing") - pubsubSignStrict := flag.Bool("pubsubSignStrict", false, "Enables pubsub strict signature verification") - gossipsubHeartbeatInterval := flag.Duration("gossipsubHeartbeatInterval", 0, "Specifies the gossipsub heartbeat interval") - gossipsubHeartbeatInitialDelay := flag.Duration("gossipsubHeartbeatInitialDelay", 0, "Specifies the gossipsub initial heartbeat delay") - flag.Parse() - - var opts []libp2p.Option - - if *id != "" { - key, err := p2pd.ReadIdentity(*id) - if err != nil { - log.Fatal(err) - } - - opts = append(opts, libp2p.Identity(key)) - } - - if *connMgr { - cm := connmgr.NewConnManager(*connMgrLo, *connMgrHi, *connMgrGrace) - opts = append(opts, libp2p.ConnectionManager(cm)) - } - - if *QUIC { - opts = append(opts, - libp2p.DefaultTransports, - libp2p.Transport(quic.NewTransport), - libp2p.ListenAddrStrings( - "/ip4/0.0.0.0/tcp/0", - "/ip4/0.0.0.0/udp/0/quic", - "/ip6/::1/tcp/0", - "/ip6/::1/udp/0/quic", - )) - } - - if *natPortMap { - opts = append(opts, libp2p.NATPortMap()) - } - - d, err := p2pd.NewDaemon(context.Background(), *sock, opts...) - if err != nil { - log.Fatal(err) - } - - if *pubsub { - if *gossipsubHeartbeatInterval > 0 { - ps.GossipSubHeartbeatInterval = *gossipsubHeartbeatInterval - } - - if *gossipsubHeartbeatInitialDelay > 0 { - ps.GossipSubHeartbeatInitialDelay = *gossipsubHeartbeatInitialDelay - } - - err = d.EnablePubsub(*pubsubRouter, *pubsubSign, *pubsubSignStrict) - if err != nil { - log.Fatal(err) - } - } - - if *dht || *dhtClient { - err = d.EnableDHT(*dhtClient) - if err != nil { - log.Fatal(err) - } - } - - if *bootstrapPeers != "" { - p2pd.BootstrapPeers = strings.Split(*bootstrapPeers, ",") - } - - if *bootstrap { - err = d.Bootstrap() - if err != nil { - log.Fatal(err) - } - } - - if !*quiet { - fmt.Printf("Control socket: %s\n", *sock) - fmt.Printf("Peer ID: %s\n", d.ID().Pretty()) - fmt.Printf("Peer Addrs:\n") - for _, addr := range d.Addrs() { - fmt.Printf("%s\n", addr.String()) - } - if *bootstrap && *bootstrapPeers != "" { - fmt.Printf("Bootstrap peers:\n") - for _, p := range p2pd.BootstrapPeers { - fmt.Printf("%s\n", p) - } - } - } +//export startDaemon +func startDaemon(args *C.char) { + argsGoString := C.GoString(args) + config := p2pd.ProcessArgs(&argsGoString) + p2pd.Start(config) +} - select {} +//export stopDaemon +func stopDaemon() { + p2pd.Stop() }