Skip to content

Commit

Permalink
Merge pull request #86 from eigerco/feat/66/polka-storage-provider-pr…
Browse files Browse the repository at this point in the history
…int-start-time-of-the-provider

Feat/66/polka storage provider print start time of the provider
  • Loading branch information
cernicc authored Jun 28, 2024
2 parents 92f2d99 + 5fedadb commit ee54b73
Show file tree
Hide file tree
Showing 18 changed files with 523 additions and 183 deletions.
19 changes: 17 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", t

async-channel = "2.3.1"
async-stream = "0.3.5"
async-trait = "0.1.80"
base64 = "0.22.1"
bitflags = "2.5.0"
blake2b_simd = { version = "1.0.2" }
Expand Down Expand Up @@ -67,6 +68,7 @@ quote = { version = "1.0.33" }
rand = "0.8.5"
rocksdb = { version = "0.21" }
scale-info = { version = "2.11.1", default-features = false }
sealed = "0.5"
serde = { version = "1.0.197", default-features = false }
serde-big-array = { version = "0.3.2" }
serde_derive = { version = "1.0.117" }
Expand Down
5 changes: 4 additions & 1 deletion cli/polka-storage-provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ repository.workspace = true
version = "0.1.0"

[dependencies]
async-trait = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
clap = { workspace = true, features = ["derive"] }
jsonrpsee = { workspace = true, features = ["server"] }
jsonrpsee = { workspace = true, features = ["http-client", "server", "ws-client"] }
sc-cli = { workspace = true }
sealed = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
subxt = { workspace = true }
Expand All @@ -21,6 +23,7 @@ tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
url = { workspace = true }
uuid = { workspace = true }

[lints]
workspace = true
33 changes: 32 additions & 1 deletion cli/polka-storage-provider/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use clap::Parser;
use thiserror::Error;
use url::Url;

use crate::commands::{InfoCommand, InitCommand, RunCommand, WalletCommand};
use crate::{
commands::{InfoCommand, InitCommand, RunCommand, WalletCommand},
rpc::{server::RPC_SERVER_DEFAULT_BIND_ADDR, ClientError},
};

/// A CLI application that facilitates management operations over a running full
/// node and other components.
Expand All @@ -9,6 +14,10 @@ use crate::commands::{InfoCommand, InitCommand, RunCommand, WalletCommand};
pub(crate) struct Cli {
#[command(subcommand)]
pub subcommand: SubCommand,

/// URL of the providers RPC server.
#[arg(long, default_value_t = Url::parse(&format!("http://{RPC_SERVER_DEFAULT_BIND_ADDR}")).unwrap())]
pub rpc_server_url: Url,
}

/// Supported sub-commands.
Expand All @@ -24,3 +33,25 @@ pub enum SubCommand {
#[command(subcommand)]
Wallet(WalletCommand),
}

/// CLI components error handling implementor.
#[derive(Debug, Error)]
pub enum CliError {
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),

#[error("FromEnv error: {0}")]
EnvError(#[from] tracing_subscriber::filter::FromEnvError),

#[error("URL parse error: {0}")]
ParseUrl(#[from] url::ParseError),

#[error("Substrate error: {0}")]
Substrate(#[from] subxt::Error),

#[error(transparent)]
SubstrateCli(#[from] sc_cli::Error),

#[error("Rpc Client error: {0}")]
RpcClient(#[from] ClientError),
}
33 changes: 29 additions & 4 deletions cli/polka-storage-provider/src/commands/info.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
use std::fmt::{self, Display, Formatter};

use chrono::{DateTime, Utc};
use clap::Parser;

use crate::Error;
use crate::{
cli::CliError,
rpc::{methods::common::InfoRequest, version::V0, Client},
};

/// Command to display information about the storage provider.
#[derive(Debug, Clone, Parser)]
pub(crate) struct InfoCommand;

impl InfoCommand {
pub async fn run(&self) -> Result<(), Error> {
// TODO(#66,@cernicc,31/05/2024): Print start time of the provider
pub async fn run(&self, client: &Client<V0>) -> Result<(), CliError> {
// TODO(#67,@cernicc,07/06/2024): Print polkadot address used by the provider
unimplemented!()

// Get server info
let server_info = client.execute(InfoRequest).await?;

let node_status_info = NodeStatusInfo {
start_time: server_info.start_time,
};

println!("{}", node_status_info);

Ok(())
}
}

struct NodeStatusInfo {
start_time: DateTime<Utc>,
}

impl Display for NodeStatusInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(f, "Started at: {}", self.start_time)
}
}
4 changes: 2 additions & 2 deletions cli/polka-storage-provider/src/commands/init.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use clap::Parser;
use tracing::info;

use crate::Error;
use crate::cli::CliError;

/// Command to initialize the storage provider.
#[derive(Debug, Clone, Parser)]
pub(crate) struct InitCommand;

impl InitCommand {
pub async fn run(&self) -> Result<(), Error> {
pub async fn run(&self) -> Result<(), CliError> {
info!("Initializing polka storage provider...");
// TODO(#64,@cernicc,31/05/2024): Init needed configurations.
// TODO(#65,@cernicc,31/05/2024): Check if full node is synced
Expand Down
20 changes: 10 additions & 10 deletions cli/polka-storage-provider/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ use tracing::info;
use url::Url;

use crate::{
rpc::{start_rpc, RpcServerState},
substrate, Error,
cli::CliError,
rpc::server::{start_rpc_server, RpcServerState, RPC_SERVER_DEFAULT_BIND_ADDR},
substrate,
};

const SERVER_DEFAULT_BIND_ADDR: &str = "127.0.0.1:8000";
const FULL_NODE_DEFAULT_RPC_ADDR: &str = "ws://127.0.0.1:9944";

/// Command to start the storage provider.
#[derive(Debug, Clone, Parser)]
pub(crate) struct RunCommand {
/// RPC API endpoint used by the parachain node.
#[arg(short = 'n', long, default_value = FULL_NODE_DEFAULT_RPC_ADDR)]
pub node_rpc_address: Url,
/// Address used for RPC. By default binds on localhost on port 8000.
#[arg(short = 'a', long, default_value = SERVER_DEFAULT_BIND_ADDR)]
#[arg(long, default_value = FULL_NODE_DEFAULT_RPC_ADDR)]
pub rpc_address: Url,
/// Address and port used for RPC server.
#[arg(long, default_value = RPC_SERVER_DEFAULT_BIND_ADDR)]
pub listen_addr: SocketAddr,
}

impl RunCommand {
pub async fn run(&self) -> Result<(), Error> {
let substrate_client = substrate::init_client(self.node_rpc_address.as_str()).await?;
pub async fn run(&self) -> Result<(), CliError> {
let substrate_client = substrate::init_client(self.rpc_address.as_str()).await?;

let state = Arc::new(RpcServerState {
start_time: Utc::now(),
substrate_client,
});

// Start RPC server
let handle = start_rpc(state, self.listen_addr).await?;
let handle = start_rpc_server(state, self.listen_addr).await?;
info!("RPC server started at {}", self.listen_addr);

// Monitor shutdown
Expand Down
17 changes: 12 additions & 5 deletions cli/polka-storage-provider/src/commands/runner.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
use clap::Parser;

use super::WalletCommand;
use crate::{cli::SubCommand, Cli, Error};
use crate::{
cli::{CliError, SubCommand},
rpc::Client,
Cli,
};

/// Parses command line arguments into the service configuration and runs the specified
/// command with it.
pub(crate) async fn run() -> Result<(), Error> {
/// Parses command line arguments into the service configuration and runs the
/// specified command with it.
pub(crate) async fn run() -> Result<(), CliError> {
// CLI arguments parsed and mapped to the struct.
let cli_arguments: Cli = Cli::parse();

// RPC client used to interact with the full node
let rpc_client = Client::new(cli_arguments.rpc_server_url).await?;

match &cli_arguments.subcommand {
SubCommand::Init(cmd) => cmd.run().await,
SubCommand::Run(cmd) => cmd.run().await,
SubCommand::Info(cmd) => cmd.run().await,
SubCommand::Info(cmd) => cmd.run(&rpc_client).await,
SubCommand::Wallet(cmd) => match cmd {
WalletCommand::GenerateNodeKey(cmd) => Ok(cmd.run()?),
WalletCommand::Generate(cmd) => Ok(cmd.run()?),
Expand Down
17 changes: 0 additions & 17 deletions cli/polka-storage-provider/src/error.rs

This file was deleted.

5 changes: 2 additions & 3 deletions cli/polka-storage-provider/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@

mod cli;
pub(crate) mod commands;
mod error;
mod rpc;
mod substrate;

pub(crate) use cli::Cli;
use cli::CliError;
use commands::runner;
pub(crate) use error::Error;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

#[tokio::main]
async fn main() -> Result<(), Error> {
async fn main() -> Result<(), CliError> {
// Logger initialization.
tracing_subscriber::registry()
.with(fmt::layer())
Expand Down
73 changes: 4 additions & 69 deletions cli/polka-storage-provider/src/rpc.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,6 @@
use std::{future::Future, net::SocketAddr, sync::Arc};

use chrono::Utc;
use error::ServerError;
use jsonrpsee::{
server::{Server, ServerHandle},
types::Params,
RpcModule,
};
use methods::create_module;
use serde::{Deserialize, Serialize};

use crate::{substrate, Error};

pub mod error;
mod client;
pub mod methods;
pub mod server;
pub mod version;

/// A definition of an RPC method handler which can be registered with an [`RpcModule`].
pub trait RpcMethod {
/// Method name.
const NAME: &'static str;
/// See [`ApiVersion`].
const API_VERSION: ApiVersion;
/// Successful response type.
type Ok: Serialize;

/// Logic for this method.
fn handle(
ctx: Arc<RpcServerState>,
params: Params,
) -> impl Future<Output = Result<Self::Ok, ServerError>> + Send;

/// Register this method with an [`RpcModule`].
fn register_async(module: &mut RpcModule<RpcServerState>) -> &mut jsonrpsee::MethodCallback
where
Self::Ok: Clone + 'static,
{
module
.register_async_method(Self::NAME, move |params, ctx| async move {
let ok = Self::handle(ctx, params).await?;
Result::<_, jsonrpsee::types::ErrorObjectOwned>::Ok(ok)
})
.expect("method should be valid") // This is safe because we know the method registered is valid.
}
}

/// Available API versions.
///
/// These are significant because they are expressed in the URL path against
/// which RPC calls are made, e.g `rpc/v0` or `rpc/v1`.
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ApiVersion {
V0,
}

pub struct RpcServerState {
pub start_time: chrono::DateTime<Utc>,
pub substrate_client: substrate::Client,
}

pub async fn start_rpc(
state: Arc<RpcServerState>,
listen_addr: SocketAddr,
) -> Result<ServerHandle, Error> {
let server = Server::builder().build(listen_addr).await?;

let module = create_module(state.clone());
let server_handle = server.start(module);

Ok(server_handle)
}
pub use client::{Client, ClientError};
Loading

0 comments on commit ee54b73

Please sign in to comment.