Skip to content
Snippets Groups Projects
Commit 61e3b3af authored by Josh Brooks's avatar Josh Brooks
Browse files

Add authenticated connection examples

parent 4815f75f
No related branches found
No related tags found
2 merge requests!9Connect with auth,!7Update and finalize README's
# xxdk Authenticated Connection Client Example
This mini-repository contains the example logic for running an authenticated
connection client. 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 that established, a connection
client is built on top. Using a precanned contact object created in
`authConnServer.xxc` this client contacts the authenticated server with a simple
message.
[`utils.go`](utils.go) contains utility functions for running the program. In this case,
we provide a tool initializing a log.
[`listener.go`](listener.go) contains logic for handling the reception of a message via the
established connection. In this example, it is very basic. We invite consumers
to use this as a basis to implement more complex message listeners.
## Build Instructions
In these instructions we will go over building an authenticated connection client
using our example. In order to build a client which successfully sends a message through
the connection, we must first go over how to build and run a connection server.
### Building a Server
In order to run a server, the following commands may be run:
```bash
cd connectServer/
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
`authConnServer.xxc`, which is the contact file for the server. A connection
client may parse this file in order to establish an authenticated connection
with the server.
### Building a Client
Please follow the steps above before continuing to these instructions.
In order to run the client, you must first move the aforementioned
`authConnServer.xxc` file to the path where you will run the client.
```bash
cd connectAuthServer/
cp authConnServer.xxc /path/to/connectAuthClient
```
Once the contact object is local to the client, you may build and run
the client:
```bash
cd connectAuthClient/
go build -o client .
./client
```
This is a long-running process which may be stopped by a user inputted kill
signal. We recommend allowing the process to run for a long enough time to
complete its requests to the server and receive the server's responses. We go
into detail on what this entails below.
Once the connection client has set up and established its connection with the
server, you can verify by checking the server's log for the string
`Message received`.
```bash
grep "Message received" server.log
INFO 2022/07/07 12:59:12.088046 Message received: {XxMessage WjdMwCH+... [73 102 32 116 104 105 115 32 109 101 115 115 97 103 101 32 105 115 32 115 101 110 116 32 115 117 99 99 101 115 115 102 117 108 108 121 44 32 119 101 39 108 108 32 104 97 118 101 32 101 115 116 97 98 108 105 115 104 101 100 32 99 111 110 116 97 99 116 32 119 105 116 104 32 116 104 101 32 115 101 114 118 101 114 46] kuycotVTjefJ4nZWJ+Ksg9/jviANn6suteW6HPmXroID l74No/qjr/8Q74mA9VadudforXet8OykqSvPIEFAeUQD [0 0 0 0 0 2 245 150] 2022-07-07 12:59:07.078570118 -0700 PDT true {58339144 QUEUED 0xc001e12780 map[PENDING:1969-12-31 16:00:01.65722394 -0800 PST PRECOMPUTING:2022-07-07 12:59:00.644730058 -0700 PDT STANDBY:2022-07-07 12:59:07.062879269 -0700 PDT QUEUED:2022-07-07 12:59:10.062881354 -0700 PDT] [] 1000 18 187058678 ID:58339144 UpdateID:187058678 State:3 BatchSize:1000 Topology:"3\xdd\xc9;\xce\xc5\xf0\xff&\x8c\xf1\x7f\nf\xa8K\x17\xb6\xd1\x0b|a\t[\x14\x8e\xde\xd1qϊB\x02" Topology:"\xf5\\\x94MB\x19ڣq݃\xbee\x99\xbfF\xb5\xa9\xf3k\x0e8 gl\xf5:d\x11\xab\x89\x17\x02" Topology:"\x01\xc1\xf6Gi\x972p\xa9\x96\xb4\x12\x0f1\x1c\xebw\xef\xca\xed\"F\xa7w\xe2\n\xbb8\xcbd\x05=\x02" Topology:"\xd5\xc3\xd00\xa3a;RqDs\xf0\xda<\xa3)$y\xef\xc1\xa0\x12_k?\x00\rIebL\xfe\x02" Topology:"vQ\xcd\t\xaf\x91ڤ\x86\x8ecl\x84\xb1\x95\x1e\x8f+ږQ\\ﷀ]7\x89\x08\x02" Timestamps:1657223940 Timestamps:1657223940644730058 Timestamps:1657223947062879269 Timestamps:1657223950062881354 Timestamps:0 Timestamps:0 Timestamps:0 ResourceQueueTimeoutMillis:3906340864 AddressSpaceSize:18 EccSignature:{Nonce:"\xb2y\xccf\x86E\xe0NR\xd2J3|\xb8d\xfe\xb3\xa8\xad\xa2\x92\xe0\xe4\x0bZ\x07\xbeٓ\xb4z\xf2" Signature:"\xe1\xc9 \x92_\xfe\x9d\x7f\x18\xb920C \xa6\xd1\xe9U\xbb\x93o\x9b\x1bp<Y\xb1\x9f\xb7O\x012^^\x9doa\x06P\x83\xfes\xbf\xe1\xaeL\xb0+\\\xdc\x12r4)\xdas49\xf6=\xd2\x13\xa0\x07"}}}
```
By default, the client sends a single message to the server, with the server
registering a `receive.Listener` which listens to messages of type
`catalog.NoType` from the client.
Verification that the server is able to send messages back to the client may
also be done. This can be done by checking the client's log for the string
`Message received`.
```bash
grep "Message received" client.log
INFO 2022/07/07 13:53:34.242752 Message received: {NoType S5yr+Zo1... [73 102 32 116 104 105 115 32 109 101 115 115 97 103 101 32 105 115 32 115 101 110 116 32 115 117 99 99 101 115 115 102 117 108 108 121 44 32 119 101 39 108 108 32 104 97 118 101 32 101 115 116 97 98 108 105 115 104 101 100 32 99 111 110 116 97 99 116 32 119 105 116 104 32 116 104 101 32 99 108 105 101 110 116 46] aT1Z9OLBN+WLMSk9UjN/2Jxe6xtmU9RadnqXU9mf8kgD q9G7VmURis3jNwj8FHxgpS3sukSdL/8+MlLaqyGbJwYD [0 0 0 0 0 1 159 92] 2022-07-07 13:53:31.078117153 -0700 PDT true {58349730 QUEUED 0xc000bc04c0 map[PENDING:1969-12-31 16:00:01.657227203 -0800 PST PRECOMPUTING:2022-07-07 13:53:23.246307109 -0700 PDT STANDBY:2022-07-07 13:53:29.216187342 -0700 PDT QUEUED:2022-07-07 13:53:32.216189662 -0700 PDT] [] 1000 18 187093087 ID:58349730 UpdateID:187093087 State:3 BatchSize:1000 Topology:"\x9bTM6\xeeh,\x7fT\xf1\xe9\x1f\xd4\x07X\x98T\xdb\x7fy\xd7\x0e\x84p\x04:\xe2m\x95E9J\x02" Topology:"\xdd4\x04ʧ\xdd\xdd<\x86\x85\x00{\x03\xdb\xd0rC\xcc\xe5<\xc6>\xf1~\x17\xe2\xcc\xcd`\xfcBm\x02" Topology:"\xdax\xa2\xe1f\x033!S\x9a1cX\xadKƗ\x90\x97c\xcc$|j\x9e\xc1Z\x9b\xc6@5%\x02" Topology:"\xd53\xc0\x1a\x9fm\x90-~D%kE\x1e+\xfc0d:R\xe20\xaa2\xa5\\N\x19\xb0e\xc5_\x02" Topology:"\xb59M\xf4w\xc6\x07\xec\xd61A\x02\xf9\xf3\x14\x9d\xf5\xd8F0\x84a\xea:\xcc\x10\x95&8du\x14\x02" Timestamps:1657227203 Timestamps:1657227203246307109 Timestamps:1657227209216187342 Timestamps:1657227212216189662 Timestamps:0 Timestamps:0 Timestamps:0 ResourceQueueTimeoutMillis:3906340864 AddressSpaceSize:18 EccSignature:{Nonce:"\xc3Ͼ\xc8T\xe1\xadE\x81\x94r\t\x14,\xfa\u008a\xfc8\x93h\xac\xf4e\xe4Y \xeb\xa5v\xa9\x82" Signature:"E$\xffjŲ\xfa/޿\xe6U@\x1d\xedp\xc4\xd7ջ\x88\xe1\xea?7\x8f\x837\xc2 ?\x99\xe5\xcc\xd7\xcd}\xadw`fPĸ\x06\x1bm\x84,\x02f\xce\xe4\x08\x96\x84K\x0c\x88wy\xfds\n"}}}
```
module connectAuthClientExample
go 1.17
require (
github.com/pkg/errors v0.9.1
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
)
require (
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/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/primitives v0.0.4-0.20220712193914-aebd8544396e // indirect
gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 // 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.
package main
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/e2e/receive"
)
// listener implements the receive.Listener interface
type listener struct {
name string
}
// Hear will be called whenever a message matching
// the RegisterListener call is received
// User-defined message handling logic goes here
func (l listener) Hear(item receive.Message) {
jww.INFO.Printf("Message received: %v", item)
}
// Name is used for debugging purposes
func (l listener) Name() string {
return l.name
}
package main
import (
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/client/xxdk"
"gitlab.com/elixxir/crypto/contact"
"io/fs"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// Logging
initLog(1, "client.log")
// Create a new client object----------------------------------------------
// Path to the server contact file
serverContactPath := "authConnServer.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` packages 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.ConnectWithAuthentication(recipientContact, messenger, params)
if err != nil {
jww.FATAL.Panicf("Failed to create connection object: %+v", err)
}
jww.INFO.Printf("Authenticated connection with %s successfully established!",
recipientContact.ID)
// Register a listener for messages----------------------------------------
// Listen for all types of messages using catalog.NoType
// User-defined behavior for message reception goes in the listener
_, err = handler.RegisterListener(catalog.NoType, listener{
name: "e2e Message Listener",
})
if err != nil {
jww.FATAL.Panicf("Could not register message listener: %+v", err)
}
// Send a message to the server--------------------------------------------
// Test message
msgBody := "If this message is sent successfully, we'll have established " +
"contact with the server."
roundIDs, messageID, timeSent, err := handler.SendE2E(
catalog.XxMessage, []byte(msgBody), params.Base)
if err != nil {
jww.FATAL.Panicf("Failed to send message: %+v", err)
}
jww.INFO.Printf("Message %v sent in RoundIDs: %+v at %v",
messageID, roundIDs, timeSent)
// 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 Authenticated Connection Server Example
This mini-respository contains the example logic for running a basic connection
server with authentication. This will be referred to as a "secure server" for brevity.
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
secure server is built on top. This program creates contact file
`authConnServer.xxc` which 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.
[`listener.go`](listener.go) contains logic for handling the reception of a message via the
established connection. In this example, it is very basic. We invite consumers
to use this as a basis to implement more complex message listeners.
## Build Instructions
In these instructions we will go over building a secure 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`.](../connectAuthClient/README.md).
In order to run a server, the following commands may be run:
```bash
cd connectAuthServer/
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 `authConnServer.xxc`, which is
the contact file for the server. A connection client may parse this file in
order to establish an authenticated connection with this server.
\ No newline at end of file
module connectAuthServerExample
go 1.17
require (
github.com/pkg/errors v0.9.1
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/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/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
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.
package main
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/e2e/receive"
)
// listener adheres to the receive.Listener interface.
type listener struct {
name string
}
// Hear will be called whenever a message matching the
// RegisterListener call is received.
//
// User-defined message handling logic goes here.
func (l *listener) Hear(item receive.Message) {
jww.INFO.Printf("Message received: %v", item)
}
// Name is used for debugging purposes.
func (l *listener) Name() string {
return l.name
}
package main
import (
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/connect"
"gitlab.com/elixxir/client/xxdk"
"io/fs"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// Logging
initLog(1, "server.log")
// Create a new client object----------------------------------------------
// Set the output contact file path
contactFilePath := "authConnServer.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---------------------------------------------
// Create callback for incoming connections
cb := func(connection connect.AuthenticatedConnection) {
jww.INFO.Printf("Authenticated connection established with %s",
connection.GetPartner().PartnerId())
// Listen for all types of messages using catalog.NoType
// User-defined behavior for message reception goes in the listener
_, err = connection.RegisterListener(
catalog.NoType, &listener{"connection server listener"})
if err != nil {
jww.FATAL.Panicf("Failed to register listener: %+v", err)
}
msgBody := "If this message is sent successfully, we'll have " +
"established contact with the client."
roundIDs, messageID, timeSent, err := connection.SendE2E(catalog.NoType,
[]byte(msgBody), e2eParams.Base)
if err != nil {
jww.FATAL.Panicf("Failed to send message: %+v", err)
}
jww.INFO.Printf("Message %v sent in RoundIDs: %+v at %v", messageID,
roundIDs, timeSent)
}
// Start connection server-------------------------------------------------
// Start the connection server, which will allow clients to start
//connections with you
authConnServer, err := connect.StartAuthenticatedServer(
identity, cb, net, e2eParams, connectionListParams)
if err != nil {
jww.FATAL.Panicf("Unable to start authenticated connection server: %+v",
err)
}
// Start network threads---------------------------------------------------
// Set networkFollowerTimeout to a value of your choice (seconds)
networkFollowerTimeout := 5 * time.Second
err = authConnServer.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
authConnServer.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 = authConnServer.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.
Please register or to comment