Rust reimplementation of Angry.Im
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

paste.rs 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. use actix_web::{http, App, AsyncResponder, Responder, HttpMessage, HttpRequest, HttpResponse};
  2. use actix_web::error::{ErrorNotFound, ErrorInternalServerError};
  3. use app::{AngryError, AngryAppState};
  4. use bytes::Bytes;
  5. use futures::Future;
  6. use futures::future::{self, Either};
  7. use htmlescape;
  8. use util;
  9. pub fn setup_routes(app: App<AngryAppState>) -> App<AngryAppState> {
  10. app.resource("/p/text", |r| r.method(http::Method::POST).f(paste))
  11. .resource("/t/{id}", |r| r.method(http::Method::GET).f(show_paste))
  12. }
  13. fn paste(req: &HttpRequest<AngryAppState>) -> impl Responder {
  14. // TODO: Maybe we can make an abstraction of the common logic
  15. // in this module and the url module?
  16. let base_url = util::conn_scheme_host_port(&req.request().connection_info());
  17. let state = req.state().clone();
  18. let state_1 = state.clone();
  19. let db = state.get_db();
  20. let db_1 = db.clone();
  21. req.body().limit(15 * 1024)
  22. .map_err(|e| e.into())
  23. .and_then(move |body: Bytes| {
  24. let id = util::rand_str(6);
  25. state.spawn_pool(db.get_async_utf8(format!("paste_{}", id)))
  26. .map(|r| (r, id, body))
  27. })
  28. .and_then(move |(r, id, body)| {
  29. if r != "" {
  30. // TODO: Retry if we hit an existing one
  31. println!("{}", r);
  32. Either::A(future::err(AngryError::String("WTF".into())))
  33. } else {
  34. Either::B(
  35. state_1.spawn_pool(db_1.set_async(format!("paste_{}", id), body.to_vec()))
  36. .map(|_| id)
  37. )
  38. }
  39. })
  40. .map(move |id| {
  41. format!("{}/t/{}", base_url, id)
  42. })
  43. .map_err(|e| {
  44. // TODO: Properly return the error
  45. // Maybe we need a class to convert AngryError into corresponding HTTP errors?
  46. // e.g. maybe return 404 if we cannot parse the request string?
  47. println!("{:?}", e);
  48. ErrorInternalServerError(e)
  49. })
  50. .responder()
  51. }
  52. fn show_paste(req: &HttpRequest<AngryAppState>) -> impl Responder {
  53. let ua = req.headers().get(http::header::USER_AGENT)
  54. .and_then(|r| {
  55. r.to_str().ok()
  56. }).unwrap_or("").to_owned();
  57. let id = req.match_info().get("id").unwrap().to_owned();
  58. let state = req.state().clone();
  59. let db = state.get_db();
  60. state.spawn_pool(db.get_async_utf8(format!("paste_{}", id)))
  61. .map_err(|e| {
  62. println!("{:?}", e);
  63. ErrorInternalServerError(e)
  64. })
  65. .and_then(move |p| {
  66. if p != "" {
  67. let mut resp = HttpResponse::Ok();
  68. if util::ua_is_browser(&ua) {
  69. // Show a rendered HTML for GUI browsers
  70. resp.header(http::header::CONTENT_TYPE, "text/html");
  71. Ok(resp.body(
  72. include_str!("../../template/code.html")
  73. .replace("{{code}}", &htmlescape::encode_minimal(&p))))
  74. } else {
  75. resp.header(http::header::CONTENT_TYPE, "text/plain");
  76. Ok(resp.body(p))
  77. }
  78. } else {
  79. Err(ErrorNotFound("Paste data not recorded"))
  80. }
  81. })
  82. .responder()
  83. }