aboutsummaryrefslogtreecommitdiff
path: root/src/modules/finger.rs
blob: 44e4df6fa15daed9f8eed2ed3acc7daa255f223f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use {
  crate::{response::success, route::track_mount},
  tokio::io::{AsyncReadExt, AsyncWriteExt},
  windmark::response::Response,
};

pub fn module(router: &mut windmark::router::Router) {
  track_mount(router, "/finger", "Finger-to-Gemini Gateway", |context| {
    success(
      &format!(
        r"# Finger-to-Gemini Gateway

To use this gateway, simply append the address of your target resource to the end of the current route, minus the protocol. Routed paths are supported!

To visit my personal Finger server, <finger://fuwn.me>, you would visit <gemini://fuwn.me/finger/fuwn.me>.

=> /finger/fuwn.me Try it!"
      ),
      &context,
    )
  });
  track_mount(
    router,
    "/finger/*uri",
    "-Finger-to-Gemini Gateway Router",
    |context| async move {
      if let Some(uri) = context.parameters.get("uri") {
        let path;
        let url = url::Url::parse({
          let mut parts = uri.split("/");
          let host = parts.next().unwrap();

          path = parts.collect::<Vec<&str>>().join("/");

          &if !host.contains(":") {
            format!("{}:79", host)
          } else {
            host.to_string()
          }
        })
        .unwrap();

        let mut stream =
          tokio::net::TcpStream::connect(url.to_string()).await.unwrap();
        let mut buffer = [0; 1024];

        stream.write_all(format!("{path}\n").as_bytes()).await.unwrap();

        let mut response = String::new();

        loop {
          let bytes_read = match stream.read(&mut buffer).await {
            Ok(0) => break,
            Ok(n) => n,
            Err(e) => {
              eprintln!("error: failed to read from socket: {:?}", e);

              break;
            }
          };

          #[allow(unsafe_code)]
          response.push_str(unsafe {
            std::str::from_utf8_unchecked(&buffer[..bytes_read])
          });
        }

        Response::success(response)
      } else {
        Response::bad_request("Invalid URI")
      }
    },
  );
}