Răsfoiți Sursa

swapd: Add project skeleton

parazyd 2 ani în urmă
părinte
comite
5a526fe10e
10 a modificat fișierele cu 315 adăugiri și 0 ștergeri
  1. 3 0
      .gitignore
  2. 19 0
      Cargo.lock
  3. 1 0
      Cargo.toml
  4. 9 0
      Makefile
  5. 34 0
      bin/swapd/Cargo.toml
  6. 41 0
      bin/swapd/Makefile
  7. BIN
      bin/swapd/darkfi-swapd
  8. 127 0
      bin/swapd/src/main.rs
  9. 67 0
      bin/swapd/src/rpc.rs
  10. 14 0
      bin/swapd/swapd.toml

+ 3 - 0
.gitignore

@@ -28,6 +28,9 @@
 /bin/lilith/lilith
 /lilith
 
+/bin/swapd/swapd
+/swapd
+
 /bin/tau/taud/taud
 /taud
 

+ 19 - 0
Cargo.lock

@@ -6335,6 +6335,25 @@ dependencies = [
  "sval_fmt",
 ]
 
+[[package]]
+name = "swapd"
+version = "0.4.1"
+dependencies = [
+ "darkfi",
+ "darkfi-serial",
+ "easy-parallel",
+ "log",
+ "serde",
+ "signal-hook",
+ "signal-hook-async-std",
+ "simplelog",
+ "sled",
+ "smol",
+ "structopt",
+ "structopt-toml",
+ "url",
+]
+
 [[package]]
 name = "syn"
 version = "1.0.109"

+ 1 - 0
Cargo.toml

@@ -30,6 +30,7 @@ members = [
     "bin/genev/genevd",
     "bin/genev/genev-cli",
     "bin/darkirc",
+    "bin/swapd",
     "bin/tau/taud",
     #"bin/tau/tau-cli",
     "bin/vanityaddr",

+ 9 - 0
Makefile

@@ -24,6 +24,7 @@ BINS = \
 	genev \
 	genevd \
 	lilith \
+	swapd \
 	taud \
 	vanityaddr
 
@@ -87,6 +88,13 @@ lilith:
 		RUST_TARGET="$(RUST_TARGET)" \
 		RUSTFLAGS="$(RUSTFLAGS)"
 
+swapd:
+	$(MAKE) -C bin/$@ \
+		PREFIX="$(PREFIX)" \
+		CARGO="$(CARGO)" \
+		RUST_TARGET="$(RUST_TARGET)" \
+		RUSTFLAGS="$(RUSTFLAGS)"
+
 taud:
 	$(MAKE) -C bin/tau/$@ \
 		PREFIX="$(PREFIX)" \
@@ -142,6 +150,7 @@ clean:
 	$(MAKE) -C bin/genev/genev-cli clean
 	$(MAKE) -C bin/genev/genevd clean
 	$(MAKE) -C bin/lilith clean
+	$(MAKE) -C bin/swapd clean
 	$(MAKE) -C bin/tau/taud clean
 	$(MAKE) -C bin/vanityaddr clean
 	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release

+ 34 - 0
bin/swapd/Cargo.toml

@@ -0,0 +1,34 @@
+[package]
+name = "swapd"
+version = "0.4.1"
+homepage = "https://dark.fi"
+description = "Atomic Swap Daemon"
+authors = ["Dyne.org foundation <foundation@dyne.org>"]
+repository = "https://github.com/darkrenaissance/darkfi"
+license = "AGPL-3.0-only"
+edition = "2021"
+
+[dependencies]
+darkfi = {path = "../../", features = ["async-daemonize", "async-serial", "system", "util", "net", "rpc", "sled"]}
+darkfi-serial = {path = "../../src/serial", features = ["async"]}
+
+# Misc
+log = "0.4.20"
+
+# Encoding
+url = "2.5.0"
+
+# Database
+sled = "0.34.7"
+
+# Daemon
+easy-parallel = "3.3.1"
+signal-hook-async-std = "0.2.2"
+signal-hook = "0.3.17"
+simplelog = "0.12.1"
+smol = "1.3.0"
+
+# Argument parsing
+serde = {version = "1.0.193", features = ["derive"]}
+structopt = "0.3.26"
+structopt-toml = "0.5.1"

+ 41 - 0
bin/swapd/Makefile

@@ -0,0 +1,41 @@
+.POSIX:
+
+# Install prefix
+PREFIX = $(HOME)/.cargo
+
+# Cargo binary
+CARGO = cargo +nightly
+
+# Compile target
+RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut  -d' ' -f2)
+# Uncomment when doing musl static builds
+#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
+
+SRC = \
+	Cargo.toml \
+	../../Cargo.toml \
+	$(shell find src -type f -name '*.rs') \
+	$(shell find ../../src -type f -name '*.rs') \
+
+BIN = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
+
+all: $(BIN)
+
+$(BIN): $(SRC)
+	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(RUST_TARGET) --release --package $@
+	cp -f ../../target/$(RUST_TARGET)/release/$@ $@
+	cp -f ../../target/$(RUST_TARGET)/release/$@ ../../$@
+
+clean:
+	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release --package $(BIN)
+	rm -f $(BIN) ../../$(BIN)
+
+install: all
+	mkdir -p $(DESTDIR)$(PREFIX)/bin
+	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/$(BIN)
+
+uninstall:
+	rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
+
+.PHONY: all clean install uninstall

BIN
bin/swapd/darkfi-swapd


+ 127 - 0
bin/swapd/src/main.rs

@@ -0,0 +1,127 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use std::{collections::HashSet, sync::Arc};
+
+use darkfi::{
+    async_daemonize, cli_desc,
+    rpc::server::{listen_and_serve, RequestHandler},
+    system::{StoppableTask, StoppableTaskPtr},
+    util::path::expand_path,
+    Error, Result,
+};
+use log::{error, info};
+use serde::Deserialize;
+use smol::{fs, lock::Mutex, stream::StreamExt, Executor};
+use structopt::StructOpt;
+use structopt_toml::StructOptToml;
+use url::Url;
+
+const CONFIG_FILE: &str = "swapd.toml";
+const CONFIG_FILE_CONTENTS: &str = include_str!("../swapd.toml");
+
+/// JSON-RPC server methods
+mod rpc;
+
+#[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
+#[serde(default)]
+#[structopt(name = "darkfi-mmproxy", about = cli_desc!())]
+struct Args {
+    #[structopt(short, parse(from_occurrences))]
+    /// Increase verbosity (-vvv supported)
+    verbose: u8,
+
+    #[structopt(short, long)]
+    /// Configuration file to use
+    config: Option<String>,
+
+    #[structopt(long)]
+    /// Set log file output
+    log: Option<String>,
+
+    #[structopt(flatten)]
+    swapd: SwapdArgs,
+}
+
+#[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
+#[structopt()]
+struct SwapdArgs {
+    #[structopt(long, default_value = "tcp://127.0.0.1:52821")]
+    /// darkfi-swapd JSON-RPC listen URL
+    swapd_rpc: Url,
+
+    #[structopt(long, default_value = "~/.local/darkfi/swapd")]
+    /// Path to swapd's filesystem database
+    swapd_db: String,
+}
+
+/// Swapd daemon state
+struct Swapd {
+    /// Main reference to the swapd filesystem databaase
+    _sled_db: sled::Db,
+    /// JSON-RPC connection tracker
+    rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
+}
+
+impl Swapd {
+    /// Instantiate `Swapd` state
+    async fn new(_swapd_args: &SwapdArgs, sled_db: sled::Db) -> Result<Self> {
+        Ok(Self { _sled_db: sled_db, rpc_connections: Mutex::new(HashSet::new()) })
+    }
+}
+
+async_daemonize!(realmain);
+async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
+    info!("Starting DarkFi Atomic Swap Daemon...");
+
+    // Create datastore path if not there already.
+    let datastore = expand_path(&args.swapd.swapd_db)?;
+    fs::create_dir_all(&datastore).await?;
+    let sled_db = sled::open(datastore)?;
+
+    info!("Initializing daemon state");
+    let swapd = Arc::new(Swapd::new(&args.swapd, sled_db.clone()).await?);
+
+    info!("Starting JSON-RPC server on {}", args.swapd.swapd_rpc);
+    let swapd_ = Arc::clone(&swapd);
+    let rpc_task = StoppableTask::new();
+    rpc_task.clone().start(
+        listen_and_serve(args.swapd.swapd_rpc, swapd.clone(), None, ex.clone()),
+        |res| async move {
+            match res {
+                Ok(()) | Err(Error::RpcServerStopped) => swapd_.stop_connections().await,
+                Err(e) => error!("Failed stopping JSON-RPC server: {}", e),
+            }
+        },
+        Error::RpcServerStopped,
+        ex.clone(),
+    );
+
+    info!("Ready to operate");
+
+    // Signal handling for graceful termination.
+    let (signals_handler, signals_task) = SignalHandler::new(ex)?;
+    signals_handler.wait_termination(signals_task).await?;
+    info!("Caught termination signal, cleaning up and exiting");
+
+    info!("Flushing sled database");
+    sled_db.flush_async().await?;
+
+    info!("Shut down successfully");
+    Ok(())
+}

