Skip to content
Snippets Groups Projects
node.hpp 3.26 KiB
Newer Older
Nicolas Pope's avatar
Nicolas Pope committed
/**
 * @file node.hpp
 * @copyright Copyright (c) 2022 University of Turku, MIT License
 * @author Nicolas Pope
 */

#pragma once

#include <memory>
#include <string>
#include <ftl/uuid.hpp>
Nicolas Pope's avatar
Nicolas Pope committed

namespace ftl {
namespace net {
class Peer;
using PeerPtr = std::shared_ptr<Peer>;
Nicolas Pope's avatar
Nicolas Pope committed
}

namespace protocol {

enum struct NodeType {
    kNode,
    kWebService,
};

enum struct NodeStatus {
    kInvalid,       // no socket
    kConnecting,    // socket created, no handshake yet
    kConnected,     // connection fully established
    kDisconnected,  // socket closed, reconnect not possible
    kReconnecting   // socket closed, call reconnect() to try reconnecting
Nicolas Pope's avatar
Nicolas Pope committed
};

/**
 * @brief An API wrapper for a network connection. This object provides the
 * available RPC calls and connection status or control methods. Note that
 * releasing the shared pointer will not result in connection termination,
 * it must be closed and then released for the garbage collection to happen.
 * 
Nicolas Pope's avatar
Nicolas Pope committed
 */
class Node {
 public:
    /** Peer for outgoing connection: resolve address and connect */
    explicit Node(const ftl::net::PeerPtr &impl);
    virtual ~Node();

    /**
     * Close the peer if open. Setting retry parameter to true will initiate
     * backoff retry attempts. This is used to deliberately close a connection
     * and not for error conditions where different close semantics apply.
     * 
     * @param retry Should reconnection be attempted?
     */
    void close(bool retry = false);

    bool isConnected() const;
    /**
     * Block until the connection and handshake has completed. You should use
     * onConnect callbacks instead of blocking, mostly this is intended for
     * the unit tests to keep them synchronous.
     * 
     * @return True if all connections were successful, false if timeout or error.
     */
    bool waitConnection(int seconds = 1);

    /**
     * Make a reconnect attempt. Called internally by Universe object.
     */
    bool reconnect();

    bool isOutgoing() const;

    /**
     * Test if the connection is valid. This returns true in all conditions
     * except where the socket has been disconnected permenantly, or was never
     * able to connect, perhaps due to an invalid address, or is in middle of a
     * reconnect attempt. (Valid states: kConnecting, kConnected)
     * 
     * Should return true only in cases when valid OS socket exists.
     */
    bool isValid() const;

    /** node type */
    virtual NodeType getType() const { return NodeType::kNode; }

    NodeStatus status() const;
    uint32_t getFTLVersion() const;
    uint8_t getFTLMajor() const { return getFTLVersion() >> 16; }
    uint8_t getFTLMinor() const { return (getFTLVersion() >> 8) & 0xFF; }
    uint8_t getFTLPatch() const { return getFTLVersion() & 0xFF; }

    /**
     * Get the sockets protocol, address and port as a url string. This will be
     * the same as the initial connection string on the client.
     */
    std::string getURI() const;

    /**
     * Get the UUID for this peer.
     */
    const ftl::UUID &id() const;

    /**
     * Get the peer id as a string.
     */
    std::string to_string() const;

    void noReconnect();

    unsigned int localID();

    int connectionCount() const;

 protected:
    ftl::net::PeerPtr peer_;
Nicolas Pope's avatar
Nicolas Pope committed
};

}  // namespace protocol
}  // namespace ftl