Initial commit
This commit is contained in:
commit
7494237d19
12 changed files with 1890 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
/static/**.mjs
|
1600
Cargo.lock
generated
Normal file
1600
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "fedirect"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.5.1"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
serde_json = "1.0.135"
|
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# FeDirect
|
||||
|
||||
Fedi links that open on your preferred instance!
|
||||
|
||||
## Building
|
||||
|
||||
To compile TypeScript, the build script assumes Deno is installed.
|
||||
|
||||
When you have Deno and Rust installed, simply use Cargo to build the project
|
||||
|
||||
```sh
|
||||
# For example, to build for release, you can do
|
||||
cargo build --release
|
||||
# Or, to immediately run it
|
||||
cargo run --release
|
||||
# Or, to run during development:
|
||||
cargo run
|
||||
```
|
14
build.rs
Normal file
14
build.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
println!("cargo::rerun-if-changed=tsconfig.json");
|
||||
println!("cargo::rerun-if-changed=static/**.mts");
|
||||
assert!(Command::new("deno")
|
||||
.args(["run", "-A", "npm:typescript/tsc"])
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.status()
|
||||
.unwrap()
|
||||
.success());
|
||||
}
|
89
known-software.json
Normal file
89
known-software.json
Normal file
|
@ -0,0 +1,89 @@
|
|||
{
|
||||
"software": {
|
||||
"misskey": {
|
||||
"aliases": [
|
||||
"misskey",
|
||||
"mk"
|
||||
],
|
||||
"groups": [
|
||||
"misskey-compliant",
|
||||
"misskey-v13"
|
||||
]
|
||||
},
|
||||
"sharkey": {
|
||||
"aliases": [
|
||||
"sharkey",
|
||||
"sk"
|
||||
],
|
||||
"groups": [
|
||||
"misskey-compliant",
|
||||
"misskey-v13"
|
||||
],
|
||||
"forkOf": "misskey"
|
||||
},
|
||||
"iceshrimp-js": {
|
||||
"aliases": [
|
||||
"iceshrimp-js"
|
||||
],
|
||||
"groups": [
|
||||
"misskey-compliant",
|
||||
"misskey-v12",
|
||||
"iceshrimp"
|
||||
],
|
||||
"forkOf": "misskey"
|
||||
},
|
||||
"iceshrimp-dotnet": {
|
||||
"aliases": [
|
||||
"iceshrimp-dotnet"
|
||||
],
|
||||
"groups": [
|
||||
"misskey-compliant",
|
||||
"misskey-v12",
|
||||
"iceshrimp"
|
||||
],
|
||||
"forkOf": "misskey"
|
||||
},
|
||||
"firefish": {
|
||||
"aliases": [
|
||||
"firefish",
|
||||
"calckey"
|
||||
],
|
||||
"groups": [
|
||||
"misskey-compliant",
|
||||
"misskey-v12"
|
||||
],
|
||||
"forkOf": "misskey"
|
||||
}
|
||||
},
|
||||
"groups": {
|
||||
"misskey-compliant": {
|
||||
"aliases": [
|
||||
"misskey-compliant",
|
||||
"mkc"
|
||||
]
|
||||
},
|
||||
"misskey-v12": {
|
||||
"aliases": [
|
||||
"misskey-v12",
|
||||
"misskeyv12",
|
||||
"misskey12",
|
||||
"mkv12",
|
||||
"mk12"
|
||||
]
|
||||
},
|
||||
"misskey-v13": {
|
||||
"aliases": [
|
||||
"misskey-v13",
|
||||
"misskeyv13",
|
||||
"misskey13",
|
||||
"mkv13",
|
||||
"mk13"
|
||||
]
|
||||
},
|
||||
"iceshrimp": {
|
||||
"aliases": [
|
||||
"iceshrimp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
67
src/known_software.rs
Normal file
67
src/known_software.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use rocket::request::FromParam;
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
pub static KNOWN_SOFTWARE: LazyLock<KnownSoftware> =
|
||||
LazyLock::new(|| serde_json::from_str(include_str!("../known-software.json")).unwrap());
|
||||
pub static KNOWN_SOFTWARE_NAMES: LazyLock<HashMap<String, String>> =
|
||||
LazyLock::new(|| KNOWN_SOFTWARE.get_name_map());
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Software {
|
||||
aliases: HashSet<String>,
|
||||
groups: HashSet<String>,
|
||||
fork_of: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Group {
|
||||
aliases: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct KnownSoftware {
|
||||
software: HashMap<String, Software>,
|
||||
groups: HashMap<String, Group>,
|
||||
}
|
||||
|
||||
impl KnownSoftware {
|
||||
fn get_name_map(&self) -> HashMap<String, String> {
|
||||
let mut map = HashMap::new();
|
||||
self.software.iter().for_each(|(name, software)| {
|
||||
software.aliases.iter().for_each(|alias| {
|
||||
assert_eq!(map.insert(alias.to_owned(), name.to_owned()), None);
|
||||
});
|
||||
});
|
||||
self.groups.iter().for_each(|(name, group)| {
|
||||
group.aliases.iter().for_each(|alias: &String| {
|
||||
assert_eq!(map.insert(alias.to_owned(), name.to_owned()), None);
|
||||
});
|
||||
});
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KnownInstanceSoftware<'r> {
|
||||
pub requested: &'r str,
|
||||
pub resolved: &'static String,
|
||||
}
|
||||
|
||||
impl<'r> FromParam<'r> for KnownInstanceSoftware<'r> {
|
||||
type Error = &'r str;
|
||||
|
||||
fn from_param(param: &'r str) -> Result<Self, Self::Error> {
|
||||
if let Some(resolved) = KNOWN_SOFTWARE_NAMES.get(param) {
|
||||
Ok(KnownInstanceSoftware {
|
||||
requested: param,
|
||||
resolved,
|
||||
})
|
||||
} else {
|
||||
Err(param)
|
||||
}
|
||||
}
|
||||
}
|
51
src/main.rs
Normal file
51
src/main.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
use known_software::KnownInstanceSoftware;
|
||||
use rocket::{
|
||||
fs::{FileServer, NamedFile},
|
||||
http::ContentType,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod known_software;
|
||||
|
||||
#[get("/known-software.json")]
|
||||
async fn known_software_json() -> Option<NamedFile> {
|
||||
NamedFile::open("known-software.json").await.ok()
|
||||
}
|
||||
|
||||
#[get("/<instance>/<route..>", rank = 1)]
|
||||
async fn route_for_known_instance_software(
|
||||
instance: KnownInstanceSoftware<'_>,
|
||||
route: PathBuf,
|
||||
) -> Option<NamedFile> {
|
||||
NamedFile::open("static/crossroad.html").await.ok()
|
||||
}
|
||||
|
||||
#[get("/<instance>/<route..>", rank = 2)]
|
||||
fn route_for_unknown_instance_software(instance: &str, route: PathBuf) -> (ContentType, String) {
|
||||
(
|
||||
ContentType::HTML,
|
||||
format!(
|
||||
"Hello from <code>{}</code>! The software <code>{}</code> is unknown.",
|
||||
route.display(),
|
||||
instance
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
rocket::build()
|
||||
.mount("/static", FileServer::from("static").rank(0))
|
||||
.mount("/api", routes![])
|
||||
.mount(
|
||||
"/",
|
||||
routes![
|
||||
known_software_json,
|
||||
route_for_known_instance_software,
|
||||
route_for_unknown_instance_software
|
||||
],
|
||||
)
|
||||
}
|
11
static/crossroad.html
Normal file
11
static/crossroad.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>FeDirect</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="/static/crossroad.mjs"></script>
|
||||
</body>
|
||||
</html>
|
2
static/crossroad.mts
Normal file
2
static/crossroad.mts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import knownSoftware from "./known_software.mjs";
|
||||
console.log(knownSoftware);
|
16
static/known_software.mts
Normal file
16
static/known_software.mts
Normal file
|
@ -0,0 +1,16 @@
|
|||
type Software = {
|
||||
aliases: string[],
|
||||
groups: string[],
|
||||
forkOf?: string,
|
||||
}
|
||||
|
||||
type Group = {
|
||||
aliases: string[],
|
||||
}
|
||||
|
||||
type KnownSoftware = {
|
||||
software: Record<string, Software>,
|
||||
groups: Record<string, Group>,
|
||||
}
|
||||
|
||||
export default await fetch("/known-software.json").then(r => r.json()) as KnownSoftware;
|
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2023",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"strictNullChecks": true,
|
||||
},
|
||||
"include": [
|
||||
"static/**.mts",
|
||||
],
|
||||
}
|
Loading…
Add table
Reference in a new issue