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 authored and NathanFlurry committed Jul 6, 2024
1 parent f901a5b commit 8942739
Show file tree
Hide file tree
Showing 135 changed files with 8,569 additions and 802 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",
}
],
}
50 changes: 25 additions & 25 deletions fern/definition/servers/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ types:
datacenter_id: uuid
cluster_id: uuid
metadata: unknown
image_id: uuid
args: optional<list<string>>
environment: optional<map<string, string>>
network: Network
resources: Resources
kill_timeout:
docs: >-
The duration to wait for in milliseconds before killing the server.
This should be set to a safe default, and can be overridden during a
DELETE request if needed.
type: optional<long>
runtime: Runtime
create_ts: long
destroy_ts: optional<long>

Expand All @@ -31,38 +34,29 @@ types:
docs: The amount of memory in megabytes
type: integer

Runtime:
properties:
docker: optional<DockerRuntime>

DockerRuntime:
Network:
properties:
image_id: uuid
args: optional<list<string>>
environment: optional<map<string, string>>
network: DockerNetwork
mode: optional<NetworkMode>
ports: map<string, Port>

DockerNetwork:
properties:
mode: optional<DockerNetworkMode>
ports: map<string, DockerPort>

DockerNetworkMode:
NetworkMode:
enum:
- bridge
- host

DockerPort:
Port:
properties:
port: optional<integer>
routing: DockerPortRouting
routing: PortRouting
server_port: optional<integer>
public_host: optional<string>
public_port: optional<integer>

DockerPortRouting:
PortRouting:
properties:
game_guard: optional<DockerGameGuardRouting>
host: optional<DockerHostRouting>
game_guard: optional<GameGuardRouting>
host: optional<HostRouting>

DockerGameGuardRouting:
GameGuardRouting:
properties:
protocol: optional<GameGuardProtocol>

Expand All @@ -74,5 +68,11 @@ types:
- tcp_tls
- udp

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

HostProtocol:
enum:
- tcp
- udp
16 changes: 15 additions & 1 deletion fern/definition/servers/servers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,28 @@ types:
docs: The name ID of the datacenter
type: string
metadata: unknown
image_id: uuid
args: optional<list<string>>
environment: optional<map<string, string>>
network: CreateServerNetworkRequest
resources: commons.Resources
kill_timeout:
docs: >-
The duration to wait for in milliseconds before killing the server.
This should be set to a safe default, and can be overridden during a
DELETE request if needed.
type: optional<long>
runtime: commons.Runtime

CreateServerNetworkRequest:
properties:
mode: optional<commons.NetworkMode>
ports: map<string, CreateServerPortRequest>

CreateServerPortRequest:
properties:
routing: commons.PortRouting
server_port: optional<integer>

CreateServerResponse:
properties:
server:
Expand Down
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
Loading

0 comments on commit 8942739

Please sign in to comment.