tu-wien
/
kerma
Archived
2
0
Fork 0
This repository has been archived on 2023-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
kerma/utils/client.go

168 lines
3.8 KiB
Go

// Package utils provides utilities that are needed for the functioning of Kerma
package utils
import (
"bufio"
"errors"
"kerma/helpers"
"kerma/models"
"net"
"time"
"github.com/docker/go/canonical/json"
)
/*
A Client represents a Kerma client with the following properties:
- State - the current state of the application
- Handler - a TCPHandler that is used to handle requests to and from remote peers
- Logger
*/
type Client struct {
State *models.State
Handler TCPHandler
Logger helpers.Logger
}
/*
Construct creates a new client with the specified state and handler objects
*/
func (c *Client) Construct(state *models.State, h TCPHandler) {
c.State = state
c.Handler = h
}
/*
InitHandshake initiates a handshake on the specified connection
*/
func (c *Client) InitHandshake(peerName string) {
var resp models.Hello
resp.Construct()
respJSON, _ := json.MarshalCanonical(resp)
c.Handler.Output(respJSON)
c.Handler.Conn.SetDeadline(time.Now().Add(time.Duration(c.State.Config.ConnTimeout) * time.Second))
in, err := bufio.NewReader(c.Handler.Conn).ReadBytes('\n')
if err != nil {
c.Logger.Error(err.Error())
if errors.Is(err, net.ErrClosed) {
c.State.RemovePeerByName(peerName)
} else {
c.Handler.Fail("Failed reading message")
}
return
}
msg, err := c.Handler.Input(in)
if err != nil {
c.Logger.Error(err.Error())
c.Handler.Fail("Failed parsing message")
return
}
msgJSON, err := json.MarshalCanonical(msg)
if err != nil {
c.Logger.Error("Failed parsing message " + err.Error())
c.Handler.Fail("Failed parsing message")
return
}
if msgType, ok := msg["type"]; ok {
if msgType == "hello" {
var helloReq models.Hello
err := helloReq.UnmarshalJSON(msgJSON)
if err == nil {
c.Logger.Info("Constructing handshake with " + c.Handler.GetRemotePeer())
c.State.CompleteHandshake(peerName)
} else {
c.Handler.Fail("Hello response invalid")
return
}
} else {
c.Handler.Fail("Response type not expected " + msgType.(string))
return
}
} else {
c.Handler.Fail("Response type not specified")
return
}
}
/*
DiscoverPeers requests remote peers from a known peer
*/
func (c *Client) DiscoverPeers(peerName string) {
if c.State.CheckForHandshake(peerName) {
var req models.Generic
req.BuildPeerRequest()
reqJSON, _ := req.MarshalJson()
c.Handler.Output(reqJSON)
}
}
/*
DiscoverChainTip requests chaintip from a known peer
*/
func (c *Client) DiscoverChainTip(peerName string) {
if c.State.CheckForHandshake(peerName) {
var req models.Generic
req.BuildChainTipRequest()
reqJSON, _ := req.MarshalJson()
c.Handler.Output(reqJSON)
}
}
/*
DiscoverMempool requests mempool from a known peer
*/
func (c *Client) DiscoverMempool(peerName string) {
if c.State.CheckForHandshake(peerName) {
var req models.Generic
req.BuildMempoolRequest()
reqJSON, _ := req.MarshalJson()
c.Handler.Output(reqJSON)
}
}
/*
DiscoverObject requests remote objects from a known peer
*/
func (c *Client) DiscoverObject(peerName string, objectID string) {
if c.State.CheckForHandshake(peerName) {
var req models.ObjectWrapper
req.BuildObjectRequest(objectID)
reqJSON, _ := req.MarshalJson()
c.Handler.Output(reqJSON)
}
}
/*
GossipBlocks sends information about local blocks to peer
*/
func (c *Client) GossipBlocks(peerName string) {
if c.State.CheckForHandshake(peerName) {
for _, block := range c.State.Chain {
var req models.ObjectWrapper
bid := block.GetID()
req.BuildGossipObject(bid)
reqJSON, _ := req.MarshalJson()
c.Handler.Output(reqJSON)
}
}
}
/*
GossipTransactions sends information about local transactions to peer
*/
func (c *Client) GossipTransactions(peerName string) {
if c.State.CheckForHandshake(peerName) {
for txid := range c.State.Transactions {
var req models.ObjectWrapper
req.BuildGossipObject(txid)
reqJSON, _ := req.MarshalJson()
c.Handler.Output(reqJSON)
}
}
}