Skip to content
Snippets Groups Projects
Commit 44277be6 authored by Jake Taylor's avatar Jake Taylor :lips:
Browse files

Merge branch 'XX-3965/FileTransferConnect' into 'master'

XX-3965 / Add file transfer connect client

See merge request !10
parents 2213221a f98bd36e
No related branches found
No related tags found
1 merge request!10XX-3965 / Add file transfer connect client
# xxdk File Transfer Connect Example
This mini-repository contains example logic for running a basic connection
client and sending a file transfer. This is provided by the xx network team as a
springboard to help consumers better understand our API and how it may be used.
[`main.go`](main.go) contains the crux of the logic. We avoid complicating our
example by avoiding the usage of CLI flags for basic variables you may change in
the code. This file initiates an xxdk E2E object with a connection client built
on top. Then the connection client is wrapped in a file transfer manager that
facilitates the sending of an example file to a precanned contact object created
in `fileTransferConnectServer`.
[`utils.go`](utils.go) contains utility functions for running the program. In
this case, we provide a tool initializing a log.
## Build Instructions
In these instructions we will go over building a connection client using our
example. In order to build a client that successfully sends a message through
the connection, we must first go over how to build and run a connection server.
### Building a Client
E2E clients communicate with each other directly via the xx network.
To build and run a client, execute the following bash commands:
```shell
cd fileTransferConnectClient/
go build -o client .
./client
```
This will start an e2e client and connection that can be monitored via log
activity in `client.log`. This will read the contact at `connectServer.xxc.xxc`,
attempting to establish a connection and send a test file. This functionality
can be skipped by setting the relevant variable in the code to empty string.
By default, the client sends a single file to the recipient, with the recipient
registering a `fileTransfer.ReceiveCallback` that listens to messages of type
`catalog.NewFileTransfer` from the connection partner.
Verification that the client is able to send messages may
also be done. This can be done by checking the client's log for the string
`Received progress callback for`.
```shell
grep "Received progress callback for" client.log
INFO 2022/07/07 12:59:12.088046 Received progress callback for...
```
module gitlab.com/elixxir/xxdk-examples/fileTransferConnectClient
go 1.17
require (
github.com/spf13/jwalterweatherman v1.1.0
gitlab.com/elixxir/client v1.5.1-0.20220706193049-a0b718049663
gitlab.com/elixxir/crypto v0.0.7-0.20220606201132-c370d5039cea
gitlab.com/xx_network/primitives v0.0.4-0.20220630163313-7890038258c6
)
require (
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
github.com/badoux/checkmail v1.2.1 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/elliotchance/orderedmap v1.4.0 // indirect
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
github.com/ttacon/libphonenumber v1.2.1 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f // indirect
gitlab.com/elixxir/comms v0.0.4-0.20220603231314-e47e4af13326 // indirect
gitlab.com/elixxir/ekv v0.1.7 // indirect
gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f // indirect
gitlab.com/xx_network/comms v0.0.4-0.20220630163702-f3d372ef6acd // indirect
gitlab.com/xx_network/crypto v0.0.5-0.20220606200528-3f886fe49e81 // indirect
gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 // indirect
go.uber.org/ratelimit v0.2.0 // indirect
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)
This diff is collapsed.
// Sending Normal messages (Getting Started guide)
package main
import (
"errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/fileTransfer"
ftConnect "gitlab.com/elixxir/client/fileTransfer/connect"
"gitlab.com/elixxir/client/xxdk"
ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
"gitlab.com/xx_network/primitives/id"
"io/fs"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/crypto/contact"
)
func main() {
// Logging
initLog(1, "client.log")
// Create a new client object----------------------------------------------
// Path to the server contact file
serverContactPath := "connectServer.xxc"
// You would ideally use a configuration tool to acquire these parameters
statePath := "statePath"
statePass := "password"
// The following connects to mainnet. For historical reasons it is called a
// JSON file, but it is actually a marshalled file with a cryptographic
// signature attached. This may change in the future.
ndfURL := "https://elixxir-bins.s3.us-west-1.amazonaws.com/ndf/mainnet.json"
certificatePath := "../mainnet.crt"
ndfPath := "ndf.json"
// Check if state exists
if _, err := os.Stat(statePath); errors.Is(err, fs.ErrNotExist) {
// Attempt to read the NDF
var ndfJSON []byte
ndfJSON, err = ioutil.ReadFile(ndfPath)
if err != nil {
jww.INFO.Printf("NDF does not exist: %+v", err)
}
// If NDF can't be read, retrieve it remotely
if ndfJSON == nil {
cert, err := ioutil.ReadFile(certificatePath)
if err != nil {
jww.FATAL.Panicf("Failed to read certificate: %v", err)
}
ndfJSON, err = xxdk.DownloadAndVerifySignedNdfWithUrl(
ndfURL, string(cert))
if err != nil {
jww.FATAL.Panicf("Failed to download NDF: %+v", err)
}
}
// Initialize the state
err = xxdk.NewCmix(string(ndfJSON), statePath, []byte(statePass), "")
if err != nil {
jww.FATAL.Panicf("Failed to initialize state: %+v", err)
}
}
// Login to your client session--------------------------------------------
// Login with the same sessionPath and sessionPass used to call NewClient()
net, err := xxdk.LoadCmix(statePath, []byte(statePass),
xxdk.GetDefaultCMixParams())
if err != nil {
jww.FATAL.Panicf("Failed to load state: %+v", err)
}
// Get reception identity (automatically created if one does not exist)
identityStorageKey := "identityStorageKey"
identity, err := xxdk.LoadReceptionIdentity(identityStorageKey, net)
if err != nil {
// If no extant xxdk.ReceptionIdentity, generate and store a new one
identity, err = xxdk.MakeReceptionIdentity(net)
if err != nil {
jww.FATAL.Panicf("Failed to generate reception identity: %+v", err)
}
err = xxdk.StoreReceptionIdentity(
identityStorageKey, identity, net)
if err != nil {
jww.FATAL.Panicf("Failed to store new reception identity: %+v", err)
}
}
// Create an E2E client
// The connect package handles AuthCallbacks,
// xxdk.DefaultAuthCallbacks is fine here
params := xxdk.GetDefaultE2EParams()
jww.INFO.Printf("Using E2E parameters: %+v", params)
messenger, err := xxdk.Login(net, xxdk.DefaultAuthCallbacks{},
identity, params)
if err != nil {
jww.FATAL.Panicf("Unable to Login: %+v", err)
}
// Start network threads----------------------------------------------------
// Set networkFollowerTimeout to a value of your choice (seconds)
networkFollowerTimeout := 5 * time.Second
err = messenger.StartNetworkFollower(networkFollowerTimeout)
if err != nil {
jww.FATAL.Panicf("Failed to start network follower: %+v", err)
}
// Set up a wait for the network to be connected
waitUntilConnected := func(connected chan bool) {
waitTimeout := 30 * time.Second
timeoutTimer := time.NewTimer(waitTimeout)
isConnected := false
// Wait until we connect or panic if we cannot before the timeout
for !isConnected {
select {
case isConnected = <-connected:
jww.INFO.Printf("Network Status: %v", isConnected)
break
case <-timeoutTimer.C:
jww.FATAL.Panicf("Timeout on starting network follower")
}
}
}
// Create a tracker channel to be notified of network changes
connected := make(chan bool, 10)
// Provide a callback that will be signalled when network
// health status changes
messenger.GetCmix().AddHealthCallback(
func(isConnected bool) {
connected <- isConnected
})
// Wait until connected or crash on timeout
waitUntilConnected(connected)
// Connect with the server-------------------------------------------------
// Recipient's contact (read from a Client CLI-generated contact file)
contactData, err := ioutil.ReadFile(serverContactPath)
if err != nil {
jww.FATAL.Panicf("Failed to read server contact file: %+v", err)
}
// Imported "gitlab.com/elixxir/crypto/contact"
// which provides an Unmarshal function to convert the
// byte slice ([]byte) output of ioutil.ReadFile() to the Contact type
// expected by RequestAuthenticatedChannel()
recipientContact, err := contact.Unmarshal(contactData)
if err != nil {
jww.FATAL.Panicf("Failed to get contact data: %+v", err)
}
jww.INFO.Printf("Recipient contact: %+v", recipientContact)
// Create the connection
handler, err := connect.Connect(recipientContact, messenger, params)
if err != nil {
jww.FATAL.Panicf("Failed to create connection object: %+v", err)
}
jww.INFO.Printf("Connect with %s successfully established!",
recipientContact.ID)
// Create file transfer manager--------------------------------------------
// Create general file transfer manager
ftParams := fileTransfer.DefaultParams()
ftManager, err := fileTransfer.NewManager(ftParams, identity.ID,
messenger.GetCmix(), messenger.GetStorage(), messenger.GetRng())
if err != nil {
jww.FATAL.Panicf("Failed to create file transfer manager: %+v", err)
}
err = messenger.AddService(ftManager.StartProcesses)
if err != nil {
jww.FATAL.Panicf("Failed to start file transfer pcoesses: %+v", err)
}
// Create ReceiveCallback that is called when a new file transfer is received
receiveCB := func(tid *ftCrypto.TransferID, fileName, fileType string,
sender *id.ID, size uint32, preview []byte) {
// Inform the user that a new file transfer has been received
jww.INFO.Printf("Received new file %q transfer %s of type %s from %s "+
"of size %d bytes with preview: %q",
fileName, tid, fileType, sender, size, preview)
receivedProgressCB := func(completed bool, received, total uint16,
rt fileTransfer.ReceivedTransfer, t fileTransfer.FilePartTracker,
err error) {
// Show the file transfer progress to the user.
jww.INFO.Printf("Received progress callback for %q "+
"{completed: %t, received: %d, total: %d, err: %v}",
fileName, completed, received, total, err)
}
// Register received progress callback
err = ftManager.RegisterReceivedProgressCallback(
tid, receivedProgressCB, 0)
if err != nil {
jww.FATAL.Panicf(
"Failed to register received progress callback: %+v", err)
}
}
// Wrap the file transfer in the connection wrapper
ftConnectParams := ftConnect.DefaultParams()
ftWrapper, err := ftConnect.NewWrapper(
receiveCB, ftConnectParams, ftManager, handler, messenger.GetCmix())
if err != nil {
jww.FATAL.Panicf("Failed to create file transfer manager: %+v", err)
}
// Send a file to the server-----------------------------------------------
// Define file
fileName := "Lorem Ipsum"
fileType := "txt"
fileData := []byte(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"Sed lobortis justo ut sapien euismod varius. " +
"Suspendisse ut ornare augue. " +
"Mauris a est et nibh mattis gravida.")
preview := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
// Define progress callback
progressCB := func(completed bool, arrived, total uint16,
st fileTransfer.SentTransfer, t fileTransfer.FilePartTracker, err error) {
// Show the file transfer progress to the user.
jww.INFO.Printf("Sent progress callback for %q "+
"{completed: %t, arrived: %d, total: %d, err: %v}",
fileName, completed, arrived, total, err)
}
// The retry rate is the number of retries allowed when sending a message
// part fails. A retry of 1.0 does not allow any resends. A retry of 1.5
// allows for half the parts to be resent on failure.
retryRate := float32(1.5)
// Send file
tid, err := ftWrapper.Send(recipientContact.ID, fileName, fileType,
fileData, retryRate, preview, progressCB, 0)
if err != nil {
jww.FATAL.Panicf("Failed to send file: %+v", err)
}
jww.INFO.Printf("File transfer %s initiated.", tid)
// Keep app running to receive messages------------------------------------
// Wait until the user terminates the program
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
err = messenger.StopNetworkFollower()
if err != nil {
jww.ERROR.Printf("Failed to stop network follower: %+v", err)
} else {
jww.INFO.Printf("Stopped network follower.")
}
os.Exit(0)
}
package main
import (
jww "github.com/spf13/jwalterweatherman"
"io/ioutil"
"log"
"os"
)
func initLog(threshold uint, logPath string) {
if logPath != "-" && logPath != "" {
// Disable stdout output
jww.SetStdoutOutput(ioutil.Discard)
// Use log file
logOutput, err := os.OpenFile(logPath,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err.Error())
}
jww.SetLogOutput(logOutput)
}
if threshold > 1 {
jww.INFO.Printf("log level set to: TRACE")
jww.SetStdoutThreshold(jww.LevelTrace)
jww.SetLogThreshold(jww.LevelTrace)
jww.SetFlags(log.LstdFlags | log.Lmicroseconds)
} else if threshold == 1 {
jww.INFO.Printf("log level set to: DEBUG")
jww.SetStdoutThreshold(jww.LevelDebug)
jww.SetLogThreshold(jww.LevelDebug)
jww.SetFlags(log.LstdFlags | log.Lmicroseconds)
} else {
jww.INFO.Printf("log level set to: INFO")
jww.SetStdoutThreshold(jww.LevelInfo)
jww.SetLogThreshold(jww.LevelInfo)
}
}
# xxdk Connection Server Example
This mini-repository contains the example logic for running a basic connection
server and receiving a file transfer. This is provided by the xx network team as
a springboard to help consumers better understand our API and how it may be
used.
[`main.go`](main.go) contains the crux of the logic. We avoid complicating our
example by avoiding the usage of CLI flags for basic variables you may change in
the code. This file initiates an xxdk cMix object. With that client established,
a connection server is built on top. When a new connection is received, a file
transfer manager is created that wraps the connection and waits to receive a
file transfer. This program creates contact file `connectServer.xxc` that may
be used by a client to contact the server.
[`utils.go`](utils.go) contains utility functions for running the program. In this
case, we provide a tool initializing a log. It also contains a utility to write the
contact file to disk.
## Build Instructions
In these instructions we will go over building a connection server using our
example. This will not include instructions on running a client, which
establishes a connection. That documentation may be found in the [`README.md` for
`connectClient`.](../connectClient/README.md).
In order to run a server, the following commands may be run:
```bash
cd fileTransferConnectServer/
go build -o server .
./server
```
This will initialize the server. You may verify its functionality by checking
the `server.log` file. It is a long-running process which may be stopped by a
user inputted kill signal. This will create a file `connectServer.xxc`, which is
the contact file for the server. A connection client may parse this file in
order to establish a connection with this server.
\ No newline at end of file
module gitlab.com/elixxir/xxdk-examples/fileTransferConnectServer
go 1.17
require (
github.com/spf13/jwalterweatherman v1.1.0
gitlab.com/elixxir/client v1.5.1-0.20220713213756-95ed0fc8e7cf
gitlab.com/elixxir/crypto v0.0.7-0.20220606201132-c370d5039cea
gitlab.com/xx_network/primitives v0.0.4-0.20220712193914-aebd8544396e
)
require (
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
github.com/badoux/checkmail v1.2.1 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/elliotchance/orderedmap v1.4.0 // indirect
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
github.com/ttacon/libphonenumber v1.2.1 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f // indirect
gitlab.com/elixxir/comms v0.0.4-0.20220603231314-e47e4af13326 // indirect
gitlab.com/elixxir/ekv v0.1.7 // indirect
gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f // indirect
gitlab.com/xx_network/comms v0.0.4-0.20220630163702-f3d372ef6acd // indirect
gitlab.com/xx_network/crypto v0.0.5-0.20220606200528-3f886fe49e81 // indirect
gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 // indirect
go.uber.org/ratelimit v0.2.0 // indirect
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)
This diff is collapsed.
// Starting connection server
package main
import (
"errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/fileTransfer"
ftConnect "gitlab.com/elixxir/client/fileTransfer/connect"
"gitlab.com/elixxir/client/xxdk"
ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
"gitlab.com/xx_network/primitives/id"
"io/fs"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
"gitlab.com/elixxir/client/connect"
)
func main() {
// Logging
initLog(1, "server.log")
// Create a new client object----------------------------------------------
// Set the output contact file path
contactFilePath := "connectServer.xxc"
// You would ideally use a configuration tool to acquire these parameters
statePath := "statePath"
statePass := "password"
// The following connects to mainnet. For historical reasons it is called a
// JSON file, but it is actually a marshalled file with a cryptographic
// signature attached. This may change in the future.
ndfURL := "https://elixxir-bins.s3.us-west-1.amazonaws.com/ndf/mainnet.json"
certificatePath := "../mainnet.crt"
ndfPath := "ndf.json"
// High level parameters for the network
e2eParams := xxdk.GetDefaultE2EParams()
connectionListParams := connect.DefaultConnectionListParams()
// Check if state exists
if _, err := os.Stat(statePath); errors.Is(err, fs.ErrNotExist) {
// Attempt to read the NDF
var ndfJSON []byte
ndfJSON, err = ioutil.ReadFile(ndfPath)
if err != nil {
jww.INFO.Printf("NDF does not exist: %+v", err)
}
// If NDF can't be read, retrieve it remotely
if ndfJSON == nil {
cert, err := ioutil.ReadFile(certificatePath)
if err != nil {
jww.FATAL.Panicf("Failed to read certificate: %v", err)
}
ndfJSON, err = xxdk.DownloadAndVerifySignedNdfWithUrl(
ndfURL, string(cert))
if err != nil {
jww.FATAL.Panicf("Failed to download NDF: %+v", err)
}
}
// Initialize the state
err = xxdk.NewCmix(string(ndfJSON), statePath, []byte(statePass), "")
if err != nil {
jww.FATAL.Panicf("Failed to initialize state: %+v", err)
}
}
// Load client state and identity------------------------------------------
// Load with the same sessionPath and sessionPass used to call NewClient()
net, err := xxdk.LoadCmix(statePath, []byte(statePass),
xxdk.GetDefaultCMixParams())
if err != nil {
jww.FATAL.Panicf("Failed to load state: %+v", err)
}
// Get reception identity (automatically created if one does not exist)
identityStorageKey := "identityStorageKey"
identity, err := xxdk.LoadReceptionIdentity(identityStorageKey, net)
if err != nil {
// If no extant xxdk.ReceptionIdentity, generate and store a new one
identity, err = xxdk.MakeReceptionIdentity(net)
if err != nil {
jww.FATAL.Panicf("Failed to generate reception identity: %+v", err)
}
err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, net)
if err != nil {
jww.FATAL.Panicf("Failed to store new reception identity: %+v", err)
}
}
// Save contact file-------------------------------------------------------
// Save the contact file so that client can connect to this server
writeContact(contactFilePath, identity.GetContact())
// Handle incoming connections and create file transfer manager------------
// Create callback for incoming connections
cb := func(connection connect.Connection) {
// Create general file transfer manager
ftParams := fileTransfer.DefaultParams()
ftManager, err := fileTransfer.NewManager(ftParams, identity.ID,
net.GetCmix(), net.GetStorage(), net.GetRng())
if err != nil {
jww.FATAL.Panicf("Failed to create file transfer manager: %+v", err)
}
err = net.AddService(ftManager.StartProcesses)
if err != nil {
jww.FATAL.Panicf("Failed to start file transfer pcoesses: %+v", err)
}
// Create ReceiveCallback that is called when a new file transfer is received
receiveCB := func(tid *ftCrypto.TransferID, fileName, fileType string,
sender *id.ID, size uint32, preview []byte) {
// Inform the user that a new file transfer has been received
jww.INFO.Printf("Received new file %q transfer %s of type %s from %s "+
"of size %d bytes with preview: %q",
fileName, tid, fileType, sender, size, preview)
receivedProgressCB := func(completed bool, received, total uint16,
rt fileTransfer.ReceivedTransfer, t fileTransfer.FilePartTracker,
err error) {
// Show the file transfer progress to the user.
jww.INFO.Printf("Received progress callback for %q "+
"{completed: %t, received: %d, total: %d, err: %v}",
fileName, completed, received, total, err)
// Once the file is complete, receive the full file.
if completed {
fileData, err := ftManager.Receive(tid)
if err != nil {
jww.FATAL.Panicf("Failed to receive full file: %+v", err)
}
jww.INFO.Printf("Completed receiving file %q: %q",
fileName, fileData)
}
}
// Register received progress callback
err = ftManager.RegisterReceivedProgressCallback(
tid, receivedProgressCB, 0)
if err != nil {
jww.FATAL.Panicf(
"Failed to register received progress callback: %+v", err)
}
}
// Wrap the file transfer in the connection wrapper
ftConnectParams := ftConnect.DefaultParams()
_, err = ftConnect.NewWrapper(
receiveCB, ftConnectParams, ftManager, connection, net.GetCmix())
if err != nil {
jww.FATAL.Panicf("Failed to create file transfer manager: %+v", err)
}
}
// Start connection server-------------------------------------------------
// Start the connection server, which will allow clients to start
// connections with you
connectServer, err := connect.StartServer(
identity, cb, net, e2eParams, connectionListParams)
if err != nil {
jww.FATAL.Panicf("Unable to start connection server: %+v", err)
}
// Start network threads---------------------------------------------------
// Set networkFollowerTimeout to a value of your choice (seconds)
networkFollowerTimeout := 5 * time.Second
err = connectServer.E2e.StartNetworkFollower(networkFollowerTimeout)
if err != nil {
jww.FATAL.Panicf("Failed to start network follower: %+v", err)
}
// Set up a wait for the network to be connected
waitUntilConnected := func(connected chan bool) {
waitTimeout := 30 * time.Second
timeoutTimer := time.NewTimer(waitTimeout)
isConnected := false
// Wait until we connect or panic if we cannot before the timeout
for !isConnected {
select {
case isConnected = <-connected:
jww.INFO.Printf("Network Status: %v", isConnected)
break
case <-timeoutTimer.C:
jww.FATAL.Panicf("Timeout on starting network follower")
}
}
}
// Create a tracker channel to be notified of network changes
connected := make(chan bool, 10)
// Provide a callback that will be signalled when network health
// status changes
connectServer.E2e.GetCmix().AddHealthCallback(
func(isConnected bool) {
connected <- isConnected
})
// Wait until connected or crash on timeout
waitUntilConnected(connected)
// Keep app running to receive messages------------------------------------
// Wait until the user terminates the program
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
err = connectServer.E2e.StopNetworkFollower()
if err != nil {
jww.ERROR.Printf("Failed to stop network follower: %+v", err)
} else {
jww.INFO.Printf("Stopped network follower.")
}
os.Exit(0)
}
package main
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/xx_network/primitives/utils"
"io/ioutil"
"log"
"os"
)
func initLog(threshold uint, logPath string) {
if logPath != "-" && logPath != "" {
// Disable stdout output
jww.SetStdoutOutput(ioutil.Discard)
// Use log file
logOutput, err := os.OpenFile(logPath,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err.Error())
}
jww.SetLogOutput(logOutput)
}
if threshold > 1 {
jww.INFO.Printf("log level set to: TRACE")
jww.SetStdoutThreshold(jww.LevelTrace)
jww.SetLogThreshold(jww.LevelTrace)
jww.SetFlags(log.LstdFlags | log.Lmicroseconds)
} else if threshold == 1 {
jww.INFO.Printf("log level set to: DEBUG")
jww.SetStdoutThreshold(jww.LevelDebug)
jww.SetLogThreshold(jww.LevelDebug)
jww.SetFlags(log.LstdFlags | log.Lmicroseconds)
} else {
jww.INFO.Printf("log level set to: INFO")
jww.SetStdoutThreshold(jww.LevelInfo)
jww.SetLogThreshold(jww.LevelInfo)
}
}
func writeContact(outfilePath string, c contact.Contact) {
err := utils.WriteFileDef(outfilePath, c.Marshal())
if err != nil {
jww.ERROR.Printf("could not write contact file: %+v", err)
} else {
jww.INFO.Printf("contact written to %s successfully", outfilePath)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment