Skip to content
Snippets Groups Projects
plugin.go 4.27 KiB
package client

import (
    "github.com/iotaledger/goshimmer/packages/accountability"
    "github.com/iotaledger/goshimmer/packages/daemon"
    "github.com/iotaledger/goshimmer/packages/network"
    "github.com/iotaledger/goshimmer/packages/node"
    "github.com/iotaledger/goshimmer/plugins/analysis/types/addnode"
    "github.com/iotaledger/goshimmer/plugins/analysis/types/connectnodes"
    "github.com/iotaledger/goshimmer/plugins/analysis/types/ping"
    "github.com/iotaledger/goshimmer/plugins/autopeering/protocol"
    "github.com/iotaledger/goshimmer/plugins/autopeering/types/peer"
    "github.com/iotaledger/goshimmer/plugins/autopeering/types/request"
    "github.com/iotaledger/goshimmer/plugins/autopeering/types/response"
    "github.com/iotaledger/goshimmer/plugins/gossip/neighbormanager"
    "net"
    "time"
)

func Run(plugin *node.Plugin) {
    daemon.BackgroundWorker(func() {
        shuttingDown := false
        for !shuttingDown {
            if conn, err := net.Dial("tcp", *SERVER_ADDRESS.Value); err != nil {
                plugin.LogDebug("Could not connect to reporting server: " + err.Error())
            } else {
                managedConn := network.NewManagedConnection(conn)
                eventDispatchers := getEventDispatchers(managedConn)

                reportCurrentStatus(eventDispatchers)
                setupHooks(managedConn, eventDispatchers)

                shuttingDown = keepConnectionAlive(managedConn)
            }
        }
    })
}

func getEventDispatchers(conn *network.ManagedConnection) *EventDispatchers {
    return &EventDispatchers{
        AddNode: func(nodeId []byte) {
            conn.Write((&addnode.Packet{ NodeId: nodeId }).Marshal())
        },
        ConnectNodes: func(sourceId []byte, targetId []byte) {
            conn.Write((&connectnodes.Packet{ SourceId: sourceId, TargetId: targetId }).Marshal())
        },
    }
}

func reportCurrentStatus(eventDispatchers *EventDispatchers) {
    eventDispatchers.AddNode(accountability.OWN_ID.Identifier)

    reportChosenNeighbors(eventDispatchers)
}

func setupHooks(conn *network.ManagedConnection, eventDispatchers *EventDispatchers) {
    // define hooks ////////////////////////////////////////////////////////////////////////////////////////////////////

    onDiscoverPeer := func(p *peer.Peer) {
        eventDispatchers.AddNode(p.Identity.Identifier)
    }

    onIncomingRequestAccepted := func(req *request.Request) {
        eventDispatchers.ConnectNodes(req.Issuer.Identity.Identifier, accountability.OWN_ID.Identifier)
    }

    onOutgoingRequestAccepted := func(res *response.Response) {
        eventDispatchers.ConnectNodes(accountability.OWN_ID.Identifier, res.Issuer.Identity.Identifier)
    }
    // setup hooks /////////////////////////////////////////////////////////////////////////////////////////////////////

    protocol.Events.DiscoverPeer.Attach(onDiscoverPeer)
    protocol.Events.IncomingRequestAccepted.Attach(onIncomingRequestAccepted)
    protocol.Events.OutgoingRequestAccepted.Attach(onOutgoingRequestAccepted)

    // clean up hooks on close /////////////////////////////////////////////////////////////////////////////////////////

    var onClose func()
    onClose = func() {
        protocol.Events.DiscoverPeer.Detach(onDiscoverPeer)
        protocol.Events.IncomingRequestAccepted.Detach(onIncomingRequestAccepted)
        protocol.Events.OutgoingRequestAccepted.Detach(onOutgoingRequestAccepted)

        conn.Events.Close.Detach(onClose)
    }
    conn.Events.Close.Attach(onClose)
}

func reportChosenNeighbors(dispatchers *EventDispatchers) {
    for _, chosenNeighbor := range neighbormanager.CHOSEN_NEIGHBORS {
        dispatchers.AddNode(chosenNeighbor.Identity.Identifier)
    }
    for _, chosenNeighbor := range neighbormanager.CHOSEN_NEIGHBORS {
        dispatchers.ConnectNodes(accountability.OWN_ID.Identifier, chosenNeighbor.Identity.Identifier)
    }
}

func keepConnectionAlive(conn *network.ManagedConnection) bool {
    go conn.Read(make([]byte, 1))

    ticker := time.NewTicker(1 * time.Second)
    for {
        select {
            case <- daemon.ShutdownSignal:
                return true

            case <- ticker.C:
                if _, err := conn.Write((&ping.Packet{}).Marshal()); err != nil {
                    return false
                }
        }
    }
}