-
Notifications
You must be signed in to change notification settings - Fork 114
fix(pb): get new actor ids working e2e #2471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,11 +6,13 @@ authors = ["Rivet Gaming, LLC <[email protected]>"] | |
license = "Apache-2.0" | ||
|
||
[dependencies] | ||
anyhow = "1.0" | ||
bytes = "1.0" | ||
futures-util = "0.3" | ||
http = "0.2" | ||
serde = { version = "1.0", features = ["derive"] } | ||
serde_json = "1.0" | ||
tokio = { version = "1.40", features = ["full",] } | ||
tokio-tungstenite = "0.23.1" | ||
tokio-util = "0.7" | ||
uuid = { version = "1", features = ["v4", "serde"] } | ||
warp = "0.3.7" |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,10 +1,12 @@ | ||||||||||||||||||||||||||||||||||||||||||||
use std::{env, net::SocketAddr, sync::Arc, time::Duration}; | ||||||||||||||||||||||||||||||||||||||||||||
use std::{env, io::Cursor, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
use anyhow::*; | ||||||||||||||||||||||||||||||||||||||||||||
use bytes::Bytes; | ||||||||||||||||||||||||||||||||||||||||||||
use futures_util::{SinkExt, StreamExt}; | ||||||||||||||||||||||||||||||||||||||||||||
use serde::{de::DeserializeOwned, Serialize}; | ||||||||||||||||||||||||||||||||||||||||||||
use serde_json::json; | ||||||||||||||||||||||||||||||||||||||||||||
use tokio::sync::Mutex; | ||||||||||||||||||||||||||||||||||||||||||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; | ||||||||||||||||||||||||||||||||||||||||||||
use uuid::Uuid; | ||||||||||||||||||||||||||||||||||||||||||||
use tokio::{net::UnixStream, sync::Mutex}; | ||||||||||||||||||||||||||||||||||||||||||||
use tokio_util::codec::{Framed, LengthDelimitedCodec}; | ||||||||||||||||||||||||||||||||||||||||||||
use warp::Filter; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
const PING_INTERVAL: Duration = Duration::from_secs(1); | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -18,20 +20,20 @@ async fn main() { | |||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Get manager connection details from env vars | ||||||||||||||||||||||||||||||||||||||||||||
let manager_ip = env::var("RIVET_MANAGER_IP").expect("RIVET_MANAGER_IP not set"); | ||||||||||||||||||||||||||||||||||||||||||||
let manager_port = env::var("RIVET_MANAGER_PORT").expect("RIVET_MANAGER_PORT not set"); | ||||||||||||||||||||||||||||||||||||||||||||
let manager_addr = format!("ws://{}:{}", manager_ip, manager_port); | ||||||||||||||||||||||||||||||||||||||||||||
let manager_socket_path = PathBuf::from( | ||||||||||||||||||||||||||||||||||||||||||||
env::var("RIVET_MANAGER_SOCKET_PATH").expect("RIVET_MANAGER_SOCKET_PATH not set"), | ||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Get HTTP server port from env var or use default | ||||||||||||||||||||||||||||||||||||||||||||
let http_port = env::var("PORT_MAIN") | ||||||||||||||||||||||||||||||||||||||||||||
.expect("PORT_MAIN not set") | ||||||||||||||||||||||||||||||||||||||||||||
.parse::<u16>() | ||||||||||||||||||||||||||||||||||||||||||||
.expect("bad PORT_MAIN"); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Spawn the WebSocket client | ||||||||||||||||||||||||||||||||||||||||||||
// Spawn the unix socket client | ||||||||||||||||||||||||||||||||||||||||||||
tokio::spawn(async move { | ||||||||||||||||||||||||||||||||||||||||||||
if let Err(e) = run_websocket_client(&manager_addr).await { | ||||||||||||||||||||||||||||||||||||||||||||
eprintln!("WebSocket client error: {}", e); | ||||||||||||||||||||||||||||||||||||||||||||
if let Err(e) = run_socket_client(manager_socket_path).await { | ||||||||||||||||||||||||||||||||||||||||||||
eprintln!("Socket client error: {}", e); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
@@ -53,25 +55,28 @@ async fn main() { | |||||||||||||||||||||||||||||||||||||||||||
warp::serve(echo).run(http_addr).await; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
async fn run_websocket_client(url: &str) -> Result<(), Box<dyn std::error::Error>> { | ||||||||||||||||||||||||||||||||||||||||||||
println!("Connecting to WebSocket at {}", url); | ||||||||||||||||||||||||||||||||||||||||||||
async fn run_socket_client(socket_path: PathBuf) -> Result<()> { | ||||||||||||||||||||||||||||||||||||||||||||
println!("Connecting to socket at {}", socket_path.display()); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Connect to the WebSocket server | ||||||||||||||||||||||||||||||||||||||||||||
let (ws_stream, _) = connect_async(url).await?; | ||||||||||||||||||||||||||||||||||||||||||||
println!("WebSocket connection established"); | ||||||||||||||||||||||||||||||||||||||||||||
// Connect to the socket server | ||||||||||||||||||||||||||||||||||||||||||||
let stream = UnixStream::connect(socket_path).await?; | ||||||||||||||||||||||||||||||||||||||||||||
println!("Socket connection established"); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Split the stream | ||||||||||||||||||||||||||||||||||||||||||||
let (mut write, mut read) = ws_stream.split(); | ||||||||||||||||||||||||||||||||||||||||||||
let codec = LengthDelimitedCodec::builder() | ||||||||||||||||||||||||||||||||||||||||||||
.length_field_type::<u32>() | ||||||||||||||||||||||||||||||||||||||||||||
.length_field_length(4) | ||||||||||||||||||||||||||||||||||||||||||||
// No offset | ||||||||||||||||||||||||||||||||||||||||||||
.length_field_offset(0) | ||||||||||||||||||||||||||||||||||||||||||||
// Header length is not included in the length calculation | ||||||||||||||||||||||||||||||||||||||||||||
.length_adjustment(4) | ||||||||||||||||||||||||||||||||||||||||||||
// header is included in the returned bytes | ||||||||||||||||||||||||||||||||||||||||||||
.num_skip(0) | ||||||||||||||||||||||||||||||||||||||||||||
.new_codec(); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
let payload = json!({ | ||||||||||||||||||||||||||||||||||||||||||||
"init": { | ||||||||||||||||||||||||||||||||||||||||||||
"access_token": env::var("RIVET_ACCESS_TOKEN").expect("RIVET_ACCESS_TOKEN not set"), | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
let framed = Framed::new(stream, codec); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
let data = serde_json::to_vec(&payload)?; | ||||||||||||||||||||||||||||||||||||||||||||
write.send(Message::Binary(data)).await?; | ||||||||||||||||||||||||||||||||||||||||||||
println!("Sent init message"); | ||||||||||||||||||||||||||||||||||||||||||||
// Split the stream | ||||||||||||||||||||||||||||||||||||||||||||
let (write, mut read) = framed.split(); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Ping thread | ||||||||||||||||||||||||||||||||||||||||||||
let write = Arc::new(Mutex::new(write)); | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -80,10 +85,14 @@ async fn run_websocket_client(url: &str) -> Result<(), Box<dyn std::error::Error | |||||||||||||||||||||||||||||||||||||||||||
loop { | ||||||||||||||||||||||||||||||||||||||||||||
tokio::time::sleep(PING_INTERVAL).await; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
let payload = json!({ | ||||||||||||||||||||||||||||||||||||||||||||
"ping": {} | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
if write2 | ||||||||||||||||||||||||||||||||||||||||||||
.lock() | ||||||||||||||||||||||||||||||||||||||||||||
.await | ||||||||||||||||||||||||||||||||||||||||||||
.send(Message::Ping(Vec::new())) | ||||||||||||||||||||||||||||||||||||||||||||
.send(encode_frame(&payload).unwrap()) | ||||||||||||||||||||||||||||||||||||||||||||
.await | ||||||||||||||||||||||||||||||||||||||||||||
.is_err() | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -93,53 +102,61 @@ async fn run_websocket_client(url: &str) -> Result<(), Box<dyn std::error::Error | |||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Process incoming messages | ||||||||||||||||||||||||||||||||||||||||||||
while let Some(message) = read.next().await { | ||||||||||||||||||||||||||||||||||||||||||||
match message { | ||||||||||||||||||||||||||||||||||||||||||||
Ok(msg) => match msg { | ||||||||||||||||||||||||||||||||||||||||||||
Message::Pong(_) => {} | ||||||||||||||||||||||||||||||||||||||||||||
Message::Binary(buf) => { | ||||||||||||||||||||||||||||||||||||||||||||
let packet = serde_json::from_slice::<serde_json::Value>(&buf)?; | ||||||||||||||||||||||||||||||||||||||||||||
println!("Received packet: {packet:?}"); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
if let Some(packet) = packet.get("start_actor") { | ||||||||||||||||||||||||||||||||||||||||||||
let payload = json!({ | ||||||||||||||||||||||||||||||||||||||||||||
"actor_state_update": { | ||||||||||||||||||||||||||||||||||||||||||||
"actor_id": packet["actor_id"], | ||||||||||||||||||||||||||||||||||||||||||||
"generation": packet["generation"], | ||||||||||||||||||||||||||||||||||||||||||||
"state": { | ||||||||||||||||||||||||||||||||||||||||||||
"running": null, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
let data = serde_json::to_vec(&payload)?; | ||||||||||||||||||||||||||||||||||||||||||||
write.lock().await.send(Message::Binary(data)).await?; | ||||||||||||||||||||||||||||||||||||||||||||
} else if let Some(packet) = packet.get("signal_actor") { | ||||||||||||||||||||||||||||||||||||||||||||
let payload = json!({ | ||||||||||||||||||||||||||||||||||||||||||||
"actor_state_update": { | ||||||||||||||||||||||||||||||||||||||||||||
"actor_id": packet["actor_id"], | ||||||||||||||||||||||||||||||||||||||||||||
"generation": packet["generation"], | ||||||||||||||||||||||||||||||||||||||||||||
"state": { | ||||||||||||||||||||||||||||||||||||||||||||
"exited": { | ||||||||||||||||||||||||||||||||||||||||||||
"exit_code": null, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
let data = serde_json::to_vec(&payload)?; | ||||||||||||||||||||||||||||||||||||||||||||
write.lock().await.send(Message::Binary(data)).await?; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
msg => eprintln!("Unexpected message: {msg:?}"), | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
Err(e) => { | ||||||||||||||||||||||||||||||||||||||||||||
eprintln!("Error reading message: {}", e); | ||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
while let Some(frame) = read.next().await.transpose()? { | ||||||||||||||||||||||||||||||||||||||||||||
let (_, packet) = decode_frame::<serde_json::Value>(&frame.freeze())?; | ||||||||||||||||||||||||||||||||||||||||||||
println!("Received packet: {packet:?}"); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
if let Some(packet) = packet.get("start_actor") { | ||||||||||||||||||||||||||||||||||||||||||||
let payload = json!({ | ||||||||||||||||||||||||||||||||||||||||||||
"actor_state_update": { | ||||||||||||||||||||||||||||||||||||||||||||
"actor_id": packet["actor_id"], | ||||||||||||||||||||||||||||||||||||||||||||
"generation": packet["generation"], | ||||||||||||||||||||||||||||||||||||||||||||
"state": { | ||||||||||||||||||||||||||||||||||||||||||||
"running": null, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
write.lock().await.send(encode_frame(&payload)?).await?; | ||||||||||||||||||||||||||||||||||||||||||||
} else if let Some(packet) = packet.get("signal_actor") { | ||||||||||||||||||||||||||||||||||||||||||||
let payload = json!({ | ||||||||||||||||||||||||||||||||||||||||||||
"actor_state_update": { | ||||||||||||||||||||||||||||||||||||||||||||
"actor_id": packet["actor_id"], | ||||||||||||||||||||||||||||||||||||||||||||
"generation": packet["generation"], | ||||||||||||||||||||||||||||||||||||||||||||
"state": { | ||||||||||||||||||||||||||||||||||||||||||||
"exited": { | ||||||||||||||||||||||||||||||||||||||||||||
"exit_code": null, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
write.lock().await.send(encode_frame(&payload)?).await?; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
println!("WebSocket connection closed"); | ||||||||||||||||||||||||||||||||||||||||||||
println!("Socket connection closed"); | ||||||||||||||||||||||||||||||||||||||||||||
Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
fn decode_frame<T: DeserializeOwned>(frame: &Bytes) -> Result<([u8; 4], T)> { | ||||||||||||||||||||||||||||||||||||||||||||
ensure!(frame.len() >= 4, "Frame too short"); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Extract the header (first 4 bytes) | ||||||||||||||||||||||||||||||||||||||||||||
let header = [frame[0], frame[1], frame[2], frame[3]]; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Deserialize the rest of the frame (payload after the header) | ||||||||||||||||||||||||||||||||||||||||||||
let payload = serde_json::from_slice(&frame[4..])?; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
Ok((header, payload)) | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
fn encode_frame<T: Serialize>(payload: &T) -> Result<Bytes> { | ||||||||||||||||||||||||||||||||||||||||||||
let mut buf = Vec::with_capacity(4); | ||||||||||||||||||||||||||||||||||||||||||||
buf.extend_from_slice(&[0u8; 4]); // header (currently unused) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
let mut cursor = Cursor::new(&mut buf); | ||||||||||||||||||||||||||||||||||||||||||||
serde_json::to_writer(&mut cursor, payload)?; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
Ok(buf.into()) | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+154
to
+162
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of fn encode_frame<T: Serialize>(payload: &T) -> Result<Bytes> {
let mut buf = Vec::with_capacity(4);
buf.extend_from_slice(&[0u8; 4]); // header (currently unused)
let mut cursor = Cursor::new(&mut buf);
cursor.set_position(4); // Position cursor after header
serde_json::to_writer(&mut cursor, payload)?;
Ok(buf.into())
} This ensures the header bytes are preserved and the JSON payload is appended correctly.
Suggested change
Spotted by Diamond |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
encode_frame
function initializes a buffer with 4 zero bytes as a header, but these bytes are never populated with the actual length information. This appears inconsistent with theLengthDelimitedCodec
configuration, which expects the first 4 bytes to contain the length of the payload.Consider updating the header bytes with the appropriate length information before returning the buffer:
Spotted by Diamond
Is this helpful? React 👍 or 👎 to let us know.