main.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. use darkfi::{
  2. cli::{
  3. cli_config::{log_config, spawn_config},
  4. Config, MapConfig,
  5. },
  6. error::{Error, Result},
  7. rpc::{jsonrpc, jsonrpc::JsonResult},
  8. util::{async_util, join_config_path},
  9. };
  10. use async_std::sync::Arc;
  11. use easy_parallel::Parallel;
  12. use log::debug;
  13. use serde_json::{json, Value};
  14. use smol::Executor;
  15. use std::{io, io::Read, path::PathBuf};
  16. use termion::{async_stdin, event::Key, input::TermRead, raw::IntoRawMode};
  17. use tui::{
  18. backend::{Backend, TermionBackend},
  19. Terminal,
  20. };
  21. use map::{
  22. model::{Connection, IdList, InfoList, NodeInfo},
  23. ui,
  24. view::{IdListView, InfoListView},
  25. Model, View,
  26. };
  27. const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../map_config.toml");
  28. struct Map {
  29. url: String,
  30. }
  31. impl Map {
  32. pub fn new(url: String) -> Self {
  33. Self { url }
  34. }
  35. async fn request(&self, r: jsonrpc::JsonRequest) -> Result<Value> {
  36. let reply: JsonResult = match jsonrpc::send_request(&self.url, json!(r)).await {
  37. Ok(v) => v,
  38. Err(e) => return Err(e),
  39. };
  40. match reply {
  41. JsonResult::Resp(r) => {
  42. debug!(target: "RPC", "<-- {}", serde_json::to_string(&r)?);
  43. Ok(r.result)
  44. }
  45. JsonResult::Err(e) => {
  46. debug!(target: "RPC", "<-- {}", serde_json::to_string(&e)?);
  47. Err(Error::JsonRpcError(e.error.message.to_string()))
  48. }
  49. JsonResult::Notif(n) => {
  50. debug!(target: "RPC", "<-- {}", serde_json::to_string(&n)?);
  51. Err(Error::JsonRpcError("Unexpected reply".to_string()))
  52. }
  53. }
  54. }
  55. // --> {"jsonrpc": "2.0", "method": "say_hello", "params": [], "id": 42}
  56. // <-- {"jsonrpc": "2.0", "result": "hello world", "id": 42}
  57. async fn _say_hello(&self) -> Result<Value> {
  58. let req = jsonrpc::request(json!("say_hello"), json!([]));
  59. Ok(self.request(req).await?)
  60. }
  61. //--> {"jsonrpc": "2.0", "method": "poll", "params": [], "id": 42}
  62. // <-- {"jsonrpc": "2.0", "result": {"nodeID": [], "nodeinfo" [], "id": 42}
  63. async fn get_info(&self) -> Result<Value> {
  64. let req = jsonrpc::request(json!("get_info"), json!([]));
  65. Ok(self.request(req).await?)
  66. }
  67. }
  68. #[async_std::main]
  69. async fn main() -> Result<()> {
  70. let config_path = join_config_path(&PathBuf::from("map_config.toml"))?;
  71. spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
  72. let config = Config::<MapConfig>::load(config_path)?;
  73. let stdout = io::stdout().into_raw_mode()?;
  74. let backend = TermionBackend::new(stdout);
  75. let mut terminal = Terminal::new(backend)?;
  76. terminal.clear()?;
  77. let infos = Vec::new();
  78. let info_list = InfoList::new(infos.clone());
  79. let ids = Vec::new();
  80. let id_list = IdList::new(ids);
  81. let model = Arc::new(Model::new(id_list, info_list));
  82. let nthreads = num_cpus::get();
  83. let (signal, shutdown) = async_channel::unbounded::<()>();
  84. let ex = Arc::new(Executor::new());
  85. let ex2 = ex.clone();
  86. let (_, result) = Parallel::new()
  87. .each(0..nthreads, |_| smol::future::block_on(ex.run(shutdown.recv())))
  88. .finish(|| {
  89. smol::future::block_on(async move {
  90. run_rpc(&config, ex2.clone(), model.clone()).await?;
  91. render(&config, &mut terminal, model.clone()).await?;
  92. drop(signal);
  93. Ok::<(), darkfi::Error>(())
  94. })
  95. });
  96. result
  97. }
  98. async fn run_rpc(config: &MapConfig, ex: Arc<Executor<'_>>, model: Arc<Model>) -> Result<()> {
  99. // TODO: listen to multiple nodes
  100. let client = Map::new(config.nodes[0].node_id.to_string());
  101. ex.spawn(poll(client, model)).detach();
  102. Ok(())
  103. }
  104. async fn poll(client: Map, model: Arc<Model>) -> Result<()> {
  105. loop {
  106. let reply = client.get_info().await?;
  107. if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
  108. let id = reply.as_object().unwrap().get("id").unwrap();
  109. let connections = reply.as_object().unwrap().get("connections").unwrap();
  110. let outgoing = connections.get("outgoing").unwrap();
  111. let incoming = connections.get("incoming").unwrap();
  112. let mut outconnects = Vec::new();
  113. let mut inconnects = Vec::new();
  114. let out0 = Connection::new(
  115. outgoing[0].get("id").unwrap().as_str().unwrap().to_string(),
  116. outgoing[0].get("message").unwrap().as_str().unwrap().to_string(),
  117. );
  118. let out1 = Connection::new(
  119. outgoing[1].get("id").unwrap().as_str().unwrap().to_string(),
  120. outgoing[1].get("message").unwrap().as_str().unwrap().to_string(),
  121. );
  122. let in0 = Connection::new(
  123. incoming[0].get("id").unwrap().as_str().unwrap().to_string(),
  124. incoming[0].get("message").unwrap().as_str().unwrap().to_string(),
  125. );
  126. let in1 = Connection::new(
  127. incoming[1].get("id").unwrap().as_str().unwrap().to_string(),
  128. incoming[1].get("message").unwrap().as_str().unwrap().to_string(),
  129. );
  130. outconnects.push(out0);
  131. outconnects.push(out1);
  132. inconnects.push(in0);
  133. inconnects.push(in1);
  134. let infos = vec![NodeInfo {
  135. // TODO: should never crash
  136. id: id.as_str().unwrap().to_string(),
  137. outgoing: outconnects,
  138. incoming: inconnects,
  139. }];
  140. for node in infos {
  141. // update node info if we don't have it already
  142. if !model.id_list.node_id.lock().await.contains(&node.clone().id) {
  143. model.id_list.node_id.lock().await.push(node.clone().id);
  144. // TODO: update new info if we don't have
  145. model.info_list.infos.lock().await.push(node.clone());
  146. }
  147. }
  148. } else {
  149. // TODO: error handling
  150. println!("Reply is an error");
  151. }
  152. async_util::sleep(2).await;
  153. }
  154. }
  155. async fn render<B: Backend>(
  156. _config: &MapConfig,
  157. terminal: &mut Terminal<B>,
  158. model: Arc<Model>,
  159. ) -> io::Result<()> {
  160. let mut asi = async_stdin();
  161. terminal.clear()?;
  162. let id_list = IdListView::new(Vec::new());
  163. let info_list = InfoListView::new(Vec::new());
  164. let mut view = View::new(id_list.clone(), info_list.clone());
  165. view.id_list.state.select(Some(1));
  166. view.info_list.index = 0;
  167. loop {
  168. // on first run, add available nodes
  169. // every time run the program, simply update nodes
  170. let mut view = view.clone();
  171. view.update(
  172. model.id_list.node_id.lock().await.clone(),
  173. model.info_list.infos.lock().await.clone(),
  174. );
  175. if view.info_list.infos.is_empty() {
  176. // TODO: make this a loading widget
  177. println!("Initializing...");
  178. async_util::sleep(1).await;
  179. terminal.clear()?;
  180. } else {
  181. terminal.draw(|f| {
  182. ui::ui(f, view.clone());
  183. })?;
  184. }
  185. for k in asi.by_ref().keys() {
  186. match k.unwrap() {
  187. Key::Char('q') => {
  188. terminal.clear()?;
  189. return Ok(());
  190. }
  191. Key::Char('j') => {
  192. view.id_list.next();
  193. view.info_list.next().await;
  194. }
  195. Key::Char('k') => {
  196. view.id_list.previous();
  197. view.info_list.previous().await;
  198. }
  199. _ => (),
  200. }
  201. }
  202. }
  203. }