feat: Basic communication with Node subprocess
This commit is contained in:
commit
a61eb0734d
|
@ -0,0 +1,4 @@
|
||||||
|
.direnv
|
||||||
|
target/
|
||||||
|
node_modules/
|
||||||
|
index.js
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "hyperdeck-monitor"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
color-eyre = "0.6.3"
|
||||||
|
futures-util = "0.3.30"
|
||||||
|
serde = { version = "1.0.199", features = ["derive"] }
|
||||||
|
serde_json = "1.0.116"
|
||||||
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
|
tokio-tungstenite = "0.21.0"
|
||||||
|
tokio-util = "0.7.10"
|
||||||
|
tracing = "0.1.40"
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
url = "2.5.0"
|
|
@ -0,0 +1,26 @@
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=package.json");
|
||||||
|
println!("cargo:rerun-if-changed=package-lock.json");
|
||||||
|
println!("cargo:rerun-if-changed=index.ts");
|
||||||
|
|
||||||
|
let npm_install_output = Command::new("npm")
|
||||||
|
.arg("install")
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run `npm install`");
|
||||||
|
if !npm_install_output.status.success() {
|
||||||
|
let err = String::from_utf8(npm_install_output.stderr).unwrap_or("Unknown".to_string());
|
||||||
|
panic!("Running `npm install` failed, reason: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
let ts_build_output = Command::new("npm")
|
||||||
|
.arg("run")
|
||||||
|
.arg("build")
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run `npm run build`");
|
||||||
|
if !ts_build_output.status.success() {
|
||||||
|
let err = String::from_utf8(ts_build_output.stderr).unwrap_or("Unknown".to_string());
|
||||||
|
panic!("Running `npm run build` failed, reason: {err}");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1714253743,
|
||||||
|
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": [
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1714356894,
|
||||||
|
"narHash": "sha256-W6Mss7AG6bnFT1BqRApHXvLXBrFOu7V0+EUe9iML30s=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "d9b44509b4064f0a3fc9c7c92a603861f52fbedc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
rust-overlay = {
|
||||||
|
url = "github:oxalica/rust-overlay";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.follows = "nixpkgs";
|
||||||
|
flake-utils.follows = "flake-utils";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
rust-overlay,
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem
|
||||||
|
(
|
||||||
|
system: let
|
||||||
|
overlays = [(import rust-overlay)];
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system overlays;
|
||||||
|
};
|
||||||
|
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
rustToolchain
|
||||||
|
nodejs
|
||||||
|
];
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
rustToolchain
|
||||||
|
nodejs
|
||||||
|
];
|
||||||
|
in
|
||||||
|
with pkgs; {
|
||||||
|
formatter = pkgs.alejandra;
|
||||||
|
|
||||||
|
devShells.default = mkShell {
|
||||||
|
inherit buildInputs nativeBuildInputs;
|
||||||
|
|
||||||
|
RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
|
const wss = new WebSocket.Server({ port: 7867 });
|
||||||
|
|
||||||
|
wss.on('connection', function connection(ws) {
|
||||||
|
ws.on('message', function message(data) {
|
||||||
|
console.log('received: %s', data);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
event: "log",
|
||||||
|
message: "Hello"
|
||||||
|
}));
|
||||||
|
});
|
|
@ -0,0 +1,100 @@
|
||||||
|
{
|
||||||
|
"name": "hyperdeck-monitor",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "hyperdeck-monitor",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"hyperdeck-connection": "^2.0.1",
|
||||||
|
"ws": "^8.17.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"typescript": "^5.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.12.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
|
||||||
|
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/ws": {
|
||||||
|
"version": "8.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
|
||||||
|
"integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eventemitter3": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||||
|
},
|
||||||
|
"node_modules/hyperdeck-connection": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hyperdeck-connection/-/hyperdeck-connection-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-80fBsX57048ps253+t+BiG4d0JnVXWJESxAVrlQz3u7f2BLjMNguvUoTAR/N5xbdkHGcY2f6T4XCKzIMegpg4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": "^4.0.7",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||||
|
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
|
||||||
|
"integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "hyperdeck-monitor",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"hyperdeck-connection": "^2.0.1",
|
||||||
|
"ws": "^8.17.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"typescript": "^5.4.5"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "stable"
|
||||||
|
components = [ "rust-src", "cargo", "rustc" ]
|
|
@ -0,0 +1,192 @@
|
||||||
|
use std::{net::IpAddr, time::Duration};
|
||||||
|
|
||||||
|
use color_eyre::Report;
|
||||||
|
use futures_util::{
|
||||||
|
pin_mut, select,
|
||||||
|
stream::{SplitSink, SplitStream},
|
||||||
|
FutureExt, SinkExt, StreamExt,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio_tungstenite::{tungstenite::Message, MaybeTlsStream, WebSocketStream};
|
||||||
|
use tokio_util::sync::CancellationToken;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
setup_logging().expect("Failed to setup logging");
|
||||||
|
tracing::info!("Hello, world!");
|
||||||
|
|
||||||
|
let cancel = CancellationToken::new();
|
||||||
|
let node_process = run_node_process(cancel.clone()).fuse();
|
||||||
|
|
||||||
|
let (ws_message_tx, ws_message_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let (commands_tx, commands_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let state = AppState::default();
|
||||||
|
let ws_process = talk_to_node_ws(state, ws_message_tx, commands_rx, cancel.clone()).fuse();
|
||||||
|
|
||||||
|
pin_mut!(node_process);
|
||||||
|
pin_mut!(ws_process);
|
||||||
|
|
||||||
|
select! {
|
||||||
|
_ = node_process => {},
|
||||||
|
_ = ws_process => {},
|
||||||
|
_ = cancel.cancelled().fuse() => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
cancel.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_node_process(cancel: CancellationToken) {
|
||||||
|
while !cancel.is_cancelled() {
|
||||||
|
let result = tokio::process::Command::new("node")
|
||||||
|
.arg("index.js")
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
if let Ok(output) = result {
|
||||||
|
if !output.status.success() {
|
||||||
|
let err = String::from_utf8(output.stderr).unwrap_or("Unknown".to_string());
|
||||||
|
tracing::error!("Node process exited with error: {}", err);
|
||||||
|
// Back-off in case we are immediately crashing in a loop.
|
||||||
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct AppState {}
|
||||||
|
enum NodeWsCommand {
|
||||||
|
Ping,
|
||||||
|
AddHyperdeck(AddHyperdeckCommand),
|
||||||
|
RemoveHyperdeck(RemoveHyperdeckCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[serde(tag = "event")]
|
||||||
|
enum NodeWsMessageReceived {
|
||||||
|
Log { message: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct AddHyperdeckCommand {
|
||||||
|
ip: IpAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct RemoveHyperdeckCommand {
|
||||||
|
ip: IpAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn talk_to_node_ws(
|
||||||
|
state: AppState,
|
||||||
|
ws_message_tx: tokio::sync::mpsc::UnboundedSender<NodeWsMessageReceived>,
|
||||||
|
commands_rx: tokio::sync::mpsc::UnboundedReceiver<NodeWsCommand>,
|
||||||
|
cancel: CancellationToken,
|
||||||
|
) {
|
||||||
|
let ws_stream = wait_for_connection().await;
|
||||||
|
let (write, read) = ws_stream.split();
|
||||||
|
|
||||||
|
let outgoing = handle_outbound_messages(commands_rx, write).fuse();
|
||||||
|
let incoming = handle_inbound_messages(read, ws_message_tx).fuse();
|
||||||
|
|
||||||
|
pin_mut!(outgoing);
|
||||||
|
pin_mut!(incoming);
|
||||||
|
|
||||||
|
select! {
|
||||||
|
_ = outgoing => {},
|
||||||
|
_ = incoming => {},
|
||||||
|
_ = cancel.cancelled().fuse() => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_for_connection() -> WebSocketStream<MaybeTlsStream<TcpStream>> {
|
||||||
|
loop {
|
||||||
|
// Wait for Node to wake up...
|
||||||
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
|
|
||||||
|
let ws_url = url::Url::parse("ws://127.0.0.1:7867").expect("Invalid websocket URL");
|
||||||
|
match tokio_tungstenite::connect_async(ws_url.clone()).await {
|
||||||
|
Ok((ws_stream, _)) => {
|
||||||
|
tracing::info!("Connected to Node process on {ws_url}");
|
||||||
|
return ws_stream;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!("Error connecting to Node process: {:?}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_outbound_messages(
|
||||||
|
mut commands_rx: tokio::sync::mpsc::UnboundedReceiver<NodeWsCommand>,
|
||||||
|
mut socket_tx: SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>,
|
||||||
|
) {
|
||||||
|
while let Some(command) = commands_rx.recv().await {
|
||||||
|
match command {
|
||||||
|
NodeWsCommand::Ping => {
|
||||||
|
let _ = socket_tx
|
||||||
|
.send(tokio_tungstenite::tungstenite::Message::Ping(vec![]))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
NodeWsCommand::AddHyperdeck(command) => {
|
||||||
|
let _ = socket_tx
|
||||||
|
.send(tokio_tungstenite::tungstenite::Message::Text(
|
||||||
|
serde_json::to_string(&command)
|
||||||
|
.expect("Could not serialize AddHyperdeck command"),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
NodeWsCommand::RemoveHyperdeck(command) => {
|
||||||
|
let _ = socket_tx
|
||||||
|
.send(tokio_tungstenite::tungstenite::Message::Text(
|
||||||
|
serde_json::to_string(&command)
|
||||||
|
.expect("Could not serialize RemoveHyperdeck command"),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_inbound_messages(
|
||||||
|
socket_rx: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||||
|
ws_message_tx: tokio::sync::mpsc::UnboundedSender<NodeWsMessageReceived>,
|
||||||
|
) {
|
||||||
|
socket_rx
|
||||||
|
.for_each(|message| async {
|
||||||
|
match message {
|
||||||
|
Ok(tokio_tungstenite::tungstenite::Message::Text(text)) => {
|
||||||
|
if let Ok(received) = serde_json::from_str::<NodeWsMessageReceived>(&text) {
|
||||||
|
match received {
|
||||||
|
NodeWsMessageReceived::Log { message } => {
|
||||||
|
tracing::info!("Message from Node process: {message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(tokio_tungstenite::tungstenite::Message::Pong(_)) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_logging() -> Result<(), Report> {
|
||||||
|
if std::env::var("RUST_LIB_BACKTRACE").is_err() {
|
||||||
|
std::env::set_var("RUST_LIB_BACKTRACE", "1");
|
||||||
|
}
|
||||||
|
color_eyre::install()?;
|
||||||
|
|
||||||
|
if std::env::var("RUST_LOG").is_err() {
|
||||||
|
std::env::set_var("RUST_LOG", "debug");
|
||||||
|
}
|
||||||
|
tracing_subscriber::fmt::fmt()
|
||||||
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
.init();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"index.ts"
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
}
|
Loading…
Reference in New Issue