actions.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. use cursive::{views::TextArea, Cursive};
  2. use utils::{hash::Hashable as _, serialize::Serialize as _};
  3. use crate::{get_appdata, message::Message, ui, Appdata};
  4. // TODO (low): Create proper user objects. Related: add a way to verify a user.
  5. pub fn on_user_click(siv: &mut Cursive, user: &str) {
  6. let language = get_appdata(siv).language;
  7. ui::alert(siv, ui::Labels::User.localize(language), user.into());
  8. }
  9. pub fn on_message_click(siv: &mut Cursive, message_id: &str) {
  10. let appdata = get_appdata(siv);
  11. let message = appdata.messages.get(message_id);
  12. if let Some(message) = message {
  13. ui::alert(
  14. siv,
  15. ui::Labels::Message.localize(appdata.language),
  16. format!(
  17. "Time: {}\nChannel: {}\nSender: {}\nContent: {}",
  18. message.time, message.channel, message.sender, message.content
  19. ),
  20. );
  21. }
  22. }
  23. pub fn on_input_submit(siv: &mut Cursive, input_field_id: &str) {
  24. let text = siv
  25. .call_on_name(input_field_id, |view: &mut TextArea| {
  26. view.get_content().to_string()
  27. })
  28. .expect("Failed to retrieve input field content.");
  29. let appdata = get_appdata(siv);
  30. let language = appdata.language;
  31. let channel = appdata.current_channel;
  32. let message = Message::new(&appdata.username, &text, &channel);
  33. if message.is_valid() {
  34. // NOTE:
  35. // If an error was shown during send, it's likely that loading will fail too
  36. // so we don't need to show it again
  37. let mut error_dialogue_shown = false;
  38. match send_message(siv, message) {
  39. Ok(_) => clear_input_field(siv),
  40. Err(e) => {
  41. error_dialogue_shown = true;
  42. ui::error(siv, ui::Labels::FailedToSendMessage(e).localize(language))
  43. }
  44. };
  45. let res = load_messages(siv);
  46. if let Err(e) = res {
  47. if !error_dialogue_shown {
  48. ui::error(siv, ui::Labels::FailedToLoadMessages(e).localize(language));
  49. }
  50. }
  51. } else if !text.is_empty() {
  52. // Invalid message
  53. ui::error(siv, ui::Labels::InvalidMessage.localize(language));
  54. }
  55. ui::visual_update(siv);
  56. }
  57. pub fn clear_input_field(siv: &mut Cursive) {
  58. siv.call_on_name(ui::INPUT_FIELD_ID, |view: &mut TextArea| {
  59. view.set_content("");
  60. })
  61. .expect("Failed to clear input field.");
  62. }
  63. type StatusCode = u16;
  64. pub enum NetworkError {
  65. #[allow(dead_code)]
  66. ReqwestError(reqwest::Error),
  67. StatusCodeError(StatusCode),
  68. InvalidUrl,
  69. }
  70. fn fix_url(url: &str) -> Result<String, NetworkError> {
  71. if url.is_empty() {
  72. return Err(NetworkError::InvalidUrl);
  73. }
  74. let mut url = url.to_string();
  75. if !url.starts_with("http://") && !url.starts_with("https://") {
  76. url = format!("http://{}", url);
  77. }
  78. if !url.ends_with('/') {
  79. url.push('/');
  80. }
  81. Ok(url)
  82. }
  83. pub fn send_message(siv: &mut Cursive, message: Message) -> Result<(), NetworkError> {
  84. let url = fix_url(&get_appdata(siv).api_endpoint)?;
  85. let str = utils::binary::bin2hex(message.serialize_checked());
  86. let resp = reqwest::blocking::Client::new()
  87. .post(format!("{}", url))
  88. .body(str)
  89. .send()
  90. .map_err(|e| NetworkError::ReqwestError(e))?;
  91. if resp.status().is_success() {
  92. Ok(())
  93. } else {
  94. Err(NetworkError::StatusCodeError(resp.status().as_u16()))
  95. }
  96. }
  97. pub fn load_messages(siv: &mut Cursive) -> Result<(), NetworkError> {
  98. let appdata = get_appdata(siv);
  99. let url = fix_url(&appdata.api_endpoint)?;
  100. let resp = reqwest::blocking::Client::new()
  101. .get(url)
  102. .send()
  103. .map_err(|e| NetworkError::ReqwestError(e))?;
  104. if resp.status() != reqwest::StatusCode::OK {
  105. return Err(NetworkError::StatusCodeError(resp.status().as_u16()));
  106. }
  107. let bytes = resp.bytes().map_err(|e| NetworkError::ReqwestError(e))?;
  108. let contents = String::from_utf8_lossy(&bytes);
  109. let mut messages = vec![];
  110. for message_ser_hex in contents.split(",") {
  111. let Some(message_ser_bin) = utils::binary::hex2bin(message_ser_hex) else {
  112. continue;
  113. };
  114. let Ok(message) = Message::deserialize_checked(message_ser_bin) else {
  115. continue;
  116. };
  117. if message.is_valid() {
  118. messages.push(message);
  119. }
  120. }
  121. siv.with_user_data(|appdata: &mut Appdata| {
  122. for message in messages {
  123. appdata.messages.insert(message.hash().to_string(), message);
  124. }
  125. });
  126. Ok(())
  127. }