diff --git a/Cargo.lock b/Cargo.lock index 5f45e032e0..77f870e7bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12668,6 +12668,7 @@ dependencies = [ "reqwest 0.11.27", "rivet-config", "rivet-metrics", + "rivet-util", "service-discovery", "sqlx", "tempfile", @@ -12974,12 +12975,14 @@ dependencies = [ "regex", "reqwest 0.12.12", "rivet-config", + "rivet-metrics", "rivet-util-macros", "serde", "serde_json", "sqlx", "thiserror 1.0.69", "tokio", + "tracing", "types-proto", "url", "uuid", diff --git a/examples/system-test-actor/package.json b/examples/system-test-actor/package.json index 99d2ab0999..0bf33ca551 100644 --- a/examples/system-test-actor/package.json +++ b/examples/system-test-actor/package.json @@ -14,6 +14,7 @@ "@types/deno": "^2.2.0", "@types/node": "^22.13.9", "@types/ws": "^8.18.0", + "dgram": "^1.0.1", "node-fetch": "^3.3.2", "tsx": "^4.7.0", "typescript": "^5.3.3", diff --git a/examples/system-test-actor/src/container/main.ts b/examples/system-test-actor/src/container/main.ts index b4059469de..98190c13d2 100644 --- a/examples/system-test-actor/src/container/main.ts +++ b/examples/system-test-actor/src/container/main.ts @@ -1,6 +1,7 @@ import { serve } from "@hono/node-server"; import { createNodeWebSocket } from "@hono/node-ws"; import { createAndStartServer } from "../shared/server.js"; +import dgram from 'dgram'; let injectWebSocket: any; const { app, port } = createAndStartServer((app) => { @@ -12,3 +13,40 @@ const { app, port } = createAndStartServer((app) => { const server = serve({ fetch: app.fetch, port }); injectWebSocket(server); + + +// Get port from environment +const portEnv = + typeof Deno !== "undefined" + ? Deno.env.get("PORT_UDP") + : process.env.PORT_UDP; + +if (portEnv) { + // Create a UDP socket + const udpServer = dgram.createSocket('udp4'); + + // Listen for incoming messages + udpServer.on('message', (msg, rinfo) => { + console.log(`UDP server received: ${msg} from ${rinfo.address}:${rinfo.port}`); + + // Echo the message back to the sender + udpServer.send(msg, rinfo.port, rinfo.address, (err) => { + if (err) console.error('Failed to send UDP response:', err); + }); + }); + + // Handle errors + udpServer.on('error', (err) => { + console.error('UDP server error:', err); + udpServer.close(); + }); + + + const port2 = Number.parseInt(portEnv); + + udpServer.bind(port2, () => { + console.log(`UDP echo server running on port ${port2}`); + }); +} else { + console.warn("missing PORT_UDP"); +} diff --git a/examples/system-test-actor/tests/client.ts b/examples/system-test-actor/tests/client.ts index 01c29fae39..ab837a78b6 100644 --- a/examples/system-test-actor/tests/client.ts +++ b/examples/system-test-actor/tests/client.ts @@ -1,5 +1,6 @@ import { RivetClient } from "@rivet-gg/api"; import WebSocket from "ws"; +import dgram from 'dgram'; // Can be opt since they're not required for dev const RIVET_ENDPOINT = process.env.RIVET_ENDPOINT; @@ -48,6 +49,13 @@ async function run() { guard: {}, }, }, + udp: { + protocol: "udp", + // internalPort: 80, + routing: { + host: {}, + }, + }, }, }, lifecycle: { @@ -106,6 +114,7 @@ async function run() { await new Promise((resolve) => setTimeout(resolve, 100)); } + // WS await new Promise((resolve, reject) => { // Open a WebSocket to that endpoint const ws = new WebSocket(`${actorOrigin}/ws`); @@ -144,6 +153,47 @@ async function run() { }; }); + // UDP + let res = await client.actor.get(actor.id, { + project: RIVET_PROJECT, + environment: RIVET_ENVIRONMENT, + }); + + console.log("Connecting to UDP echo server..."); + const udpPort = res.actor.network.ports.udp; + const udpServer = `${udpPort.hostname}:${udpPort.port}`; + console.log("UDP server address:", udpServer); + + // Create a UDP socket + const udpClient = dgram.createSocket('udp4'); + + // Send a message to the UDP echo server + const message = Buffer.from('Hello UDP server!'); + udpClient.send(message, udpPort.port, udpPort.hostname, (err) => { + if (err) { + console.error("Error sending UDP message:", err); + udpClient.close(); + } else { + console.log("UDP message sent"); + } + }); + + // Listen for a response + udpClient.on('message', (msg, rinfo) => { + console.log(`UDP message received: ${msg.toString()}`); + console.log(`From: ${rinfo.address}:${rinfo.port}`); + udpClient.close(); + }); + + udpClient.on('error', (err) => { + console.error("UDP client error:", err); + udpClient.close(); + }); + + udpClient.on('close', () => { + console.log("UDP connection closed"); + }); + console.log("Sleeping forever so you can debug"); await new Promise((resolve) => setTimeout(resolve, 100_000_000)); } catch (error) { diff --git a/examples/system-test-actor/yarn.lock b/examples/system-test-actor/yarn.lock index 0e0cb9349f..dca9c217be 100644 --- a/examples/system-test-actor/yarn.lock +++ b/examples/system-test-actor/yarn.lock @@ -514,6 +514,13 @@ __metadata: languageName: node linkType: hard +"dgram@npm:^1.0.1": + version: 1.0.1 + resolution: "dgram@npm:1.0.1" + checksum: 10c0/de7db34827917ee4f2a8ba113b2e07b38d992feaa369cc539b8ac116d81c69feadf2f9f510dae7d58342c88af6330022ad0445fda1eafe6b9017ad9ffd6a28f4 + languageName: node + linkType: hard + "dunder-proto@npm:^1.0.1": version: 1.0.1 resolution: "dunder-proto@npm:1.0.1" @@ -1529,6 +1536,7 @@ __metadata: "@types/deno": "npm:^2.2.0" "@types/node": "npm:^22.13.9" "@types/ws": "npm:^8.18.0" + dgram: "npm:^1.0.1" hono: "npm:^4.6.17" node-fetch: "npm:^3.3.2" tsx: "npm:^4.7.0"