mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Merge pull request #91707 from Faless/ws/heartbeat
[WebSocket] Add optional heartbeat via "ping" control frames.
This commit is contained in:
commit
b85a4752cc
@ -155,6 +155,10 @@
|
|||||||
The extra HTTP headers to be sent during the WebSocket handshake.
|
The extra HTTP headers to be sent during the WebSocket handshake.
|
||||||
[b]Note:[/b] Not supported in Web exports due to browsers' restrictions.
|
[b]Note:[/b] Not supported in Web exports due to browsers' restrictions.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="heartbeat_interval" type="float" setter="set_heartbeat_interval" getter="get_heartbeat_interval" default="0.0">
|
||||||
|
The interval (in seconds) at which the peer will automatically send WebSocket "ping" control frames. When set to [code]0[/code], no "ping" control frames will be sent.
|
||||||
|
[b]Note:[/b] Has no effect in Web exports due to browser restrictions.
|
||||||
|
</member>
|
||||||
<member name="inbound_buffer_size" type="int" setter="set_inbound_buffer_size" getter="get_inbound_buffer_size" default="65535">
|
<member name="inbound_buffer_size" type="int" setter="set_inbound_buffer_size" getter="get_inbound_buffer_size" default="65535">
|
||||||
The size of the input buffer in bytes (roughly the maximum amount of memory that will be allocated for the inbound packets).
|
The size of the input buffer in bytes (roughly the maximum amount of memory that will be allocated for the inbound packets).
|
||||||
</member>
|
</member>
|
||||||
|
@ -70,6 +70,9 @@ void WebSocketPeer::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("set_max_queued_packets", "buffer_size"), &WebSocketPeer::set_max_queued_packets);
|
ClassDB::bind_method(D_METHOD("set_max_queued_packets", "buffer_size"), &WebSocketPeer::set_max_queued_packets);
|
||||||
ClassDB::bind_method(D_METHOD("get_max_queued_packets"), &WebSocketPeer::get_max_queued_packets);
|
ClassDB::bind_method(D_METHOD("get_max_queued_packets"), &WebSocketPeer::get_max_queued_packets);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_heartbeat_interval", "interval"), &WebSocketPeer::set_heartbeat_interval);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_heartbeat_interval"), &WebSocketPeer::get_heartbeat_interval);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "supported_protocols"), "set_supported_protocols", "get_supported_protocols");
|
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "supported_protocols"), "set_supported_protocols", "get_supported_protocols");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "handshake_headers"), "set_handshake_headers", "get_handshake_headers");
|
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "handshake_headers"), "set_handshake_headers", "get_handshake_headers");
|
||||||
|
|
||||||
@ -78,6 +81,8 @@ void WebSocketPeer::_bind_methods() {
|
|||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_queued_packets"), "set_max_queued_packets", "get_max_queued_packets");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_queued_packets"), "set_max_queued_packets", "get_max_queued_packets");
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "heartbeat_interval"), "set_heartbeat_interval", "get_heartbeat_interval");
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(WRITE_MODE_TEXT);
|
BIND_ENUM_CONSTANT(WRITE_MODE_TEXT);
|
||||||
BIND_ENUM_CONSTANT(WRITE_MODE_BINARY);
|
BIND_ENUM_CONSTANT(WRITE_MODE_BINARY);
|
||||||
|
|
||||||
@ -151,3 +156,12 @@ void WebSocketPeer::set_max_queued_packets(int p_max_queued_packets) {
|
|||||||
int WebSocketPeer::get_max_queued_packets() const {
|
int WebSocketPeer::get_max_queued_packets() const {
|
||||||
return max_queued_packets;
|
return max_queued_packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double WebSocketPeer::get_heartbeat_interval() const {
|
||||||
|
return heartbeat_interval_msec / 1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketPeer::set_heartbeat_interval(double p_interval) {
|
||||||
|
ERR_FAIL_COND(p_interval < 0);
|
||||||
|
heartbeat_interval_msec = p_interval * 1000.0;
|
||||||
|
}
|
||||||
|
@ -72,6 +72,7 @@ protected:
|
|||||||
int outbound_buffer_size = DEFAULT_BUFFER_SIZE;
|
int outbound_buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
int inbound_buffer_size = DEFAULT_BUFFER_SIZE;
|
int inbound_buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
int max_queued_packets = 2048;
|
int max_queued_packets = 2048;
|
||||||
|
uint64_t heartbeat_interval_msec = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static WebSocketPeer *create(bool p_notify_postinitialize = true) {
|
static WebSocketPeer *create(bool p_notify_postinitialize = true) {
|
||||||
@ -117,6 +118,9 @@ public:
|
|||||||
void set_max_queued_packets(int p_max_queued_packets);
|
void set_max_queued_packets(int p_max_queued_packets);
|
||||||
int get_max_queued_packets() const;
|
int get_max_queued_packets() const;
|
||||||
|
|
||||||
|
double get_heartbeat_interval() const;
|
||||||
|
void set_heartbeat_interval(double p_interval);
|
||||||
|
|
||||||
WebSocketPeer();
|
WebSocketPeer();
|
||||||
~WebSocketPeer();
|
~WebSocketPeer();
|
||||||
};
|
};
|
||||||
|
@ -636,7 +636,10 @@ void WSLPeer::_wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct w
|
|||||||
uint8_t is_string = arg->opcode == WSLAY_TEXT_FRAME ? 1 : 0;
|
uint8_t is_string = arg->opcode == WSLAY_TEXT_FRAME ? 1 : 0;
|
||||||
peer->in_buffer.write_packet(arg->msg, arg->msg_length, &is_string);
|
peer->in_buffer.write_packet(arg->msg, arg->msg_length, &is_string);
|
||||||
}
|
}
|
||||||
// Ping or pong.
|
if (op == WSLAY_PONG) {
|
||||||
|
peer->heartbeat_waiting = false;
|
||||||
|
}
|
||||||
|
// Pong.
|
||||||
}
|
}
|
||||||
|
|
||||||
wslay_event_callbacks WSLPeer::_wsl_callbacks = {
|
wslay_event_callbacks WSLPeer::_wsl_callbacks = {
|
||||||
@ -680,7 +683,31 @@ void WSLPeer::poll() {
|
|||||||
|
|
||||||
if (ready_state == STATE_OPEN || ready_state == STATE_CLOSING) {
|
if (ready_state == STATE_OPEN || ready_state == STATE_CLOSING) {
|
||||||
ERR_FAIL_NULL(wsl_ctx);
|
ERR_FAIL_NULL(wsl_ctx);
|
||||||
|
uint64_t ticks = OS::get_singleton()->get_ticks_msec();
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
if (heartbeat_interval_msec != 0 && ticks - last_heartbeat > heartbeat_interval_msec && ready_state == STATE_OPEN) {
|
||||||
|
if (heartbeat_waiting) {
|
||||||
|
wslay_event_context_free(wsl_ctx);
|
||||||
|
wsl_ctx = nullptr;
|
||||||
|
close(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
heartbeat_waiting = true;
|
||||||
|
struct wslay_event_msg msg;
|
||||||
|
msg.opcode = WSLAY_PING;
|
||||||
|
msg.msg = nullptr;
|
||||||
|
msg.msg_length = 0;
|
||||||
|
err = wslay_event_queue_msg(wsl_ctx, &msg);
|
||||||
|
if (err == 0) {
|
||||||
|
last_heartbeat = ticks;
|
||||||
|
} else {
|
||||||
|
print_verbose("Websocket (wslay) failed to send ping: " + itos(err));
|
||||||
|
wslay_event_context_free(wsl_ctx);
|
||||||
|
wsl_ctx = nullptr;
|
||||||
|
close(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((err = wslay_event_recv(wsl_ctx)) != 0 || (err = wslay_event_send(wsl_ctx)) != 0) {
|
if ((err = wslay_event_recv(wsl_ctx)) != 0 || (err = wslay_event_send(wsl_ctx)) != 0) {
|
||||||
// Error close.
|
// Error close.
|
||||||
print_verbose("Websocket (wslay) poll error: " + itos(err));
|
print_verbose("Websocket (wslay) poll error: " + itos(err));
|
||||||
@ -781,6 +808,7 @@ void WSLPeer::close(int p_code, String p_reason) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
heartbeat_waiting = false;
|
||||||
in_buffer.clear();
|
in_buffer.clear();
|
||||||
packet_buffer.resize(0);
|
packet_buffer.resize(0);
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@ private:
|
|||||||
int close_code = -1;
|
int close_code = -1;
|
||||||
String close_reason;
|
String close_reason;
|
||||||
uint8_t was_string = 0;
|
uint8_t was_string = 0;
|
||||||
|
uint64_t last_heartbeat = 0;
|
||||||
|
bool heartbeat_waiting = false;
|
||||||
|
|
||||||
// WebSocket configuration.
|
// WebSocket configuration.
|
||||||
bool use_tls = true;
|
bool use_tls = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user