mirror of
https://github.com/NotAShelf/mpvrc.git
synced 2026-04-16 07:53:48 +00:00
commit
c9b1555cbd
12 changed files with 498 additions and 2 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
||||||
2
.github/workflows/doc.yml
vendored
2
.github/workflows/doc.yml
vendored
|
|
@ -9,7 +9,7 @@ on:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: write
|
||||||
pages: write
|
pages: write
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1 +1,7 @@
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
# Sensitive
|
||||||
|
certificate.pem
|
||||||
|
private_key.pem
|
||||||
|
identity.pfx
|
||||||
|
|
||||||
|
|
|
||||||
164
Cargo.lock
generated
164
Cargo.lock
generated
|
|
@ -114,6 +114,15 @@ version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -166,6 +175,22 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.13"
|
version = "0.5.13"
|
||||||
|
|
@ -203,6 +228,21 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|
@ -325,12 +365,32 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
|
"native-tls",
|
||||||
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
|
@ -356,6 +416,50 @@ version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.68"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
@ -391,6 +495,12 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
|
|
@ -482,12 +592,44 @@ version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.216"
|
version = "1.0.216"
|
||||||
|
|
@ -529,6 +671,12 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
|
|
@ -623,6 +771,16 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.41"
|
version = "0.1.41"
|
||||||
|
|
@ -707,6 +865,12 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
|
||||||
12
Cargo.toml
12
Cargo.toml
|
|
@ -2,12 +2,24 @@
|
||||||
name = "mrc"
|
name = "mrc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
default-run = "cli"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "cli" # CLI implementation for terminal usage
|
||||||
|
path = "src/cli.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "server" # remote usage
|
||||||
|
path = "src/server.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = {version = "4.5.23", features = ["derive"]}
|
clap = {version = "4.5.23", features = ["derive"]}
|
||||||
clap_derive = "4.5.18"
|
clap_derive = "4.5.18"
|
||||||
ipc-channel = "0.19.0"
|
ipc-channel = "0.19.0"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1.0.133"
|
serde_json = "1.0.133"
|
||||||
tokio = { version = "1.42.0", features = ["full"] }
|
tokio = { version = "1.42.0", features = ["full"] }
|
||||||
|
native-tls = "0.2"
|
||||||
|
tokio-native-tls = "0.3"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-subscriber = "0.3.19"
|
tracing-subscriber = "0.3.19"
|
||||||
|
|
|
||||||
16
README.md
Normal file
16
README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
Creating a PKCS#12 certificate file using OpenSSL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
|
||||||
|
openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
Before running the server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export TLS_PFX_PATH=/path/to/identity.pfx
|
||||||
|
export TLS_PASSWORD="your_identity_passphrase"
|
||||||
|
export AUTH_TOKEN="your_auth_token"
|
||||||
|
```
|
||||||
|
|
||||||
|
How you handle environment is up to you, Systemd makes it somewhat easy.
|
||||||
26
flake.lock
generated
Normal file
26
flake.lock
generated
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734880952,
|
||||||
|
"narHash": "sha256-ZTt3x0DN55JGjdYv8TEDC/YDxcYfpFDLApYvKFMnxNM=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "578baae41df4920fb34db92ae3a312c23ea90b89",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
23
flake.nix
Normal file
23
flake.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs";
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
}: let
|
||||||
|
systems = ["x86_64-linux" "aarch64-linux"];
|
||||||
|
forEachSystem = nixpkgs.lib.genAttrs systems;
|
||||||
|
|
||||||
|
pkgsForEach = nixpkgs.legacyPackages;
|
||||||
|
in rec {
|
||||||
|
packages = forEachSystem (system: {
|
||||||
|
default = pkgsForEach.${system}.callPackage ./nix/package.nix {};
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = forEachSystem (system: {
|
||||||
|
default = pkgsForEach.${system}.callPackage ./nix/shell.nix {};
|
||||||
|
});
|
||||||
|
|
||||||
|
hydraJobs = packages;
|
||||||
|
};
|
||||||
|
}
|
||||||
12
nix/package.nix
Normal file
12
nix/package.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{rustPlatform}:
|
||||||
|
rustPlatform.buildRustPackage (finalAttrs: {
|
||||||
|
pname = "mrc";
|
||||||
|
version = "0.0.1";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
cargoLock.lockFile = finalAttrs.src + /Cargo.lock;
|
||||||
|
meta = {
|
||||||
|
description = "MPV IPC wrapper";
|
||||||
|
mainProgram = "mrc";
|
||||||
|
};
|
||||||
|
})
|
||||||
26
nix/shell.nix
Normal file
26
nix/shell.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
mkShell,
|
||||||
|
rust-analyzer,
|
||||||
|
rustfmt,
|
||||||
|
clippy,
|
||||||
|
cargo,
|
||||||
|
gcc,
|
||||||
|
openssl,
|
||||||
|
pkg-config,
|
||||||
|
rustc,
|
||||||
|
}:
|
||||||
|
mkShell {
|
||||||
|
name = "mrc";
|
||||||
|
packages = [
|
||||||
|
rust-analyzer
|
||||||
|
rustfmt
|
||||||
|
clippy
|
||||||
|
cargo
|
||||||
|
gcc
|
||||||
|
clippy
|
||||||
|
rustfmt
|
||||||
|
openssl
|
||||||
|
pkg-config
|
||||||
|
rustc
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -216,7 +216,6 @@ async fn main() -> io::Result<()> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// I don't like this either, but it looks cleaner than a multi-line
|
// I don't like this either, but it looks cleaner than a multi-line
|
||||||
// print macro just cramped in here.
|
// print macro just cramped in here.
|
||||||
let commands = vec![
|
let commands = vec![
|
||||||
211
src/server.rs
Normal file
211
src/server.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
use std::env;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use native_tls::{Identity, TlsAcceptor as NativeTlsAcceptor};
|
||||||
|
use serde_json::json;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio_native_tls::TlsAcceptor;
|
||||||
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
|
use mrc::{get_property, playlist_clear, playlist_next, playlist_prev, quit, seek, set_property};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(author, version, about)]
|
||||||
|
struct Config {
|
||||||
|
/// The IP address and port to bind the server to
|
||||||
|
#[arg(short, long, default_value = "127.0.0.1:8080")]
|
||||||
|
bind: String,
|
||||||
|
|
||||||
|
/// Path to MPV IPC socket
|
||||||
|
#[arg(short, long, default_value = "/tmp/mpvsocket")]
|
||||||
|
socket: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connection(
|
||||||
|
stream: tokio::net::TcpStream,
|
||||||
|
acceptor: Arc<TlsAcceptor>,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
let mut stream = acceptor.accept(stream).await?;
|
||||||
|
let mut buffer = vec![0; 2048];
|
||||||
|
|
||||||
|
let n = stream.read(&mut buffer).await?;
|
||||||
|
let request = String::from_utf8_lossy(&buffer[..n]);
|
||||||
|
|
||||||
|
debug!("Received request:\n{}", request);
|
||||||
|
|
||||||
|
let headers = request.split("\r\n").collect::<Vec<&str>>();
|
||||||
|
let token_line = headers
|
||||||
|
.iter()
|
||||||
|
.find(|&&line| line.starts_with("Authorization:"));
|
||||||
|
let token = match token_line {
|
||||||
|
Some(line) => line.split(" ").nth(1).unwrap_or_default(),
|
||||||
|
None => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
let auth_token = match env::var("AUTH_TOKEN") {
|
||||||
|
Ok(token) => token,
|
||||||
|
Err(_) => {
|
||||||
|
error!("Authentication token is not set. Connection cannot be accepted.");
|
||||||
|
stream.write_all(b"Authentication token not set\n").await?;
|
||||||
|
|
||||||
|
// You know what? I do not care to panic when the authentication token is
|
||||||
|
// missing in the environment. Start the goddamned server and hell, even
|
||||||
|
// accept incoming connections. Authenticated requests will be refused
|
||||||
|
// when the token is incorrect or not set, so we can simply continue here.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if token != auth_token {
|
||||||
|
stream.write_all(b"Authentication failed\n").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Client authenticated");
|
||||||
|
stream.write_all(b"Authenticated\n").await?;
|
||||||
|
|
||||||
|
let command = request.split("\r\n\r\n").last().unwrap_or("");
|
||||||
|
info!("Received command: {}", command);
|
||||||
|
|
||||||
|
let response = match process_command(command.trim()).await {
|
||||||
|
Ok(response) => response,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error processing command: {}", e);
|
||||||
|
format!("Error: {:?}", e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
stream.write_all(response.as_bytes()).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_command(command: &str) -> Result<String, String> {
|
||||||
|
match command {
|
||||||
|
"pause" => {
|
||||||
|
info!("Pausing playback");
|
||||||
|
set_property("pause", &json!(true), None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to pause: {:?}", e))?;
|
||||||
|
Ok("Paused playback\n".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"play" => {
|
||||||
|
info!("Unpausing playback");
|
||||||
|
set_property("pause", &json!(false), None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to play: {:?}", e))?;
|
||||||
|
Ok("Resumed playback\n".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"stop" => {
|
||||||
|
info!("Stopping playback and quitting MPV");
|
||||||
|
quit(None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to stop: {:?}", e))?;
|
||||||
|
Ok("Stopped playback\n".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"next" => {
|
||||||
|
info!("Skipping to next item in the playlist");
|
||||||
|
playlist_next(None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to skip to next: {:?}", e))?;
|
||||||
|
Ok("Skipped to next item\n".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"prev" => {
|
||||||
|
info!("Skipping to previous item in the playlist");
|
||||||
|
playlist_prev(None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to skip to previous: {:?}", e))?;
|
||||||
|
Ok("Skipped to previous item\n".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"seek" => {
|
||||||
|
let parts: Vec<&str> = command.split_whitespace().collect();
|
||||||
|
if let Some(seconds) = parts.get(1) {
|
||||||
|
if let Ok(sec) = seconds.parse::<i32>() {
|
||||||
|
info!("Seeking to {} seconds", sec);
|
||||||
|
seek(sec.into(), None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to seek: {:?}", e))?;
|
||||||
|
return Ok(format!("Seeking to {} seconds\n", sec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err("Invalid seek command".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"clear" => {
|
||||||
|
info!("Clearing the playlist");
|
||||||
|
playlist_clear(None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to clear playlist: {:?}", e))?;
|
||||||
|
Ok("Cleared playlist\n".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
"list" => {
|
||||||
|
info!("Listing playlist items");
|
||||||
|
match get_property("playlist", None).await {
|
||||||
|
Ok(Some(data)) => Ok(format!(
|
||||||
|
"Playlist: {}",
|
||||||
|
serde_json::to_string_pretty(&data).unwrap()
|
||||||
|
)),
|
||||||
|
Ok(None) => Err("No playlist data available".to_string()),
|
||||||
|
Err(e) => Err(format!("Failed to fetch playlist: {:?}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err("Unknown command".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_tls_acceptor() -> Result<TlsAcceptor, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
let pfx_path = env::var("TLS_PFX_PATH")
|
||||||
|
.map_err(|_| std::io::Error::new(std::io::ErrorKind::NotFound, "TLS_PFX_PATH not set"))?;
|
||||||
|
let password = env::var("TLS_PASSWORD")
|
||||||
|
.map_err(|_| std::io::Error::new(std::io::ErrorKind::NotFound, "TLS_PASSWORD not set"))?;
|
||||||
|
|
||||||
|
let mut file = std::fs::File::open(&pfx_path)?;
|
||||||
|
let mut identity = vec![];
|
||||||
|
file.read_to_end(&mut identity)?;
|
||||||
|
|
||||||
|
let identity = Identity::from_pkcs12(&identity, &password)?;
|
||||||
|
let native_acceptor = NativeTlsAcceptor::new(identity)?;
|
||||||
|
Ok(TlsAcceptor::from(native_acceptor))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
let config = Config::parse();
|
||||||
|
|
||||||
|
if !std::path::Path::new(&config.socket).exists() {
|
||||||
|
error!(
|
||||||
|
"Error: MPV socket not found at '{}'. Is MPV running?",
|
||||||
|
config.socket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Server is starting...");
|
||||||
|
match create_tls_acceptor() {
|
||||||
|
Ok(acceptor) => {
|
||||||
|
let acceptor = Arc::new(acceptor);
|
||||||
|
let listener = tokio::net::TcpListener::bind(&config.bind).await?;
|
||||||
|
info!("Server is listening on {}", config.bind);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, _) = listener.accept().await?;
|
||||||
|
info!("New connection accepted.");
|
||||||
|
|
||||||
|
let acceptor = Arc::clone(&acceptor);
|
||||||
|
tokio::spawn(handle_connection(stream, acceptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to initialize TLS: {}", e);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue