forked from mirrors/relay
Add ructe
This commit is contained in:
parent
ef13e93140
commit
fbed60248d
8 changed files with 271 additions and 23 deletions
1
.env
1
.env
|
@ -1 +1,2 @@
|
|||
OUT_DIR="compiled_templates"
|
||||
DATABASE_URL=postgres://ap_actix:ap_actix@localhost:5432/ap_actix
|
||||
|
|
57
Cargo.lock
generated
57
Cargo.lock
generated
|
@ -581,6 +581,12 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
|
@ -1160,6 +1166,15 @@ dependencies = [
|
|||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
|
@ -1443,6 +1458,17 @@ dependencies = [
|
|||
"num-traits 0.2.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-integer",
|
||||
"num-traits 0.2.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
|
@ -1764,12 +1790,14 @@ dependencies = [
|
|||
"http-signature-normalization-actix",
|
||||
"log",
|
||||
"lru",
|
||||
"mime",
|
||||
"num_cpus",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"rsa",
|
||||
"rsa-magic-public-key",
|
||||
"rsa-pem",
|
||||
"ructe",
|
||||
"serde 1.0.105",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
@ -1850,6 +1878,35 @@ dependencies = [
|
|||
"yasna",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsass"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53314103d427bab245db7b3d1602faf509d2dd03db85b32421d1748e93bb4475"
|
||||
dependencies = [
|
||||
"bytecount",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"num-rational",
|
||||
"num-traits 0.2.11",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ructe"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c85620b8046f88a870d93d90fa56904dec76cc79139bfcc22e71e87f0cd2169f"
|
||||
dependencies = [
|
||||
"base64 0.11.0",
|
||||
"bytecount",
|
||||
"itertools",
|
||||
"md5",
|
||||
"mime",
|
||||
"nom",
|
||||
"rsass",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.13.0"
|
||||
|
|
|
@ -8,6 +8,7 @@ readme = "README.md"
|
|||
repository = "https://git.asonix.dog/asonix/ap-relay"
|
||||
keywords = ["activitypub", "relay"]
|
||||
edition = "2018"
|
||||
build = "src/build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -27,6 +28,7 @@ futures = "0.3.4"
|
|||
http-signature-normalization-actix = { version = "0.3.0-alpha.7", default-features = false, features = ["sha-2"] }
|
||||
log = "0.4"
|
||||
lru = "0.4.3"
|
||||
mime = "0.3.16"
|
||||
num_cpus = "1.12"
|
||||
pretty_env_logger = "0.4.0"
|
||||
rand = "0.7"
|
||||
|
@ -42,5 +44,10 @@ tokio = { version = "0.2.13", features = ["sync"] }
|
|||
ttl_cache = "0.5.1"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0"
|
||||
dotenv = "0.15.0"
|
||||
ructe = { version = "0.9.2", features = ["sass", "mime03"] }
|
||||
|
||||
[profile.dev.package.rsa]
|
||||
opt-level = 3
|
||||
|
|
82
scss/index.scss
Normal file
82
scss/index.scss
Normal file
|
@ -0,0 +1,82 @@
|
|||
body {
|
||||
background-color: #f5f5f5;
|
||||
font-family: sans-serif;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 96px;
|
||||
}
|
||||
|
||||
body,
|
||||
body * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 32px 0;
|
||||
background-color: #333;
|
||||
color: #f5f5f5;
|
||||
text-align: center;
|
||||
|
||||
h1 {
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 3px;
|
||||
margin: 32px auto 0;
|
||||
max-width: 700px;
|
||||
|
||||
h3 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 3px;
|
||||
background-color: #f5f5f5;
|
||||
padding: 8px;
|
||||
padding-left: 32px;
|
||||
padding-top: 10px;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 24px;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: #333;
|
||||
color: #f5f5f5;
|
||||
position: absolute;
|
||||
padding: 16px 8px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
&,
|
||||
&:focus,
|
||||
&:hover,
|
||||
&:active {
|
||||
color: #ea7fbc;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
12
src/build.rs
Normal file
12
src/build.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use ructe::Ructe;
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
let mut ructe = Ructe::from_env()?;
|
||||
let mut statics = ructe.statics()?;
|
||||
statics.add_sass_file("scss/index.scss")?;
|
||||
ructe.compile_templates("templates")?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -64,6 +64,9 @@ pub enum MyError {
|
|||
#[error("Too many CPUs, {0}")]
|
||||
CpuCount(#[from] std::num::TryFromIntError),
|
||||
|
||||
#[error("Couldn't flush buffer")]
|
||||
FlushBuffer,
|
||||
|
||||
#[error("Timed out while waiting on db pool")]
|
||||
DbTimeout,
|
||||
|
||||
|
|
68
src/main.rs
68
src/main.rs
|
@ -1,5 +1,14 @@
|
|||
use actix_web::{middleware::Logger, web, App, HttpServer, Responder};
|
||||
use actix_web::{
|
||||
http::header::{ContentType, Expires},
|
||||
middleware::Logger,
|
||||
web, App, HttpResponse, HttpServer,
|
||||
};
|
||||
use bb8_postgres::tokio_postgres;
|
||||
use log::error;
|
||||
use std::{
|
||||
io::BufWriter,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
mod actor;
|
||||
mod apub;
|
||||
|
@ -17,32 +26,42 @@ mod state;
|
|||
mod verifier;
|
||||
mod webfinger;
|
||||
|
||||
use self::{args::Args, config::Config, db::Db, state::State, webfinger::RelayResolver};
|
||||
|
||||
async fn index(state: web::Data<State>, config: web::Data<Config>) -> impl Responder {
|
||||
let mut s = String::new();
|
||||
s.push_str(&format!("Welcome to the relay on {}\n", config.hostname()));
|
||||
use self::{
|
||||
args::Args, config::Config, db::Db, error::MyError, state::State,
|
||||
templates::statics::StaticFile, webfinger::RelayResolver,
|
||||
};
|
||||
|
||||
async fn index(
|
||||
state: web::Data<State>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, MyError> {
|
||||
let listeners = state.listeners().await;
|
||||
if listeners.is_empty() {
|
||||
s.push_str("There are no currently connected servers\n");
|
||||
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
||||
templates::index(&mut buf, &listeners, &config)?;
|
||||
let buf = buf.into_inner().map_err(|e| {
|
||||
error!("Error rendering template, {}", e.error());
|
||||
MyError::FlushBuffer
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(buf))
|
||||
}
|
||||
|
||||
static FAR: Duration = Duration::from_secs(60 * 60 * 24);
|
||||
|
||||
async fn static_file(filename: web::Path<String>) -> HttpResponse {
|
||||
if let Some(data) = StaticFile::get(&filename.into_inner()) {
|
||||
let far_expires = SystemTime::now() + FAR;
|
||||
HttpResponse::Ok()
|
||||
.set(Expires(far_expires.into()))
|
||||
.set(ContentType(data.mime.clone()))
|
||||
.body(data.content)
|
||||
} else {
|
||||
s.push_str("Here are the currently connected servers:\n");
|
||||
s.push_str("\n");
|
||||
HttpResponse::NotFound()
|
||||
.reason("No such static file.")
|
||||
.finish()
|
||||
}
|
||||
|
||||
for listener in listeners {
|
||||
if let Some(domain) = listener.as_url().domain() {
|
||||
s.push_str(&format!("{}\n", domain));
|
||||
}
|
||||
}
|
||||
s.push_str("\n");
|
||||
s.push_str(&format!(
|
||||
"The source code for this project can be found at {}\n",
|
||||
config.source_code()
|
||||
));
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
#[actix_rt::main]
|
||||
|
@ -107,9 +126,12 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
.service(actix_webfinger::scoped::<_, RelayResolver>())
|
||||
.service(web::resource("/nodeinfo").route(web::get().to(nodeinfo::well_known))),
|
||||
)
|
||||
.service(web::resource("/static/{filename}").route(web::get().to(static_file)))
|
||||
})
|
||||
.bind(bind_address)?
|
||||
.run()
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
||||
|
|
64
templates/index.rs.html
Normal file
64
templates/index.rs.html
Normal file
|
@ -0,0 +1,64 @@
|
|||
@use crate::{config::{Config, UrlKind}, templates::statics::index_css};
|
||||
@use activitystreams::primitives::XsdAnyUri;
|
||||
|
||||
@(listeners: &[XsdAnyUri], config: &Config)
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="utf-8"/>
|
||||
<title>@config.hostname() | ActivityPub Relay</title>
|
||||
<link rel="stylesheet" href="/static/@index_css.name" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Welcome to @config.software_name() on @config.hostname()</h1>
|
||||
</header>
|
||||
<main>
|
||||
<section>
|
||||
<h3>Connected Servers:</h3>
|
||||
@if listeners.is_empty() {
|
||||
<p>There are no connected servers at this time.</p>
|
||||
} else {
|
||||
<ul>
|
||||
@for listener in listeners {
|
||||
@if let Some(domain) = listener.as_url().domain() {
|
||||
<li>@domain</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</section>
|
||||
<section>
|
||||
<h3>Joining</h3>
|
||||
<p>
|
||||
If you are the admin of a server that supports activitypub relays, you can add
|
||||
this relay to your server.
|
||||
</p>
|
||||
<h4>Mastodon</h4>
|
||||
<p>
|
||||
Mastodon admins can add this relay by adding
|
||||
<pre>@config.generate_url(UrlKind::Inbox)</pre> in their relay settings.
|
||||
</p>
|
||||
<h4>Pleroma</h4>
|
||||
<p>
|
||||
Pleroma admins can add this relay by adding
|
||||
<pre>@config.generate_url(UrlKind::Actor)</pre>
|
||||
to their relay settings (I don't actually know how pleroma handles adding
|
||||
relays, is it still a mix command?).
|
||||
</p>
|
||||
<h4>Others</h4>
|
||||
<p>
|
||||
Consult the documentation for your server. It's likely that it follows either
|
||||
Mastodon or Pleroma's relay formatting.
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
<p>
|
||||
The source code for this project can be found at
|
||||
<a href="@config.source_code()">@config.source_code()</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue