OverviewFilesCommitsIssuesDocsReleasesPeers

hyperswarm-peer / src / hyperswarm_peer.h

187 lines · c ref:
#ifndef HYPERSWARM_MULTIPLAYER_PEER_H
#define HYPERSWARM_MULTIPLAYER_PEER_H

#include <godot_cpp/classes/multiplayer_peer_extension.hpp>
#include <godot_cpp/core/binder_common.hpp>

#include "packet_queue.h"
#include "udx_transport.h"

namespace godot {

class HyperswarmMultiplayerPeer : public MultiplayerPeerExtension {
	GDCLASS(HyperswarmMultiplayerPeer, MultiplayerPeerExtension)

private:
	UdxTransport _transport;

public:
	// C++-only accessor, so a sibling extension class (the overlay) can attach its
	// own protocol to these connections. Not bound to Godot: handing a raw
	// transport pointer to GDScript would be a way to corrupt the loop from the
	// main thread.
	UdxTransport *transport_internal() { return &_transport; }

private:

	// Multiplayer state.
	int32_t _unique_id;
	int32_t _target_peer;
	int32_t _transfer_channel;
	TransferMode _transfer_mode;
	ConnectionStatus _connection_status;
	bool _is_server_peer;
	bool _refuse_connections;

	// Current packet being read by Godot (must persist between _get_packet calls).
	Packet _current_packet;
	bool _has_current_packet;

protected:
	static void _bind_methods();

public:
	HyperswarmMultiplayerPeer();
	~HyperswarmMultiplayerPeer() override;

	// ---- Custom methods exposed to GDScript ----

	// Create a server listening on the given port (unencrypted).
	Error create_server(int port);

	// Connect to a server at address:port (unencrypted).
	Error create_client(const String &address, int port);

	// Generate a new Curve25519 keypair for Noise encryption.
	// Returns: {public_key: PackedByteArray, secret_key: PackedByteArray}
	Dictionary generate_keypair();

	// Create a Noise-encrypted server with the given keypair.
	Error create_server_with_keypair(int port, const PackedByteArray &public_key,
									 const PackedByteArray &secret_key);

	// Connect to a Noise-encrypted server. Remote public key is used
	// to verify the server's identity during the Noise XX handshake.
	Error create_client_with_key(const String &address, int port,
								 const PackedByteArray &remote_public_key);

	// Get the remote peer's verified public key after Noise handshake.
	// Returns empty PackedByteArray if not encrypted or handshake not complete.
	PackedByteArray get_peer_public_key(int peer_id) const;

	// Get networking stats.
	Dictionary get_stats() const;

	// Get per-peer RTT stats (srtt, rttvar, rto, min_rtt) in milliseconds.
	Dictionary get_peer_rtt(int peer_id) const;

	// ---- DHT Discovery API ----

	// Generate a new Ed25519 keypair for DHT identity.
	// Returns: {public_key: PackedByteArray(32), secret_key: PackedByteArray(64)}
	Dictionary generate_dht_keypair();

	// Join the DHT network with Ed25519 keypair and optional bootstrap nodes.
	// Starts the transport if not already running.
	Error join_dht(const PackedByteArray &public_key, const PackedByteArray &secret_key,
				   const PackedStringArray &bootstrap_nodes = PackedStringArray());

	// Connect to a remote peer by their Ed25519 public key (via DHT discovery).
	Error connect_to_peer(const PackedByteArray &remote_public_key);

	// Start listening for incoming DHT connections.
	Error listen_on_dht();

	// Announce a 32-byte topic on the DHT.
	Error announce_topic(const PackedByteArray &topic);

	// Lookup a 32-byte topic on the DHT.
	Error lookup_topic(const PackedByteArray &topic);

	// Join a topic with server and/or client mode (session-counted, auto-refresh).
	// Matches JS Hyperswarm.join(topic, {server, client}).
	Error join_topic(const PackedByteArray &topic, bool server, bool client);

	// Leave a topic (decrements session; unannounces when server sessions reach 0).
	// Matches JS Hyperswarm.leave(topic).
	Error leave_topic(const PackedByteArray &topic);

	// Get DHT status info.
	Dictionary get_dht_status() const;

	// ---- Swarm Manager API ----

	// Join a topic with auto-connect, retry, and priority management.
	// Equivalent to JS: const swarm = new Hyperswarm(); swarm.join(topic)
	Error swarm_join(const PackedByteArray &topic, bool server, bool client);

	// Leave a swarm topic.
	Error swarm_leave(const PackedByteArray &topic);

	// Add an explicit peer by public key (direct connect, not topic-based).
	Error swarm_join_peer(const PackedByteArray &public_key);

	// Remove an explicit peer.
	Error swarm_leave_peer(const PackedByteArray &public_key);

	// Get SwarmManager diagnostic status.
	Dictionary get_swarm_status() const;

	// Get per-connection diagnostics (Array of Dictionary, one per active DhtConnection).
	Array get_connection_diagnostics() const;

	// ---- DHT Storage API ----

	// Store an immutable value on the DHT. key = BLAKE2b(value).
	// Result emitted via dht_put_complete signal.
	Error dht_put(const PackedByteArray &data);

	// Retrieve an immutable value from the DHT by key.
	// Result emitted via dht_get_complete signal.
	Error dht_get(const PackedByteArray &key);

	// Store a mutable value signed with our DHT keypair.
	// Result emitted via dht_mutable_put_complete signal.
	Error dht_mutable_put(const PackedByteArray &data, int seq);

	// Retrieve a mutable value by public key.
	// Result emitted via dht_mutable_get_complete signal.
	Error dht_mutable_get(const PackedByteArray &public_key, int min_seq);

	// ---- Required MultiplayerPeerExtension overrides ----

	void _close() override;
	void _disconnect_peer(int32_t p_peer, bool p_force) override;

	Error _get_packet(const uint8_t **r_buffer, int32_t *r_buffer_size) override;
	Error _put_packet(const uint8_t *p_buffer, int32_t p_buffer_size) override;
	int32_t _get_available_packet_count() const override;
	int32_t _get_max_packet_size() const override;

	int32_t _get_packet_peer() const override;
	int32_t _get_packet_channel() const override;
	MultiplayerPeer::TransferMode _get_packet_mode() const override;

	ConnectionStatus _get_connection_status() const override;
	int32_t _get_unique_id() const override;
	bool _is_server() const override;

	void _set_target_peer(int32_t p_peer) override;
	void _set_transfer_channel(int32_t p_channel) override;
	void _set_transfer_mode(MultiplayerPeer::TransferMode p_mode) override;
	int32_t _get_transfer_channel() const override;
	MultiplayerPeer::TransferMode _get_transfer_mode() const override;

	void _poll() override;

	// ---- Optional overrides ----

	void _set_refuse_new_connections(bool p_enable) override;
	bool _is_refusing_new_connections() const override;
	bool _is_server_relay_supported() const override;
};

} // namespace godot

#endif // HYPERSWARM_MULTIPLAYER_PEER_H