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

Write restlike server example (single use)

parent bbe4e492
No related branches found
No related tags found
1 merge request!2Write restlike server example (single use)
# xxdk Connection Server Example
module restlikeServerExample
go 1.18
require (
github.com/pkg/errors v0.9.1
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/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 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/restlike/single"
"gitlab.com/elixxir/client/xxdk"
"gitlab.com/elixxir/crypto/cyclic"
"io/fs"
"io/ioutil"
"os"
"time"
)
func main() {
// Logging
initLog(1, "client.log")
// Create a new client object----------------------------------------------
// NOTE: For some (or all) of these parameters, you may want to use a
// configuration tool of some kind
// Set the output contact file path
contactFilePath := "restlikeServer.xxc"
// Set state file 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 using the state file
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()
baseClient, 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, baseClient)
if err != nil {
// If no extant xxdk.ReceptionIdentity, generate and store a new one
identity, err = xxdk.MakeReceptionIdentity(baseClient)
if err != nil {
jww.FATAL.Panicf("Failed to generate reception identity: %+v", err)
}
err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, baseClient)
if err != nil {
jww.FATAL.Panicf("Failed to store new reception identity: %+v", err)
}
}
// Create an E2E client
// The 'restlike' package handles AuthCallbacks,
// xxdk.DefaultAuthCallbacks is fine here
params := xxdk.GetDefaultE2EParams()
jww.INFO.Printf("Using E2E parameters: %+v", params)
e2eClient, err := xxdk.Login(baseClient, xxdk.DefaultAuthCallbacks{},
identity, params)
if err != nil {
jww.FATAL.Panicf("Unable to Login: %+v", err)
}
// Save contact file-------------------------------------------------------
// Save the contact file so that client can connect to this server
writeContact(contactFilePath, identity.GetContact())
// Start rest-like single use server---------------------------------------
// Pull the reception
receptionIdentity := e2eClient.GetReceptionIdentity()
dhKeyPriv := &cyclic.Int{}
err = dhKeyPriv.UnmarshalJSON(receptionIdentity.DHKeyPrivate)
if err != nil {
jww.FATAL.Panicf("Unable to read diffie-hellman private key: %+v", err)
}
// Initialize the server
single.NewServer(receptionIdentity.ID, dhPrivateKey,
e2eClient.GetE2E().GetGroup(), e2eClient.GetCmix())
// Start network threads---------------------------------------------------
// Set networkFollowerTimeout to a value of your choice (seconds)
networkFollowerTimeout := 5 * time.Second
err = e2eClient.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
e2eClient.GetCmix().AddHealthCallback(
func(isConnected bool) {
connected <- isConnected
})
// Wait until connected or crash on timeout
waitUntilConnected(connected)
// Keep app running to receive messages------------------------------------
// NOTE: Some consumers may desire some implemented exit condition
// handling (SIGKILL, SIGABRT, etc.). That can be done here.
select {}
}
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