flakage
This commit is contained in:
parent
b5c340c104
commit
f1194c752c
79
flake.nix
79
flake.nix
|
@ -15,7 +15,7 @@
|
|||
nixpkgs,
|
||||
flake-utils,
|
||||
fenix,
|
||||
crane
|
||||
crane,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem
|
||||
(
|
||||
|
@ -30,12 +30,14 @@
|
|||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = with pkgs; [pkg-config cmake];
|
||||
buildInputs = with pkgs; [
|
||||
openssl
|
||||
zlib-ng
|
||||
] ++ lib.optionals stdenv.isDarwin [
|
||||
libiconv
|
||||
];
|
||||
buildInputs = with pkgs;
|
||||
[
|
||||
openssl
|
||||
zlib-ng
|
||||
]
|
||||
++ lib.optionals stdenv.isDarwin [
|
||||
libiconv
|
||||
];
|
||||
};
|
||||
in
|
||||
with pkgs; {
|
||||
|
@ -47,9 +49,66 @@
|
|||
];
|
||||
};
|
||||
formatter = pkgs.alejandra;
|
||||
packages.default = craneLib.buildPackage (commonArgs // {
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
});
|
||||
packages.default = craneLib.buildPackage (commonArgs
|
||||
// {
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
});
|
||||
nixosModules.default = with lib; { config, ... }: {
|
||||
options.services.smo-server = {
|
||||
enable = mkEnableOption "a game server for Super Mario Odyssey Online";
|
||||
user = mkOption {
|
||||
type = lib.types.string;
|
||||
description = "The user to start the server with";
|
||||
};
|
||||
enableFaker = mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether to enable the test bot for solo development.";
|
||||
};
|
||||
tcpPort = mkOption {
|
||||
type = lib.types.port;
|
||||
default = 1027;
|
||||
description = "The TCP port to host the server on";
|
||||
};
|
||||
udpPort = mkOption {
|
||||
type = lib.types.port;
|
||||
default = 1027;
|
||||
description = "The UDP port to host the server on";
|
||||
};
|
||||
proximity = {
|
||||
type = lib.types.attrs;
|
||||
port = {
|
||||
type = lib.types.port;
|
||||
example = 4433;
|
||||
description = "The UDP port to host the proximity chat server on";
|
||||
};
|
||||
certPath = {
|
||||
type = lib.types.path;
|
||||
example = "cert.pem";
|
||||
description = "The certificate used for encrypting the WebTransport stream";
|
||||
};
|
||||
keyPath = {
|
||||
type = lib.types.path;
|
||||
example = "cert.pem";
|
||||
description = "The certificate used for encrypting the WebTransport stream";
|
||||
};
|
||||
};
|
||||
};
|
||||
config = mkIf config.services.smo-server.enable {
|
||||
systemd.services.smo-server = with services.smo-server; {
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network.target"];
|
||||
description = "Start smo-server";
|
||||
serviceConfig = {
|
||||
WorkingDirectory = "${packages.default.outPath}";
|
||||
Type = "simple";
|
||||
ExecStart = let proxRes = 5;
|
||||
in ''${packages.default.outPath}/bin/smo-server -t ${tcpPort} -u ${udpPort} ${proxRes}'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -39,17 +39,18 @@ pub fn manager() -> &'static Address<Manager> {
|
|||
}
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
#[command(about = "A game server for Super Mario Odyssey Online")]
|
||||
struct Arguments {
|
||||
#[arg(short, long, default_value_t = 1027)]
|
||||
tcp_port: u16,
|
||||
#[arg(short, long, default_value_t = 1027)]
|
||||
udp_port: u16,
|
||||
#[arg(short, long, default_value_t = 4433)]
|
||||
prox_port: u16,
|
||||
#[arg(long, default_value = "./cert.pem")]
|
||||
prox_cert: PathBuf,
|
||||
#[arg(long, default_value = "./key.pem")]
|
||||
prox_key: PathBuf,
|
||||
#[arg(short, long, requires = "prox_cert", requires = "prox_key")]
|
||||
prox_port: Option<u16>,
|
||||
#[arg(long)]
|
||||
prox_cert: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
prox_key: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
enable_faker: bool,
|
||||
}
|
||||
|
|
|
@ -22,33 +22,44 @@ fn listeners() -> &'static RwLock<HashMap<UuidString, Address<ProximityPlayer>>>
|
|||
&LISTENERS
|
||||
}
|
||||
|
||||
pub async fn web_main(port: u16, cert: PathBuf, key: PathBuf) -> Address<Manager> {
|
||||
pub async fn web_main(port: Option<u16>, cert: Option<PathBuf>, key: Option<PathBuf>) -> Address<Manager> {
|
||||
let span = info_span!("prox");
|
||||
info!(parent: &span, "reading pems from {{ cert: {cert:?}, key: {key:?} }}");
|
||||
let identity = Identity::load_pemfiles(cert, key).await.expect("failed to create identity from proximity pems");
|
||||
let config = ServerConfig::builder().with_bind_default(port).with_identity(identity).build();
|
||||
let endpoint = Endpoint::server(config).expect("failed to build proximity endpoint");
|
||||
let endpoint = if let Some(port) = port {
|
||||
let (cert, key) = (cert.unwrap(), key.unwrap()); // guarded and enforced to be fine by clap
|
||||
info!(parent: &span, "reading pems from {{ cert: {cert:?}, key: {key:?} }}");
|
||||
let identity = Identity::load_pemfiles(cert, key).await.expect("failed to create identity from proximity pems");
|
||||
let config = ServerConfig::builder().with_bind_default(port).with_identity(identity).build();
|
||||
let endpoint = Endpoint::server(config).expect("failed to build proximity endpoint");
|
||||
|
||||
info!("listening on webtransport port {port}");
|
||||
info!(parent: &span, "listening on webtransport port {port}");
|
||||
Some(endpoint)
|
||||
} else {
|
||||
info!(parent: &span, "no port specified, not starting server");
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
let manager = xtra::spawn_tokio(
|
||||
Manager {
|
||||
players: HashMap::new(),
|
||||
next_id: 0,
|
||||
},
|
||||
Mailbox::bounded(8),
|
||||
Mailbox::bounded(32),
|
||||
);
|
||||
tokio::spawn({
|
||||
let manager = manager.clone();
|
||||
async move {
|
||||
loop {
|
||||
let connection = endpoint.accept().await;
|
||||
|
||||
ProximityPlayer::spawn(connection, manager.clone());
|
||||
if let Some(endpoint) = endpoint {
|
||||
tokio::spawn({
|
||||
let manager = manager.clone();
|
||||
async move {
|
||||
loop {
|
||||
let connection = endpoint.accept().await;
|
||||
|
||||
ProximityPlayer::spawn(connection, manager.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
.instrument(span)
|
||||
});
|
||||
.instrument(span)
|
||||
});
|
||||
}
|
||||
manager
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ impl ProximityPlayer {
|
|||
);
|
||||
|
||||
let (mut send, mut recv) = connection.accept_bi().await.expect("failed to start channel");
|
||||
trace!("getting uuid and name");
|
||||
let mut id = UuidString::new_zeroed();
|
||||
recv.read_exact(id.as_mut_bytes()).await.expect("failed to read uuid");
|
||||
let mut name = String::new_zeroed();
|
||||
|
@ -46,7 +45,7 @@ impl ProximityPlayer {
|
|||
|
||||
send.write_u8(state.len() as u8).await.expect("failed to write length");
|
||||
for player in state.values() {
|
||||
trace!("sending player {player:?}");
|
||||
trace!(parent: &span, "sending player {player:?}");
|
||||
send.write_all(player.as_bytes()).await.expect("failed to write player");
|
||||
}
|
||||
|
||||
|
@ -78,7 +77,6 @@ impl ProximityPlayer {
|
|||
loop {
|
||||
match packet::Event::deserialize(&mut recv).await {
|
||||
Ok(event) => {
|
||||
info!("deserialized event: {event:?}");
|
||||
let _ = address.send(event).detach().await;
|
||||
}
|
||||
Err(error) => {
|
||||
|
@ -359,7 +357,6 @@ impl Handler<ChangedStage> for ProximityPlayer {
|
|||
type Return = ();
|
||||
|
||||
async fn handle(&mut self, message: ChangedStage, ctx: &mut xtra::Context<Self>) -> Self::Return {
|
||||
warn!("todo: implement changed stage");
|
||||
let event = packet::Packet {
|
||||
kind: packet::Kind::StageChanged,
|
||||
data: packet::StageChanged {
|
||||
|
@ -381,7 +378,6 @@ pub mod packet {
|
|||
use anyhow::bail;
|
||||
use newtype_enum::newtype_enum;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tracing::info;
|
||||
use wtransport::{RecvStream, SendStream};
|
||||
use zerocopy::{FromZeros, Immutable, IntoBytes};
|
||||
use Event_variants::{Answer, Candidate, Offer, TargetChanged};
|
||||
|
@ -478,8 +474,6 @@ pub mod packet {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
info!("writing event: {self:?}");
|
||||
|
||||
match self {
|
||||
Self::Offer(offer) => {
|
||||
send.write_u8(Kind::Offer as u8).await?;
|
||||
|
@ -504,7 +498,6 @@ pub mod packet {
|
|||
pub async fn deserialize(recv: &mut RecvStream) -> anyhow::Result<Self> {
|
||||
async fn read_string(recv: &mut RecvStream) -> anyhow::Result<StdString> {
|
||||
let size = recv.read_u32_le().await?;
|
||||
info!("string size: {size}");
|
||||
let mut data = vec![0; size as usize];
|
||||
recv.read_exact(&mut data).await?;
|
||||
Ok(StdString::from_utf8(data)?)
|
||||
|
@ -512,12 +505,10 @@ pub mod packet {
|
|||
async fn read_fixed_string<const N: usize>(recv: &mut RecvStream) -> anyhow::Result<String<N>> {
|
||||
let mut str = String::new_zeroed();
|
||||
recv.read_exact(str.as_mut_bytes()).await?;
|
||||
info!("read id: {str}");
|
||||
Ok(str)
|
||||
}
|
||||
|
||||
let kind = recv.read_u8().await?;
|
||||
info!("reading kind: {kind}");
|
||||
let event = match kind {
|
||||
0 => Self::Offer(Offer {
|
||||
id: read_fixed_string(recv).await?,
|
||||
|
|
Loading…
Reference in a new issue