|
@@ -0,0 +1,185 @@
|
|
|
+package main
|
|
|
+
|
|
|
+/*
|
|
|
+
|
|
|
+ Two-Nodes
|
|
|
+
|
|
|
+ A simple demo for showcasing the go-DDDNS working in a two nodes environment
|
|
|
+
|
|
|
+*/
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "flag"
|
|
|
+ "io/ioutil"
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+ "os"
|
|
|
+ "os/signal"
|
|
|
+ "strconv"
|
|
|
+ "syscall"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ godddns "github.com/tobychui/go-DDDNS/godddns"
|
|
|
+)
|
|
|
+
|
|
|
+var (
|
|
|
+ //Flags
|
|
|
+ //Current node
|
|
|
+ thisNodeUUID = flag.String("nid", "node1", "The UUID of this node")
|
|
|
+
|
|
|
+ //Remote nodes
|
|
|
+ remoteNodeAUUID = flag.String("rida", "node2", "The UUID of the remote node A")
|
|
|
+ remoteNodeAIPAddr = flag.String("ripa", "127.0.0.1", "The remote node A current IP address")
|
|
|
+ remoteNodeBUUID = flag.String("ridb", "node3", "The UUID of the remote node B")
|
|
|
+ remoteNodeBIPAddr = flag.String("ripb", "127.0.0.1", "The remote node B current IP address")
|
|
|
+
|
|
|
+ //The following flags assume both remote node A and B are hosted on the same port and with same connection endpoint
|
|
|
+ connPath = flag.String("conn", "/conn", "The relative path for connection establishment")
|
|
|
+ thisNodeRecvPort = flag.Int("np", 8080, "This node receive port")
|
|
|
+ remoteNodeRecvPort = flag.Int("rp", 8080, "Remote nodes (A and B) receive port")
|
|
|
+
|
|
|
+ //Paramter, which we hardcoded here for now
|
|
|
+ syncInterval int64 = 10
|
|
|
+ serviceRouter *godddns.ServiceRouter
|
|
|
+)
|
|
|
+
|
|
|
+//Dummy function which allow all login to pass through
|
|
|
+func ValidateCred(username string, password string) bool {
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+func cleanup(configFilename string) {
|
|
|
+ //Save the router record to json file
|
|
|
+ js, err := serviceRouter.ExportRouterToJSON()
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+ ioutil.WriteFile(configFilename, []byte(js), 0755)
|
|
|
+
|
|
|
+ //Close the service router
|
|
|
+ serviceRouter.Close()
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ //Set-ups
|
|
|
+ flag.Parse()
|
|
|
+ configFilename := *thisNodeUUID + "_config.json"
|
|
|
+ c := make(chan os.Signal)
|
|
|
+ signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
|
+ go func() {
|
|
|
+ <-c
|
|
|
+ cleanup(configFilename)
|
|
|
+ os.Exit(1)
|
|
|
+ }()
|
|
|
+
|
|
|
+ //Step 1: we want to create a new service router based on the given information
|
|
|
+ if fileExists(configFilename) {
|
|
|
+ //Load service router from file
|
|
|
+ s, err := godddns.NewRouterFromJSONFile(configFilename)
|
|
|
+ if err != nil {
|
|
|
+ log.Println("Failed to load service router from file: ")
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ s.InjectAuthFunction(ValidateCred)
|
|
|
+ serviceRouter = s
|
|
|
+ log.Println("Service Router Config Loaded")
|
|
|
+ } else {
|
|
|
+ //Create a new service router
|
|
|
+ serviceRouter = godddns.NewServiceRouter(godddns.RouterOptions{
|
|
|
+ DeviceUUID: *thisNodeUUID,
|
|
|
+ AuthFunction: ValidateCred,
|
|
|
+ SyncInterval: syncInterval,
|
|
|
+ })
|
|
|
+ log.Println("Service Router Created")
|
|
|
+ }
|
|
|
+
|
|
|
+ //Optional: Enable verbal output on router
|
|
|
+ serviceRouter.Options.Verbal = true
|
|
|
+
|
|
|
+ //Step 2: Create HTTP listening endpoint for incoming connection requests and heartbeat
|
|
|
+ go func() {
|
|
|
+ http.HandleFunc("/conn", serviceRouter.HandleConnections)
|
|
|
+ log.Println("HTTP Listening endpoint started on :" + strconv.Itoa(*thisNodeRecvPort))
|
|
|
+ http.ListenAndServe(":"+strconv.Itoa(*thisNodeRecvPort), nil)
|
|
|
+ }()
|
|
|
+
|
|
|
+ if !fileExists(configFilename) {
|
|
|
+ //Step 3: we want to add the remote nodes to the list
|
|
|
+ //Node A
|
|
|
+ nodeA := serviceRouter.NewNode(godddns.NodeOptions{
|
|
|
+ NodeID: *remoteNodeAUUID,
|
|
|
+ Port: *remoteNodeRecvPort,
|
|
|
+ RESTInterface: *connPath,
|
|
|
+ RequireHTTPS: false,
|
|
|
+ })
|
|
|
+ serviceRouter.AddNode(nodeA)
|
|
|
+ log.Println("Remote NodeA Added")
|
|
|
+
|
|
|
+ //Node B
|
|
|
+ nodeB := serviceRouter.NewNode(godddns.NodeOptions{
|
|
|
+ NodeID: *remoteNodeBUUID,
|
|
|
+ Port: *remoteNodeRecvPort,
|
|
|
+ RESTInterface: *connPath,
|
|
|
+ RequireHTTPS: false,
|
|
|
+ })
|
|
|
+ serviceRouter.AddNode(nodeB)
|
|
|
+ log.Println("Remote NodeB Added")
|
|
|
+
|
|
|
+ //Step 4: Start the connection to Node 1 (Replace username and password with real value here)
|
|
|
+ retryCount := 0
|
|
|
+ retry := true
|
|
|
+ for retry {
|
|
|
+ if retryCount > 10 {
|
|
|
+ log.Println("Connection to remote node " + nodeA.UUID + " failed. Skipping.")
|
|
|
+ break
|
|
|
+ }
|
|
|
+ assignedSendingTOTP, err := nodeA.StartConnection(*remoteNodeAIPAddr, "username", "password")
|
|
|
+ if err != nil {
|
|
|
+ log.Println("Unable to establish connection to Node A. Retrying in 3 seconds", assignedSendingTOTP)
|
|
|
+ retryCount++
|
|
|
+
|
|
|
+ time.Sleep(3 * time.Second)
|
|
|
+ } else {
|
|
|
+ log.Println("Remote Node A TOTP exchange done:", assignedSendingTOTP)
|
|
|
+ retry = false
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //Start connection to Node 2
|
|
|
+ retryCount = 0
|
|
|
+ retry = true
|
|
|
+ for retry {
|
|
|
+ if retryCount > 10 {
|
|
|
+ log.Println("Connection to remote node " + nodeB.UUID + " failed. Skipping.")
|
|
|
+ break
|
|
|
+ }
|
|
|
+ assignedSendingTOTP, err := nodeB.StartConnection(*remoteNodeBIPAddr, "username", "password")
|
|
|
+ if err != nil {
|
|
|
+ log.Println("Unable to establish connection to Node B. Retrying in 3 seconds", assignedSendingTOTP)
|
|
|
+ retryCount++
|
|
|
+
|
|
|
+ time.Sleep(3 * time.Second)
|
|
|
+ } else {
|
|
|
+ log.Println("Node B TOTP exchange done:", assignedSendingTOTP)
|
|
|
+ retry = false
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //Step 4: Start Heartbeat to the remote node(s)
|
|
|
+ serviceRouter.StartHeartBeat()
|
|
|
+ log.Println("Heartbeat schedule started")
|
|
|
+
|
|
|
+ //Do a blocking loop
|
|
|
+ select {}
|
|
|
+}
|
|
|
+
|
|
|
+func fileExists(filename string) bool {
|
|
|
+ if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|