Skip to content

Commit

Permalink
feat: dynamic server nomad calls
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelOnFira committed Jul 6, 2024
1 parent a2c51b9 commit d5f049b
Show file tree
Hide file tree
Showing 91 changed files with 7,815 additions and 169 deletions.
3 changes: 3 additions & 0 deletions .vscode/rivet.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
{
"path": "../lib/bolt",
},
{
"path": "../svc",
}
],
}
8 changes: 7 additions & 1 deletion fern/definition/servers/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,10 @@ types:
- udp

DockerHostRouting:
properties: {}
properties:
protocol: optional<HostProtocol>

HostProtocol:
enum:
- tcp
- udp
25 changes: 25 additions & 0 deletions infra/default-builds/dockerfiles/test-ds-echo/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/rust

.dockerignore
.gitignore
Dockerfile

21 changes: 21 additions & 0 deletions infra/default-builds/dockerfiles/test-ds-echo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/rust

16 changes: 16 additions & 0 deletions infra/default-builds/dockerfiles/test-ds-echo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "test-ds-echo"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.29", features = ["full"] }
reqwest = "0.11"
anyhow = "1.0"
hyper = { version = "0.14", features = ["server"] }

[profile.release]
opt-level = 'z'
lto = true
codegen-units = 1

18 changes: 18 additions & 0 deletions infra/default-builds/dockerfiles/test-ds-echo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM clux/muslrust:1.77.2-stable AS build
RUN cargo new --bin /app
WORKDIR /app
COPY Cargo.toml ./
RUN cargo build --release
RUN rm -r src
COPY ./src ./src
RUN touch src/main.rs && \
cargo build --release && \
strip target/x86_64-unknown-linux-musl/release/test-ds-echo

FROM alpine:latest
COPY --from=build /app/target/x86_64-unknown-linux-musl/release/test-ds-echo /usr/local/bin/app
RUN chmod +x /usr/local/bin/app
RUN adduser -D app
USER app
CMD ["/usr/local/bin/app"]

178 changes: 178 additions & 0 deletions infra/default-builds/dockerfiles/test-ds-echo/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
use std::{convert::Infallible, env, net::SocketAddr, process::Command};

use anyhow::{Context, Result};
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt},
net::{TcpListener, UdpSocket},
};

#[tokio::main]
async fn main() -> Result<()> {
// Env
let envs: Vec<(String, String)> = env::vars().collect();
println!("Env:\n{:#?}\n", envs);

// resolv.conf
let output = Command::new("cat")
.arg("/etc/resolv.conf")
.output()
.expect("Failed to execute command");
println!(
"resolv.conf:\n{}\n",
String::from_utf8_lossy(&output.stdout)
);

// TEMP: Expose dev port
tokio::spawn(with_select_term(echo_http_server(28234)));

// TODO: Add back
// Echo servers (bridge networking)
// if let Ok(http_port) = env::var("PORT_test_http") {
// let http_port: u16 = http_port.parse()?;
// tokio::spawn(with_select_term(echo_http_server(http_port)));
// }
//
// if let Ok(tcp_port) = env::var("PORT_test_tcp") {
// let tcp_port: u16 = tcp_port.parse()?;
// tokio::spawn(with_select_term(echo_tcp_server(tcp_port)));
// }
//
// if let Ok(udp_port) = env::var("PORT_test_udp") {
// let udp_port: u16 = udp_port.parse()?;
// tokio::spawn(with_select_term(echo_udp_server(udp_port)));
// }
//
// // Echo servers (host networking)
// if let Ok(http_port) = env::var("HOST_PORT_HTTP") {
// let http_port: u16 = http_port.parse()?;
// tokio::spawn(with_select_term(echo_http_server(http_port)));
// }
//
// if let Ok(tcp_port) = env::var("HOST_PORT_TCP") {
// let tcp_port: u16 = tcp_port.parse()?;
// tokio::spawn(with_select_term(echo_tcp_server(tcp_port)));
// }
//
// if let Ok(udp_port) = env::var("HOST_PORT_UDP") {
// let udp_port: u16 = udp_port.parse()?;
// tokio::spawn(with_select_term(echo_udp_server(udp_port)));
// }

// Lobby ready
// lobby_ready().await?;

// Wait indefinitely
println!("Waiting indefinitely...");
wait_term().await?;
println!("Ctrl+C pressed. Exiting main...");

Ok(())
}

