Linstrom is moving to Go!
Reason: Fuck AGPL
This commit is contained in:
parent
f9509e7791
commit
33bdd96fb1
32 changed files with 41 additions and 4053 deletions
|
@ -1,36 +0,0 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
|
||||
{
|
||||
"name": "Rust",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
|
||||
"features": {
|
||||
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {},
|
||||
"ghcr.io/itsmechlark/features/postgresql:1": {},
|
||||
"ghcr.io/robbert229/devcontainer-features/postgresql-client:1": {}
|
||||
},
|
||||
|
||||
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
|
||||
// "mounts": [
|
||||
// {
|
||||
// "source": "devcontainer-cargo-cache-${devcontainerId}",
|
||||
// "target": "/usr/local/cargo",
|
||||
// "type": "volume"
|
||||
// }
|
||||
// ]
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "cargo install diesel_cli --no-default-features --features postgres,sqlite"
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
3047
Cargo.lock
generated
3047
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
33
Cargo.toml
33
Cargo.toml
|
@ -1,33 +0,0 @@
|
|||
[package]
|
||||
name = "linstrom"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["mStar"]
|
||||
license = "EUPL-1.2"
|
||||
description = "An ActivityPub enabled social media server focused on helping with user safety"
|
||||
readme = "README.md"
|
||||
repository = "https://gitlab.com/mstarongitlab/linstrom"
|
||||
|
||||
exclude = ["/.vscode", "/FeatureTargets.md"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
activitypub_federation = "0.5.0"
|
||||
axum = "0.7.1"
|
||||
diesel = { version = "2.1.4", features = ["sqlite", "postgres", "r2d2", "chrono"] }
|
||||
tokio = { version = "1.34.0", features = ["full"]}
|
||||
build_html = "2.4.0"
|
||||
serde = "1.0.193"
|
||||
url = "2.5.0"
|
||||
chrono = "0.4.31"
|
||||
tracing = "0.1.40"
|
||||
rand = "0.8.5"
|
||||
anyhow = "1.0.77"
|
||||
async-trait = "0.1.75"
|
||||
dotenvy = "0.15.7"
|
||||
clap = { version = "4.4.12", features = ["derive"] }
|
||||
toml = "0.8.8"
|
||||
serde_derive = "1.0.193"
|
||||
sysinfo = "0.30.3"
|
||||
diesel_migrations = "2.1.0"
|
||||
serde_json = "1.0.111"
|
|
@ -1,20 +1,25 @@
|
|||
# UI
|
||||
# Feature targets
|
||||
|
||||
## UI
|
||||
|
||||
- Firefish like
|
||||
- htmx
|
||||
|
||||
# Features
|
||||
## Features
|
||||
|
||||
### QoL
|
||||
|
||||
## QoL
|
||||
- [ ] Reactions
|
||||
- [ ] Qoute tweets
|
||||
- [ ] misskey/firefish markdown
|
||||
|
||||
## Moderation
|
||||
### Moderation
|
||||
|
||||
- [ ] Authorized Fetch
|
||||
- [ ] Lockdown (user/server) (block/ignore any incoming messages)
|
||||
- [ ] Filter-based (maybe regex) auto-block/refuse follow requests
|
||||
|
||||
## General
|
||||
### General
|
||||
|
||||
- [ ] Masto, MK/FF, Akoma/Plemora API
|
||||
- [ ] is_cat
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[config]
|
||||
database_path = "src/storage/db.sqlite"
|
||||
max_workers = 100
|
||||
min_workers = 200
|
|
@ -1,9 +0,0 @@
|
|||
# For documentation on how to configure this file,
|
||||
# see https://diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/storage/pg_schemas.rs"
|
||||
custom_type_derives = ["diesel::query_builder::QueryId"]
|
||||
|
||||
[migrations_directory]
|
||||
dir = "migrations"
|
14
go.mod
Normal file
14
go.mod
Normal file
|
@ -0,0 +1,14 @@
|
|||
module gitlab.com/beckersam/linstrom
|
||||
|
||||
go 1.21.5
|
||||
|
||||
require (
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 // indirect
|
||||
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
gorm.io/gorm v1.25.5 // indirect
|
||||
)
|
16
go.sum
Normal file
16
go.sum
Normal file
|
@ -0,0 +1,16 @@
|
|||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI=
|
||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9/go.mod h1:cJ9Ye0ZNSMN7RzZDBRY3E+8M3Bpf/R1JX22Ir9yX6WI=
|
||||
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 h1:I2nuhyVI/48VXoRCCZR2hYBgnSXa+EuDJf/VyX06TC0=
|
||||
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7/go.mod h1:5x8a6P/dhmMGFxWLcyYlyOuJ2lRNaHGhRv+yu8BaTSI=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
|
@ -1,6 +0,0 @@
|
|||
-- This file was automatically created by Diesel to setup helper functions
|
||||
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||
-- changes will be added to existing projects as new migrations.
|
||||
|
||||
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
|
||||
DROP FUNCTION IF EXISTS diesel_set_updated_at();
|
|
@ -1,36 +0,0 @@
|
|||
-- This file was automatically created by Diesel to setup helper functions
|
||||
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||
-- changes will be added to existing projects as new migrations.
|
||||
|
||||
|
||||
|
||||
|
||||
-- Sets up a trigger for the given table to automatically set a column called
|
||||
-- `updated_at` whenever the row is modified (unless `updated_at` was included
|
||||
-- in the modified columns)
|
||||
--
|
||||
-- # Example
|
||||
--
|
||||
-- ```sql
|
||||
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
|
||||
--
|
||||
-- SELECT diesel_manage_updated_at('users');
|
||||
-- ```
|
||||
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
|
||||
BEGIN
|
||||
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
|
||||
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
|
||||
BEGIN
|
||||
IF (
|
||||
NEW IS DISTINCT FROM OLD AND
|
||||
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
|
||||
) THEN
|
||||
NEW.updated_at := current_timestamp;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
|
@ -1,2 +0,0 @@
|
|||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE people;
|
|
@ -1,13 +0,0 @@
|
|||
create table people (
|
||||
ap_id text primary key,
|
||||
name text not null,
|
||||
instance text,
|
||||
mail text,
|
||||
pw_hash text,
|
||||
inbox text not null,
|
||||
public_key text not null,
|
||||
private_key text,
|
||||
last_refreshed_at timestamp not null,
|
||||
local boolean not null,
|
||||
followers text[] not null
|
||||
)
|
|
@ -1 +0,0 @@
|
|||
-- This file should undo anything in `up.sql`
|
|
@ -1 +0,0 @@
|
|||
-- Your SQL goes here
|
|
@ -1,14 +0,0 @@
|
|||
// Routes
|
||||
// User info: /:user
|
||||
// Inbox: /:user/inbox
|
||||
// Webfinger: /.well-known/webfinger
|
||||
|
||||
use axum::Router;
|
||||
|
||||
pub fn register(router: Router) -> Router {
|
||||
router
|
||||
}
|
||||
|
||||
fn get_user() -> String {
|
||||
"Foo".into()
|
||||
}
|
370
src/apis/key.rs
370
src/apis/key.rs
|
@ -1,370 +0,0 @@
|
|||
// admin/meta
|
||||
// admin/abuse-user-reports
|
||||
// admin/accounts/create
|
||||
// admin/accounts/delete
|
||||
// admin/accounts/find-by-email
|
||||
// admin/ad/create
|
||||
// admin/ad/delete
|
||||
// admin/ad/list
|
||||
// admin/ad/update
|
||||
// admin/announcements/create
|
||||
// admin/announcements/delete
|
||||
// admin/announcements/list
|
||||
// admin/announcements/update
|
||||
// admin/avatar-decorations/create
|
||||
// admin/avatar-decorations/delete
|
||||
// admin/avatar-decorations/list
|
||||
// admin/avatar-decorations/update
|
||||
// admin/delete-all-files-of-a-user
|
||||
// admin/unset-user-avatar
|
||||
// admin/unset-user-banner
|
||||
// admin/drive/clean-remote-files
|
||||
// admin/drive/cleanup
|
||||
// admin/drive/files
|
||||
// admin/drive/show-file
|
||||
// admin/emoji/add-aliases-bulk
|
||||
// admin/emoji/add
|
||||
// admin/emoji/copy
|
||||
// admin/emoji/delete-bulk
|
||||
// admin/emoji/delete
|
||||
// admin/emoji/import-zip
|
||||
// admin/emoji/list-remote
|
||||
// admin/emoji/list
|
||||
// admin/emoji/remove-aliases-bulk
|
||||
// admin/emoji/set-aliases-bulk
|
||||
// admin/emoji/set-category-bulk
|
||||
// admin/emoji/set-license-bulk
|
||||
// admin/emoji/update
|
||||
// admin/federation/delete-all-files
|
||||
// admin/federation/refresh-remote-instance-metadata
|
||||
// admin/federation/remove-all-following
|
||||
// admin/federation/update-instance
|
||||
// admin/get-index-stats
|
||||
// admin/get-table-stats
|
||||
// admin/get-user-ips
|
||||
// admin/invite/create
|
||||
// admin/invite/list
|
||||
// admin/promo/create
|
||||
// admin/queue/clear
|
||||
// admin/queue/deliver-delayed
|
||||
// admin/queue/inbox-delayed
|
||||
// admin/queue/promote
|
||||
// admin/queue/stats
|
||||
// admin/relays/add
|
||||
// admin/relays/list
|
||||
// admin/relays/remove
|
||||
// admin/reset-password
|
||||
// admin/resolve-abuse-user-report
|
||||
// admin/send-email
|
||||
// admin/server-info
|
||||
// admin/show-moderation-logs
|
||||
// admin/show-user
|
||||
// admin/show-users
|
||||
// admin/nsfw-user
|
||||
// admin/unnsfw-user
|
||||
// admin/silence-user
|
||||
// admin/unsilence-user
|
||||
// admin/suspend-user
|
||||
// admin/approve-user
|
||||
// admin/unsuspend-user
|
||||
// admin/update-meta
|
||||
// admin/delete-account
|
||||
// admin/update-user-note
|
||||
// admin/roles/create
|
||||
// admin/roles/delete
|
||||
// admin/roles/list
|
||||
// admin/roles/show
|
||||
// admin/roles/update
|
||||
// admin/roles/assign
|
||||
// admin/roles/unassign
|
||||
// admin/roles/update-default-policies
|
||||
// admin/roles/users
|
||||
// announcements
|
||||
// antennas/create
|
||||
// antennas/delete
|
||||
// antennas/list
|
||||
// antennas/notes
|
||||
// antennas/show
|
||||
// antennas/update
|
||||
// ap/get
|
||||
// ap/show
|
||||
// app/create
|
||||
// app/show
|
||||
// auth/accept
|
||||
// auth/session/generate
|
||||
// auth/session/show
|
||||
// auth/session/userkey
|
||||
// blocking/create
|
||||
// blocking/delete
|
||||
// blocking/list
|
||||
// channels/create
|
||||
// channels/featured
|
||||
// channels/follow
|
||||
// channels/followed
|
||||
// channels/owned
|
||||
// channels/show
|
||||
// channels/timeline
|
||||
// channels/unfollow
|
||||
// channels/update
|
||||
// channels/favorite
|
||||
// channels/unfavorite
|
||||
// channels/my-favorites
|
||||
// channels/search
|
||||
// charts/active-users
|
||||
// charts/ap-request
|
||||
// charts/drive
|
||||
// charts/federation
|
||||
// charts/instance
|
||||
// charts/notes
|
||||
// charts/user/drive
|
||||
// charts/user/following
|
||||
// charts/user/notes
|
||||
// charts/user/pv
|
||||
// charts/user/reactions
|
||||
// charts/users
|
||||
// clips/add-note
|
||||
// clips/remove-note
|
||||
// clips/create
|
||||
// clips/delete
|
||||
// clips/list
|
||||
// clips/notes
|
||||
// clips/show
|
||||
// clips/update
|
||||
// clips/favorite
|
||||
// clips/unfavorite
|
||||
// clips/my-favorites
|
||||
// drive
|
||||
// drive/files
|
||||
// drive/files/attached-notes
|
||||
// drive/files/check-existence
|
||||
// drive/files/create
|
||||
// drive/files/delete
|
||||
// drive/files/find-by-hash
|
||||
// drive/files/find
|
||||
// drive/files/show
|
||||
// drive/files/update
|
||||
// drive/files/upload-from-url
|
||||
// drive/folders
|
||||
// drive/folders/create
|
||||
// drive/folders/delete
|
||||
// drive/folders/find
|
||||
// drive/folders/show
|
||||
// drive/folders/update
|
||||
// drive/stream
|
||||
// email-address/available
|
||||
// endpoint
|
||||
// endpoints
|
||||
// export-custom-emojis
|
||||
// federation/followers
|
||||
// federation/following
|
||||
// federation/instances
|
||||
// federation/show-instance
|
||||
// federation/update-remote-user
|
||||
// federation/users
|
||||
// federation/stats
|
||||
// following/create
|
||||
// following/delete
|
||||
// following/update
|
||||
// following/update-all
|
||||
// following/invalidate
|
||||
// following/requests/accept
|
||||
// following/requests/cancel
|
||||
// following/requests/list
|
||||
// following/requests/reject
|
||||
// gallery/featured
|
||||
// gallery/popular
|
||||
// gallery/posts
|
||||
// gallery/posts/create
|
||||
// gallery/posts/delete
|
||||
// gallery/posts/like
|
||||
// gallery/posts/show
|
||||
// gallery/posts/unlike
|
||||
// gallery/posts/update
|
||||
// get-online-users-count
|
||||
// get-avatar-decorations
|
||||
// hashtags/list
|
||||
// hashtags/search
|
||||
// hashtags/show
|
||||
// hashtags/trend
|
||||
// hashtags/users
|
||||
// i
|
||||
// i/2fa/done
|
||||
// i/2fa/key-done
|
||||
// i/2fa/password-less
|
||||
// i/2fa/register-key
|
||||
// i/2fa/register
|
||||
// i/2fa/update-key
|
||||
// i/2fa/remove-key
|
||||
// i/2fa/unregister
|
||||
// i/apps
|
||||
// i/authorized-apps
|
||||
// i/claim-achievement
|
||||
// i/change-password
|
||||
// i/delete-account
|
||||
// i/export-data
|
||||
// i/export-blocking
|
||||
// i/export-following
|
||||
// i/export-mute
|
||||
// i/export-notes
|
||||
// i/export-favorites
|
||||
// i/export-user-lists
|
||||
// i/export-antennas
|
||||
// i/favorites
|
||||
// i/gallery/likes
|
||||
// i/gallery/posts
|
||||
// i/import-blocking
|
||||
// i/import-following
|
||||
// i/import-notes
|
||||
// i/import-muting
|
||||
// i/import-user-lists
|
||||
// i/import-antennas
|
||||
// i/notifications
|
||||
// i/notifications-grouped
|
||||
// i/page-likes
|
||||
// i/pages
|
||||
// i/pin
|
||||
// i/read-all-unread-notes
|
||||
// i/read-announcement
|
||||
// i/regenerate-token
|
||||
// i/registry/get-all
|
||||
// i/registry/get-unsecure
|
||||
// i/registry/get-detail
|
||||
// i/registry/get
|
||||
// i/registry/keys-with-type
|
||||
// i/registry/keys
|
||||
// i/registry/remove
|
||||
// i/registry/scopes-with-domain
|
||||
// i/registry/set
|
||||
// i/revoke-token
|
||||
// i/signin-history
|
||||
// i/unpin
|
||||
// i/update-email
|
||||
// i/update
|
||||
// i/move
|
||||
// i/webhooks/create
|
||||
// i/webhooks/list
|
||||
// i/webhooks/show
|
||||
// i/webhooks/update
|
||||
// i/webhooks/delete
|
||||
// invite/create
|
||||
// invite/delete
|
||||
// invite/list
|
||||
// invite/limit
|
||||
// meta
|
||||
// emojis
|
||||
// emoji
|
||||
// miauth/gen-token
|
||||
// mute/create
|
||||
// mute/delete
|
||||
// mute/list
|
||||
// renote-mute/create
|
||||
// renote-mute/delete
|
||||
// renote-mute/list
|
||||
// my/apps
|
||||
// notes
|
||||
// notes/children
|
||||
// notes/clips
|
||||
// notes/conversation
|
||||
// notes/create
|
||||
// notes/delete
|
||||
// notes/favorites/create
|
||||
// notes/favorites/delete
|
||||
// notes/featured
|
||||
// notes/global-timeline
|
||||
// notes/bubble-timeline
|
||||
// notes/hybrid-timeline
|
||||
// notes/local-timeline
|
||||
// notes/mentions
|
||||
// notes/polls/recommendation
|
||||
// notes/polls/vote
|
||||
// notes/reactions
|
||||
// notes/reactions/create
|
||||
// notes/reactions/delete
|
||||
// notes/like
|
||||
// notes/renotes
|
||||
// notes/replies
|
||||
// notes/search-by-tag
|
||||
// notes/search
|
||||
// notes/show
|
||||
// notes/state
|
||||
// notes/thread-muting/create
|
||||
// notes/thread-muting/delete
|
||||
// notes/timeline
|
||||
// notes/translate
|
||||
// notes/unrenote
|
||||
// notes/user-list-timeline
|
||||
// notes/edit
|
||||
// notes/versions
|
||||
// notifications/create
|
||||
// notifications/mark-all-as-read
|
||||
// notifications/test-notification
|
||||
// page-push
|
||||
// pages/create
|
||||
// pages/delete
|
||||
// pages/featured
|
||||
// pages/like
|
||||
// pages/show
|
||||
// pages/unlike
|
||||
// pages/update
|
||||
// flash/create
|
||||
// flash/delete
|
||||
// flash/featured
|
||||
// flash/like
|
||||
// flash/show
|
||||
// flash/unlike
|
||||
// flash/update
|
||||
// flash/my
|
||||
// flash/my-likes
|
||||
// ping
|
||||
// pinned-users
|
||||
// promo/read
|
||||
// roles/list
|
||||
// roles/show
|
||||
// roles/users
|
||||
// roles/notes
|
||||
// request-reset-password
|
||||
// reset-db
|
||||
// reset-password
|
||||
// server-info
|
||||
// stats
|
||||
// sw/show-registration
|
||||
// sw/update-registration
|
||||
// sw/register
|
||||
// sw/unregister
|
||||
// test
|
||||
// username/available
|
||||
// users
|
||||
// users/clips
|
||||
// users/followers
|
||||
// users/following
|
||||
// users/gallery/posts
|
||||
// users/get-frequently-replied-users
|
||||
// users/featured-notes
|
||||
// users/lists/create
|
||||
// users/lists/delete
|
||||
// users/lists/list
|
||||
// users/lists/pull
|
||||
// users/lists/push
|
||||
// users/lists/show
|
||||
// users/lists/favorite
|
||||
// users/lists/unfavorite
|
||||
// users/lists/update
|
||||
// users/lists/create-from-public
|
||||
// users/lists/update-membership
|
||||
// users/lists/get-memberships
|
||||
// users/notes
|
||||
// users/pages
|
||||
// users/flashs
|
||||
// users/reactions
|
||||
// users/recommendation
|
||||
// users/relation
|
||||
// users/report-abuse
|
||||
// users/search-by-username-and-host
|
||||
// users/search
|
||||
// users/show
|
||||
// users/achievements
|
||||
// users/update-memo
|
||||
// fetch-rss
|
||||
// fetch-external-resources
|
||||
// retention
|
||||
// sponsors
|
|
@ -1,4 +0,0 @@
|
|||
pub mod ap;
|
||||
pub mod key;
|
||||
pub mod oma;
|
||||
pub mod masto;
|
174
src/config.rs
174
src/config.rs
|
@ -1,174 +0,0 @@
|
|||
// Copyright (c) 2023 mStar
|
||||
//
|
||||
// Licensed under the EUPL, Version 1.2
|
||||
//
|
||||
// You may not use this work except in compliance with the Licence.
|
||||
// You should have received a copy of the Licence along with this work. If not, see:
|
||||
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
|
||||
// See the Licence for the specific language governing permissions and limitations under the Licence.
|
||||
//
|
||||
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use clap::Parser;
|
||||
use serde_derive::Deserialize;
|
||||
use std::{fs, path::PathBuf};
|
||||
use sysinfo::System;
|
||||
|
||||
const MEGABYTE: u64 = 1049000;
|
||||
/// Assumed memory consumption per worker
|
||||
/// Rather overshoot this than undershoot
|
||||
const ASSUMED_MEM_PER_WORKER: u64 = 2 * MEGABYTE;
|
||||
const CPUS_RESERVED_FOR_SYSTEM: u32 = 2;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
/// Path to the db for diesel to use
|
||||
pub database_path: String,
|
||||
/// Maximum number of workers to use
|
||||
/// A value of 0 makes stuff single-threaded
|
||||
pub max_workers: u32,
|
||||
/// Minimum number of workers to use
|
||||
pub min_workers: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ConfigRootToml {
|
||||
config: Option<ConfigToml>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ConfigToml {
|
||||
/// Path to the db for diesel to use
|
||||
database_path: Option<String>,
|
||||
/// Maximum number of workers to use
|
||||
/// A value of 0 makes stuff single-threaded
|
||||
max_workers: Option<u32>,
|
||||
/// Minimum number of workers to use
|
||||
min_workers: Option<u32>,
|
||||
}
|
||||
|
||||
/// An ActivityPub enabled social media server
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct CLIArguments {
|
||||
/// Path to the config file
|
||||
#[arg(default_value = "config.toml")]
|
||||
pub config: PathBuf,
|
||||
/// Maximum amount of workers to use.
|
||||
/// If not set, the max is calculated depending on system resources.
|
||||
/// A value of 0 will cause the server to be singlethreaded, potentially reducing the performance and responsiveness by a lot
|
||||
#[arg(long)]
|
||||
pub max_workers: Option<u32>,
|
||||
/// Minimum amount of workers to keep active at all times
|
||||
/// Can potentially increase reaction speed at the cost of resource usage
|
||||
#[arg(long)]
|
||||
pub min_workers: Option<u32>,
|
||||
|
||||
#[arg(long)]
|
||||
pub db_path: Option<String>,
|
||||
}
|
||||
|
||||
pub fn read_from_env() -> Result<Config, Error> {
|
||||
let args = CLIArguments::parse();
|
||||
|
||||
if !args.config.is_file() {
|
||||
bail!("Config path is not a file");
|
||||
};
|
||||
let ext = args.config.extension().ok_or(anyhow!(
|
||||
"Type of config file couldn't be determined. No extension"
|
||||
))?;
|
||||
if ext != "toml" {
|
||||
bail!("Config file is not a toml file");
|
||||
}
|
||||
|
||||
let contents = match fs::read_to_string(&args.config) {
|
||||
Ok(c) => c,
|
||||
Err(err) => bail!("Couldn't read config file. Error: {err}"),
|
||||
};
|
||||
|
||||
let unsanitized: ConfigRootToml = match toml::from_str(&contents) {
|
||||
Ok(d) => d,
|
||||
Err(err) => bail!("Failed to parse config file. Error: {err}"),
|
||||
};
|
||||
let conf = unsanitized.into_config(&args);
|
||||
conf.sanity_check()?;
|
||||
Ok(conf)
|
||||
}
|
||||
|
||||
fn calc_max_workers_from_system() -> u32 {
|
||||
let mut sys = System::new_all();
|
||||
sys.refresh_all();
|
||||
let available_ram = sys.available_memory() - sys.used_memory();
|
||||
let available_cpus = (sys.cpus().len() as u32) - CPUS_RESERVED_FOR_SYSTEM;
|
||||
let max_workers_ram = (available_ram / ASSUMED_MEM_PER_WORKER) as u32;
|
||||
// Assume one worker per available CPU
|
||||
// The lower number of potential workers is what we'll use
|
||||
if available_cpus > max_workers_ram {
|
||||
max_workers_ram
|
||||
} else {
|
||||
available_cpus
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigRootToml {
|
||||
fn into_config(&self, cli: &CLIArguments) -> Config {
|
||||
match &self.config {
|
||||
Some(config) => {
|
||||
let db_path = match &cli.db_path {
|
||||
Some(path) => path.clone(),
|
||||
None => match &config.database_path {
|
||||
Some(path) => path.clone(),
|
||||
None => "config.toml".into(),
|
||||
},
|
||||
};
|
||||
let min_workers = match cli.min_workers {
|
||||
Some(num) => num,
|
||||
None => match config.min_workers {
|
||||
Some(num) => num,
|
||||
None => 1,
|
||||
},
|
||||
};
|
||||
let max_workers = match cli.max_workers {
|
||||
Some(num) => num,
|
||||
None => match config.max_workers {
|
||||
Some(num) => num,
|
||||
None => calc_max_workers_from_system(),
|
||||
},
|
||||
};
|
||||
Config {
|
||||
database_path: db_path,
|
||||
min_workers,
|
||||
max_workers,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let db_path = match &cli.db_path {
|
||||
Some(path) => path.clone(),
|
||||
None => "config.toml".to_string(),
|
||||
};
|
||||
let min_workers = match cli.min_workers {
|
||||
Some(num) => num,
|
||||
None => 1,
|
||||
};
|
||||
let max_workers = match cli.max_workers {
|
||||
Some(num) => num,
|
||||
None => calc_max_workers_from_system(),
|
||||
};
|
||||
Config {
|
||||
database_path: db_path.clone(),
|
||||
min_workers,
|
||||
max_workers,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn sanity_check(&self) -> Result<(), Error> {
|
||||
if self.min_workers > self.max_workers {
|
||||
bail!("Minimum amount of workers ({}) can't be greater than maximum amount of workers ({})", self.min_workers, self.max_workers)
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
20
src/error.rs
20
src/error.rs
|
@ -1,20 +0,0 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
|
||||
/// Necessary because of this issue: https://github.com/actix/actix-web/issues/1711
|
||||
#[derive(Debug)]
|
||||
pub struct Error(pub(crate) anyhow::Error);
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Error
|
||||
where
|
||||
T: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(t: T) -> Self {
|
||||
Error(t.into())
|
||||
}
|
||||
}
|
27
src/main.rs
27
src/main.rs
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) 2023 mStar
|
||||
//
|
||||
// Licensed under the EUPL, Version 1.2
|
||||
//
|
||||
// You may not use this work except in compliance with the Licence.
|
||||
// You should have received a copy of the Licence along with this work. If not, see:
|
||||
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
|
||||
// See the Licence for the specific language governing permissions and limitations under the Licence.
|
||||
//
|
||||
|
||||
use anyhow::Error;
|
||||
|
||||
mod objects;
|
||||
mod apis;
|
||||
mod storage;
|
||||
mod guardian;
|
||||
mod config;
|
||||
mod webui;
|
||||
mod error;
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
let conf = config::read_from_env()?;
|
||||
let _db = storage::establish_connection(&conf.database_path)?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) 2023 mStar
|
||||
//
|
||||
// Licensed under the EUPL, Version 1.2
|
||||
//
|
||||
// You may not use this work except in compliance with the Licence.
|
||||
// You should have received a copy of the Licence along with this work. If not, see:
|
||||
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
|
||||
// See the Licence for the specific language governing permissions and limitations under the Licence.
|
||||
//
|
||||
|
||||
pub mod person;
|
||||
pub mod post;
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright (c) 2023 mStar
|
||||
//
|
||||
// Licensed under the EUPL, Version 1.2
|
||||
//
|
||||
// You may not use this work except in compliance with the Licence.
|
||||
// You should have received a copy of the Licence along with this work. If not, see:
|
||||
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
|
||||
// See the Licence for the specific language governing permissions and limitations under the Licence.
|
||||
//
|
||||
|
||||
use activitypub_federation::{kinds::actor::PersonType, fetch::object_id::ObjectId, protocol::public_key::PublicKey};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::storage::pg_models::PersonPG;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Person {
|
||||
pub kind: PersonType,
|
||||
pub preferred_username: String,
|
||||
pub id: ObjectId<PersonPG>,
|
||||
pub inbox: Url,
|
||||
pub public_key: PublicKey,
|
||||
}
|
||||
|
||||
pub trait IntoPerson {
|
||||
fn into_person(&self) -> Person;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
use activitypub_federation::{kinds::object::NoteType, fetch::object_id::ObjectId};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::storage::pg_person::PersonPG;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct Post {
|
||||
#[serde(rename = "type")]
|
||||
pub kind: NoteType,
|
||||
pub id: ObjectId<>,
|
||||
pub(crate) attributed_to: ObjectId<PersonPG>,
|
||||
#[serde(deserialize_with = "deserialize_one_or_many")]
|
||||
pub(crate) to: Vec<Url>,
|
||||
pub content: String,
|
||||
pub in_reply_to: Option<ObjectId<>>,
|
||||
tag: Vec<Mention>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Mention {
|
||||
pub href: Url,
|
||||
#[serde(rename = "type")]
|
||||
pub kind: MentionType,
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) 2023 mStar
|
||||
//
|
||||
// Licensed under the EUPL, Version 1.2
|
||||
//
|
||||
// You may not use this work except in compliance with the Licence.
|
||||
// You should have received a copy of the Licence along with this work. If not, see:
|
||||
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
|
||||
// See the Licence for the specific language governing permissions and limitations under the Licence.
|
||||
//
|
||||
|
||||
// TODO: Once diesel-async supports sqlite (see https://github.com/weiznich/diesel_async/discussions/95), convert to async
|
||||
pub mod pg_schemas;
|
||||
pub mod pg_person;
|
||||
pub mod pg_post;
|
||||
|
||||
use anyhow::{Error, bail};
|
||||
use diesel::{pg::Pg, r2d2::{Pool, ConnectionManager, self}};
|
||||
use diesel::PgConnection;
|
||||
use diesel_migrations::{EmbeddedMigrations, embed_migrations, MigrationHarness};
|
||||
|
||||
pub const POSTGRES_MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Storage {
|
||||
pub pool: Pool<ConnectionManager<PgConnection>>,
|
||||
}
|
||||
|
||||
/// Try and connect to a database at the given url
|
||||
/// The url can be a path to an sqlite db file or an url to a postgres db
|
||||
pub fn establish_connection(db_url: &str) -> Result<Storage, Error> {
|
||||
let manager = ConnectionManager::<PgConnection>::new(db_url);
|
||||
let pool = match r2d2::Pool::builder().build(manager) {
|
||||
Ok(a) => a,
|
||||
Err(err) => bail!("Error while creating the connection pool. Error {}", err)
|
||||
};
|
||||
match pool.get() {
|
||||
Ok(mut conn) => {run_migrations_postgres(&mut conn)?;}
|
||||
Err(e) => bail!(e)
|
||||
}
|
||||
Ok(Storage{
|
||||
pool
|
||||
})
|
||||
}
|
||||
|
||||
fn run_migrations_postgres(conn: &mut impl MigrationHarness<Pg>) -> Result<(), Error> {
|
||||
match conn.run_pending_migrations(POSTGRES_MIGRATIONS) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => bail!("Migrations failed. Error {}", e)
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
use activitypub_federation::{traits::Object, config::Data, fetch::object_id::ObjectId, protocol::verification::verify_domains_match};
|
||||
use anyhow::{anyhow, Error};
|
||||
use chrono::{Utc, NaiveDateTime, DateTime};
|
||||
use diesel::prelude::*;
|
||||
use url::Url;
|
||||
|
||||
use crate::objects::person::Person;
|
||||
|
||||
use super::{Storage, pg_schemas};
|
||||
|
||||
|
||||
#[derive(Queryable, Selectable, Debug, Clone)]
|
||||
#[diesel(table_name = crate::storage::pg_schemas::people)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct PersonPG {
|
||||
pub ap_id: String,
|
||||
pub name: String,
|
||||
pub instance: Option<String>, // Also url
|
||||
pub mail: Option<String>,
|
||||
pub pw_hash: Option<String>,
|
||||
pub inbox: String, // Is an url but diesel no likey
|
||||
pub public_key: String,
|
||||
pub private_key: Option<String>,
|
||||
pub last_refreshed_at: NaiveDateTime,
|
||||
pub local: bool,
|
||||
pub followers: Vec<Option<String>> // Strings are URLs. This is stupid. I wish I could simply use Vec<Url> instead
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Object for PersonPG {
|
||||
type DataType = Storage;
|
||||
type Kind = Person;
|
||||
type Error = Error;
|
||||
|
||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||
Some(self.last_refreshed_at.and_utc())
|
||||
}
|
||||
|
||||
async fn read_from_id(
|
||||
object_id: Url,
|
||||
data: &Data<Self::DataType>,
|
||||
) -> Result<Option<Self>, Self::Error> {
|
||||
use pg_schemas::people::dsl::*;
|
||||
let pool = data.pool.clone();
|
||||
let mut conn = pool.get()?;
|
||||
let results: Vec<PersonPG> = people
|
||||
.filter(ap_id.eq(object_id.as_str()))
|
||||
.limit(1)
|
||||
.select(PersonPG::as_select())
|
||||
.load(&mut conn)
|
||||
.expect(format!("Error loading person from id {}", object_id).as_str());
|
||||
if results.len() == 1 {
|
||||
Ok(Some(results[0].clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
|
||||
Ok(Person {
|
||||
kind: Default::default(),
|
||||
preferred_username: self.name.clone(),
|
||||
id: ObjectId::parse(&self.ap_id)?,
|
||||
inbox: Url::parse(&self.inbox)?,
|
||||
public_key: serde_json::from_str(&self.public_key).unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn verify(
|
||||
json: &Self::Kind,
|
||||
expected_domain: &Url,
|
||||
_data: &Data<Self::DataType>,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(verify_domains_match(&json.id.inner(), &expected_domain)?)
|
||||
|
||||
}
|
||||
|
||||
async fn from_json(
|
||||
json: Self::Kind,
|
||||
_data: &Data<Self::DataType>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(
|
||||
PersonPG {
|
||||
ap_id: json.id.inner().to_string(),
|
||||
name: json.preferred_username,
|
||||
instance: Some(json.inbox.authority().to_string()),
|
||||
mail: None,
|
||||
pw_hash: None,
|
||||
inbox: json.inbox.to_string(),
|
||||
public_key: serde_json::to_string(&json.public_key).unwrap(),
|
||||
private_key: None,
|
||||
last_refreshed_at: Utc::now().naive_utc(),
|
||||
local: false,
|
||||
followers: vec![]
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
pub struct PostPG {
|
||||
pub ap_id: String,
|
||||
pub text: String,
|
||||
pub creator: String,
|
||||
pub local: bool,
|
||||
pub instance: Option<String>
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
people (ap_id) {
|
||||
ap_id -> Text,
|
||||
name -> Text,
|
||||
instance -> Nullable<Text>,
|
||||
mail -> Nullable<Text>,
|
||||
pw_hash -> Nullable<Text>,
|
||||
inbox -> Text,
|
||||
public_key -> Text,
|
||||
private_key -> Nullable<Text>,
|
||||
last_refreshed_at -> Timestamp,
|
||||
local -> Bool,
|
||||
followers -> Array<Nullable<Text>>,
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (c) 2023 mStar
|
||||
//
|
||||
// Licensed under the EUPL, Version 1.2
|
||||
//
|
||||
// You may not use this work except in compliance with the Licence.
|
||||
// You should have received a copy of the Licence along with this work. If not, see:
|
||||
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
|
||||
// See the Licence for the specific language governing permissions and limitations under the Licence.
|
||||
//
|
||||
|
Loading…
Reference in a new issue