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…
	
	Add table
		
		Reference in a new issue