+ 67 - 0
bin/swapd/src/rpc.rs

@@ -0,0 +1,67 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use std::collections::HashSet;
+
+use darkfi::{
+    rpc::{
+        jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResponse, JsonResult},
+        server::RequestHandler,
+        util::JsonValue,
+    },
+    system::StoppableTaskPtr,
+};
+use darkfi_serial::async_trait;
+use smol::lock::MutexGuard;
+
+use super::Swapd;
+
+#[async_trait]
+impl RequestHandler for Swapd {
+    async fn handle_request(&self, req: JsonRequest) -> JsonResult {
+        match req.method.as_str() {
+            "ping" => self.pong(req.id, req.params).await,
+            "hello" => self.hello(req.id, req.params).await,
+            _ => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
+        }
+    }
+
+    async fn connections_mut(&self) -> MutexGuard<'_, HashSet<StoppableTaskPtr>> {
+        self.rpc_connections.lock().await
+    }
+}
+
+impl Swapd {
+    // RPCAPI:
+    // Use this kind of comment in order to have the RPC spec automatically
+    // generated in the mdbook. You should be able to write any kind of
+    // markdown in here.
+    //
+    // At the bottom, you should have the reqrep in JSON:
+    //
+    // --> {"jsonrpc": "2.0", "method": "hello", "params": ["hello"], "id": 42}
+    // --> {"jsonrpc": "2.0", "result": "hello", "id": 42}
+    async fn hello(&self, id: u16, params: JsonValue) -> JsonResult {
+        let params = params.get::<Vec<JsonValue>>().unwrap();
+        if params.len() != 1 || !params[0].is_string() {
+            return JsonError::new(ErrorCode::InvalidParams, None, id).into()
+        }
+
+        return JsonResponse::new(params[0].clone(), id).into()
+    }
+}

+ 14 - 0
bin/swapd/swapd.toml

@@ -0,0 +1,14 @@
+## darkfi-swapd configuration file
+##
+## Please make sure you go through all the settings so you can configure
+## your daemon properly.
+##
+## The default values are left commented. They can be overridden either by
+## uncommenting, or by using the command-line.
+
+#[swapd]
+# darkfi-swapd JSON-RPC listen URL.
+#swapd_rpc = "tcp://127.0.0.1:52821"
+
+# Path to swapd's filesystem database
+#swapd_db = "~/.local/darkfi/swapd"