// async fn lobby_ready() -> Result<()> {
// let url = format!(
// "{}/matchmaker/lobbies/ready",
// env::var("RIVET_API_ENDPOINT").context("RIVET_API_ENDPOINT")?
// );
// let token = env::var("RIVET_TOKEN").context("RIVET_TOKEN")?;
//
// let client = reqwest::Client::new();
// client
// .post(&url)
// .header("Content-Type", "application/json")
// .header("Authorization", format!("Bearer {}", token))
// .send()
// .await?;
//
// println!("Success, waiting indefinitely");
// Ok(())
// }

/// Waits for the SIGTERM signal.
async fn wait_term() -> Result<()> {
use tokio::signal::unix::{signal, SignalKind};

signal(SignalKind::terminate())
.expect("Failed to set up SIGTERM handler")
.recv()
.await;

Ok(())
}

/// Waits until future exits or term.
async fn with_select_term(future: impl std::future::Future<Output = Result<()>>) -> Result<()> {
tokio::select! {
result = future => result,
_ = wait_term() => {
println!("Ctrl+C pressed. Exiting...");
Ok(())
},
}
}

async fn echo_http_server(port: u16) -> Result<()> {
use hyper::{
service::{make_service_fn, service_fn},
Body, Request, Response, Server,
};

let addr = SocketAddr::from(([0, 0, 0, 0], port));
println!("HTTP: {}", port);

async fn echo(req: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new(req.into_body()))
}

let make_service = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(echo)) });
Server::bind(&addr)
.serve(make_service)
.await
.expect("hyper server");

Ok(())
}

async fn echo_tcp_server(port: u16) -> Result<()> {
let addr = SocketAddr::from(([0, 0, 0, 0], port));
println!("TCP: {}", port);

let listener = TcpListener::bind(&addr).await.context("bind failed")?;
loop {
let (socket, _) = listener.accept().await.context("accept failed")?;
tokio::spawn(async move {
let mut reader = tokio::io::BufReader::new(socket);
let mut line = String::new();
loop {
let bytes_read = reader.read_line(&mut line).await.expect("read line failed");
if bytes_read == 0 {
break;
}

// Echo the line
reader
.get_mut()
.write_all(format!("{line}\n").as_bytes())
.await
.expect("write failed");
reader.get_mut().flush().await.expect("flush failed");
line.clear();
}
});
}
}

async fn echo_udp_server(port: u16) -> Result<()> {
let addr = SocketAddr::from(([0, 0, 0, 0], port));
println!("UDP: {}", port);

let socket = UdpSocket::bind(&addr).await?;
let mut buf = vec![0u8; 1024];
loop {
let (size, src) = socket.recv_from(&mut buf).await?;
let data = String::from_utf8_lossy(&buf[..size]);
println!("Received data: {}", data);

socket.send_to(&buf[..size], &src).await?;
}
}
1 change: 1 addition & 0 deletions infra/default-builds/outputs/test-ds-echo-tag.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test-ds-echo:1719995033
3 changes: 3 additions & 0 deletions infra/default-builds/outputs/test-ds-echo.tar
Git LFS file not shown
2 changes: 1 addition & 1 deletion infra/tf/modules/secrets/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ terraform {
required_providers {
external = {
source = "hashicorp/external"
version = "2.3.1"
version = "2.3.3"
}
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/bolt/core/src/context/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,7 @@ impl ServiceContextData {
env.insert("RIVET_SUPPORT_DEPRECATED_SUBDOMAINS".into(), "1".into());
}
env.insert("RIVET_HOST_API".into(), project_ctx.host_api());
env.insert("RIVET_HOST_TUNNEL".into(), project_ctx.host_tunnel().await);
env.insert("RIVET_ORIGIN_API".into(), project_ctx.origin_api());
env.insert("RIVET_ORIGIN_HUB".into(), project_ctx.origin_hub());

Expand Down
55 changes: 51 additions & 4 deletions lib/convert/src/impls/ds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ impl ApiTryFrom<models::ServersDockerPortRouting>
(Some(game_guard), None) => Ok(
backend::dynamic_servers::docker_port::Routing::GameGuard((*game_guard).api_into()),
),
(None, Some(_)) => Ok(backend::dynamic_servers::docker_port::Routing::Host(
backend::dynamic_servers::DockerHostRouting {},
(None, Some(host)) => Ok(backend::dynamic_servers::docker_port::Routing::Host(
(*host).api_into(),
)),
(None, None) => bail_with!(SERVERS_NO_PORT_ROUTERS),
_ => bail_with!(SERVERS_MULTIPLE_PORT_ROUTERS),
Expand All @@ -225,10 +225,10 @@ impl ApiTryFrom<backend::dynamic_servers::docker_port::Routing>
host: None,
})
}
backend::dynamic_servers::docker_port::Routing::Host(_) => {
backend::dynamic_servers::docker_port::Routing::Host(host) => {
Ok(models::ServersDockerPortRouting {
game_guard: None,
host: Some(to_value({})?),
host: Some(Box::new(host.api_try_into()?)),
})
}
}
Expand Down Expand Up @@ -268,6 +268,35 @@ impl ApiTryFrom<backend::dynamic_servers::DockerGameGuardRouting>
}
}

impl ApiFrom<models::ServersDockerHostRouting> for backend::dynamic_servers::DockerHostRouting {
fn api_from(
value: models::ServersDockerHostRouting,
) -> backend::dynamic_servers::DockerHostRouting {
backend::dynamic_servers::DockerHostRouting {
protocol: backend::dynamic_servers::HostProtocol::api_from(
value.protocol.unwrap_or_default().into(),
) as i32,
}
}
}

impl ApiTryFrom<backend::dynamic_servers::DockerHostRouting> for models::ServersDockerHostRouting {
type Error = GlobalError;

fn api_try_from(
value: backend::dynamic_servers::DockerHostRouting,
) -> GlobalResult<models::ServersDockerHostRouting> {
Ok(models::ServersDockerHostRouting {
protocol: Some(
unwrap!(backend::dynamic_servers::HostProtocol::from_i32(
value.protocol
))
.api_into(),
),
})
}
}

impl ApiFrom<models::ServersGameGuardProtocol> for backend::dynamic_servers::GameGuardProtocol {
fn api_from(
value: models::ServersGameGuardProtocol,
Expand Down Expand Up @@ -315,3 +344,21 @@ impl ApiFrom<backend::dynamic_servers::GameGuardProtocol> for models::ServersGam
}
}
}

impl ApiFrom<models::ServersHostProtocol> for backend::dynamic_servers::HostProtocol {
fn api_from(value: models::ServersHostProtocol) -> backend::dynamic_servers::HostProtocol {
match value {
models::ServersHostProtocol::Udp => backend::dynamic_servers::HostProtocol::HostUdp,
models::ServersHostProtocol::Tcp => backend::dynamic_servers::HostProtocol::HostTcp,
}
}
}

impl ApiFrom<backend::dynamic_servers::HostProtocol> for models::ServersHostProtocol {
fn api_from(value: backend::dynamic_servers::HostProtocol) -> models::ServersHostProtocol {
match value {
backend::dynamic_servers::HostProtocol::HostUdp => models::ServersHostProtocol::Udp,
backend::dynamic_servers::HostProtocol::HostTcp => models::ServersHostProtocol::Tcp,
}
}
}
Loading

0 comments on commit d5f049b

Please sign in to comment.