Merge branch 'develop' of https://firefish.dev/firefish/firefish into fix/use-pagination-in-note
This commit is contained in:
commit
4bb97f2a3c
248 changed files with 1540 additions and 739 deletions
86
Cargo.lock
generated
86
Cargo.lock
generated
|
@ -220,12 +220,15 @@ dependencies = [
|
||||||
"parse-display",
|
"parse-display",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rand",
|
"rand",
|
||||||
|
"redis",
|
||||||
"regex",
|
"regex",
|
||||||
|
"rmp-serde",
|
||||||
"schemars",
|
"schemars",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"strum 0.26.2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
|
@ -524,6 +527,16 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "combine"
|
||||||
|
version = "4.6.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-oid"
|
name = "const-oid"
|
||||||
version = "0.9.6"
|
version = "0.9.6"
|
||||||
|
@ -1858,6 +1871,21 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redis"
|
||||||
|
version = "0.25.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6472825949c09872e8f2c50bde59fcefc17748b6be5c90fd67cd8b4daca73bfd"
|
||||||
|
dependencies = [
|
||||||
|
"combine",
|
||||||
|
"itoa",
|
||||||
|
"percent-encoding",
|
||||||
|
"ryu",
|
||||||
|
"sha1_smol",
|
||||||
|
"socket2",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -1985,6 +2013,28 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rmp"
|
||||||
|
version = "0.8.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rmp-serde"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "938a142ab806f18b88a97b0dea523d39e0fd730a064b035726adcfc58a8a5188"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"rmp",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.9.6"
|
version = "0.9.6"
|
||||||
|
@ -2070,6 +2120,12 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
@ -2150,7 +2206,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"strum",
|
"strum 0.25.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -2295,6 +2351,12 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1_smol"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.8"
|
version = "0.10.8"
|
||||||
|
@ -2676,6 +2738,28 @@ version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.26.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||||
|
dependencies = [
|
||||||
|
"strum_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.26.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.4.1",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn 2.0.58",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
|
@ -26,12 +26,15 @@ pretty_assertions = "1.4.0"
|
||||||
proc-macro2 = "1.0.79"
|
proc-macro2 = "1.0.79"
|
||||||
quote = "1.0.36"
|
quote = "1.0.36"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
redis = "0.25.3"
|
||||||
regex = "1.10.4"
|
regex = "1.10.4"
|
||||||
|
rmp-serde = "1.2.0"
|
||||||
schemars = "0.8.16"
|
schemars = "0.8.16"
|
||||||
sea-orm = "0.12.15"
|
sea-orm = "0.12.15"
|
||||||
serde = "1.0.197"
|
serde = "1.0.197"
|
||||||
serde_json = "1.0.115"
|
serde_json = "1.0.115"
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
|
strum = "0.26.2"
|
||||||
syn = "2.0.58"
|
syn = "2.0.58"
|
||||||
thiserror = "1.0.58"
|
thiserror = "1.0.58"
|
||||||
tokio = "1.37.0"
|
tokio = "1.37.0"
|
||||||
|
|
|
@ -42,6 +42,8 @@ cargo --version
|
||||||
|
|
||||||
### PostgreSQL and PGroonga
|
### PostgreSQL and PGroonga
|
||||||
|
|
||||||
|
Firefish requires PostgreSQL v12 or later. We recommend that you install v12.x for the same reason as Node.js.
|
||||||
|
|
||||||
PostgreSQL install instructions can be found at [this page](https://www.postgresql.org/download/).
|
PostgreSQL install instructions can be found at [this page](https://www.postgresql.org/download/).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
|
@ -1,9 +1,36 @@
|
||||||
# Install Firefish
|
# Install Firefish
|
||||||
|
|
||||||
This document shows an example procedure for installing Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation.
|
Firefish depends on the following software.
|
||||||
|
|
||||||
|
## Runtime dependencies
|
||||||
|
|
||||||
|
- At least [NodeJS](https://nodejs.org/en/) v18.17.0 (v20/v21 recommended)
|
||||||
|
- At least [PostgreSQL](https://www.postgresql.org/) v12 (v16 recommended) with [PGroonga](https://pgroonga.github.io/) extension
|
||||||
|
- At least [Redis](https://redis.io/) v7
|
||||||
|
- Web Proxy (one of the following)
|
||||||
|
- Caddy (recommended)
|
||||||
|
- Nginx (recommended)
|
||||||
|
- Apache
|
||||||
|
- [FFmpeg](https://ffmpeg.org/) for video transcoding (**optional**)
|
||||||
|
- Caching server (**optional**, one of the following)
|
||||||
|
- [DragonflyDB](https://www.dragonflydb.io/)
|
||||||
|
- [KeyDB](https://keydb.dev/)
|
||||||
|
- Another [Redis](https://redis.io/) server
|
||||||
|
|
||||||
|
## Build dependencies
|
||||||
|
|
||||||
|
- At least [Rust](https://www.rust-lang.org/) v1.74
|
||||||
|
- C/C++ compiler & build tools
|
||||||
|
- `build-essential` on Debian/Ubuntu Linux
|
||||||
|
- `base-devel` on Arch Linux
|
||||||
|
- [Python 3](https://www.python.org/)
|
||||||
|
|
||||||
|
This document shows an example procedure for installing these dependencies and Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation.
|
||||||
|
|
||||||
If you want to use the pre-built container image, please refer to [`install-container.md`](./install-container.md).
|
If you want to use the pre-built container image, please refer to [`install-container.md`](./install-container.md).
|
||||||
|
|
||||||
|
If you do not prepare your environment as document, be sure to meet the minimum dependencies given at the bottom of the page.
|
||||||
|
|
||||||
Make sure that you can use the `sudo` command before proceeding.
|
Make sure that you can use the `sudo` command before proceeding.
|
||||||
|
|
||||||
## 1. Install dependencies
|
## 1. Install dependencies
|
||||||
|
|
|
@ -69,7 +69,7 @@ renameFile: Преименуване на файла
|
||||||
_widgets:
|
_widgets:
|
||||||
activity: Дейност
|
activity: Дейност
|
||||||
notifications: Известия
|
notifications: Известия
|
||||||
timeline: Инфопоток
|
timeline: Хронология
|
||||||
clock: Часовник
|
clock: Часовник
|
||||||
trends: Актуални
|
trends: Актуални
|
||||||
photos: Снимки
|
photos: Снимки
|
||||||
|
@ -187,7 +187,7 @@ notesAndReplies: Публикации и отговори
|
||||||
noSuchUser: Потребителят не е намерен
|
noSuchUser: Потребителят не е намерен
|
||||||
pinnedPages: Закачени страници
|
pinnedPages: Закачени страници
|
||||||
pinLimitExceeded: Не може да закачаш повече публикации
|
pinLimitExceeded: Не може да закачаш повече публикации
|
||||||
flagShowTimelineReplies: Показване на отговори в инфопотока
|
flagShowTimelineReplies: Показване на отговори в хронологията
|
||||||
followersCount: Брой последователи
|
followersCount: Брой последователи
|
||||||
receivedReactionsCount: Брой получени реакции
|
receivedReactionsCount: Брой получени реакции
|
||||||
federation: Федерация
|
federation: Федерация
|
||||||
|
@ -340,7 +340,7 @@ _deck:
|
||||||
_columns:
|
_columns:
|
||||||
notifications: Известия
|
notifications: Известия
|
||||||
mentions: Споменавания
|
mentions: Споменавания
|
||||||
tl: Инфопоток
|
tl: Хронология
|
||||||
direct: Директни съобщения
|
direct: Директни съобщения
|
||||||
list: Списък
|
list: Списък
|
||||||
antenna: Антена
|
antenna: Антена
|
||||||
|
@ -375,7 +375,7 @@ basicSettings: Основни настройки
|
||||||
otherSettings: Други настройки
|
otherSettings: Други настройки
|
||||||
openInWindow: Отваряне в прозорец
|
openInWindow: Отваряне в прозорец
|
||||||
profile: Профил
|
profile: Профил
|
||||||
timeline: Инфопоток
|
timeline: Хронология
|
||||||
noAccountDescription: Този потребител все още не е написал своята биография.
|
noAccountDescription: Този потребител все още не е написал своята биография.
|
||||||
login: Вход
|
login: Вход
|
||||||
loggingIn: Вписване
|
loggingIn: Вписване
|
||||||
|
@ -558,12 +558,12 @@ _visibility:
|
||||||
specified: Директна
|
specified: Директна
|
||||||
localOnly: Само местни
|
localOnly: Само местни
|
||||||
public: Общодостъпна
|
public: Общодостъпна
|
||||||
publicDescription: Публикацията ще бъде видима във всички публични инфопотоци
|
publicDescription: Публикацията ще бъде видима във всички публични хронологии
|
||||||
home: Скрита
|
home: Скрита
|
||||||
localOnlyDescription: Не е видима за отдалечени потребители
|
localOnlyDescription: Не е видима за отдалечени потребители
|
||||||
specifiedDescription: Видима само за определени потребители
|
specifiedDescription: Видима само за определени потребители
|
||||||
followersDescription: Видима само за последователите ти и споменатите потребители
|
followersDescription: Видима само за последователите ти и споменатите потребители
|
||||||
homeDescription: Публикуване само в началния инфопоток
|
homeDescription: Публикуване само в началната хронология
|
||||||
explore: Разглеждане
|
explore: Разглеждане
|
||||||
theme: Теми
|
theme: Теми
|
||||||
wallpaper: Тапет
|
wallpaper: Тапет
|
||||||
|
@ -594,21 +594,21 @@ _tutorial:
|
||||||
да разберат дали искат да видят вашите публикации или да ви следват.
|
да разберат дали искат да видят вашите публикации или да ви следват.
|
||||||
title: Как се използва Firefish
|
title: Как се използва Firefish
|
||||||
step1_1: Добре дошли!
|
step1_1: Добре дошли!
|
||||||
step5_1: Инфопотоци, инфопотоци навсякъде!
|
step5_1: Хронологии, хронологии навсякъде!
|
||||||
step3_1: Сега е време да последвате няколко хора!
|
step3_1: Сега е време да последвате няколко хора!
|
||||||
step1_2: Нека да ви настроим. Ще бъдете готови за нула време!
|
step1_2: Нека да ви настроим. Ще бъдете готови за нула време!
|
||||||
step5_3: Началният {icon} инфопоток е мястото, където можете да видите публикации
|
step5_3: Началната {icon} хронология е мястото, където можете да видите публикации
|
||||||
от акаунтите, които следвате.
|
от акаунтите, които следвате.
|
||||||
step6_1: И така, какво е това място?
|
step6_1: И така, какво е това място?
|
||||||
step5_7: Глобалният {icon} инфопоток е мястото, където можете да видите публикации
|
step5_7: Глобалната {icon} хронология е мястото, където можете да видите публикации
|
||||||
от всеки друг свързан сървър.
|
от всеки друг свързан сървър.
|
||||||
step4_2: За първата си публикация някои хора обичат да правят публикация {introduction}
|
step4_2: За първата си публикация някои хора обичат да правят публикация {introduction}
|
||||||
или просто „Здравей свят!“
|
или просто „Здравей свят!“
|
||||||
step5_2: Вашият сървър има активирани {timelines} различни инфопотоци.
|
step5_2: Вашият сървър има активирани {timelines} различни хронологии.
|
||||||
step5_4: Местният {icon} инфопоток е мястото, където можете да видите публикации
|
step5_4: Местната {icon} хронология е мястото, където можете да видите публикации
|
||||||
от всички останали на този сървър.
|
от всички останали на този сървър.
|
||||||
step5_5: Социалният {icon} инфопоток е комбинация от Началния и Местния инфопоток.
|
step5_5: Социалната {icon} хронология е комбинация от Началната и Местната хронология.
|
||||||
step5_6: Препоръчаният {icon} инфопоток е мястото, където можете да видите публикации
|
step5_6: Препоръчаната {icon} хронология е мястото, където можете да видите публикации
|
||||||
от сървъри, препоръчани от администраторите.
|
от сървъри, препоръчани от администраторите.
|
||||||
step6_4: Сега отидете, изследвайте и се забавлявайте!
|
step6_4: Сега отидете, изследвайте и се забавлявайте!
|
||||||
step6_3: Всеки сървър работи по различни начини и не всички сървъри работят с Firefish.
|
step6_3: Всеки сървър работи по различни начини и не всички сървъри работят с Firefish.
|
||||||
|
@ -754,7 +754,7 @@ _feeds:
|
||||||
general: Общи
|
general: Общи
|
||||||
metadata: Метаданни
|
metadata: Метаданни
|
||||||
disk: Диск
|
disk: Диск
|
||||||
featured: Представени
|
featured: Препоръчани
|
||||||
yearsOld: на {age} години
|
yearsOld: на {age} години
|
||||||
reload: Опресняване
|
reload: Опресняване
|
||||||
invites: Покани
|
invites: Покани
|
||||||
|
@ -778,8 +778,8 @@ uploadFromUrl: Качване от URL адрес
|
||||||
instanceName: Име на сървъра
|
instanceName: Име на сървъра
|
||||||
instanceDescription: Описание на сървъра
|
instanceDescription: Описание на сървъра
|
||||||
accept: Приемане
|
accept: Приемане
|
||||||
enableLocalTimeline: Включване на местния инфопоток
|
enableLocalTimeline: Включване на местната хронология
|
||||||
enableGlobalTimeline: Включване на глобалния инфопоток
|
enableGlobalTimeline: Включване на глобалната хронология
|
||||||
removeMember: Премахване на член
|
removeMember: Премахване на член
|
||||||
isAdmin: Администратор
|
isAdmin: Администратор
|
||||||
isModerator: Модератор
|
isModerator: Модератор
|
||||||
|
@ -862,8 +862,8 @@ apply: Прилагане
|
||||||
selectAccount: Избор на акаунт
|
selectAccount: Избор на акаунт
|
||||||
muteThread: Заглушаване на нишката
|
muteThread: Заглушаване на нишката
|
||||||
ffVisibility: Видимост на Последвани/Последователи
|
ffVisibility: Видимост на Последвани/Последователи
|
||||||
renoteMute: Заглушаване на подсилванията в инфопотоците
|
renoteMute: Заглуш. на подсилванията в хронолог.
|
||||||
replyMute: Заглушаване на отговорите в инфопотоците
|
replyMute: Заглуш. на отговорите в хронолог.
|
||||||
blockConfirm: Сигурни ли сте, че искате да блокирате този акаунт?
|
blockConfirm: Сигурни ли сте, че искате да блокирате този акаунт?
|
||||||
appearance: Облик
|
appearance: Облик
|
||||||
fontSize: Размер на шрифта
|
fontSize: Размер на шрифта
|
||||||
|
@ -893,7 +893,7 @@ charts: Диаграми
|
||||||
disablePagesScript: Изключване на AiScript в Страниците
|
disablePagesScript: Изключване на AiScript в Страниците
|
||||||
updatedAt: Обновено на
|
updatedAt: Обновено на
|
||||||
privateDescription: Видима само за теб
|
privateDescription: Видима само за теб
|
||||||
enableTimelineStreaming: Автоматично обновяване на инфопотоците
|
enableTimelineStreaming: Автоматично обновяване на хронологиите
|
||||||
toEdit: Редактиране
|
toEdit: Редактиране
|
||||||
showEmojisInReactionNotifications: Показване на емоджита в известията за реакции
|
showEmojisInReactionNotifications: Показване на емоджита в известията за реакции
|
||||||
rememberNoteVisibility: Запомняне на настройките за видимост на публикациите
|
rememberNoteVisibility: Запомняне на настройките за видимост на публикациите
|
||||||
|
@ -932,3 +932,11 @@ clientSettings: Настройки за устройството
|
||||||
behavior: Поведение
|
behavior: Поведение
|
||||||
detectPostLanguage: Автоматично откриване на езика и показване на бутон за превеждане
|
detectPostLanguage: Автоматично откриване на езика и показване на бутон за превеждане
|
||||||
за публикации на чужди езици
|
за публикации на чужди езици
|
||||||
|
replyUnmute: Отмяна на заглушаването на отговорите
|
||||||
|
searchWords: Думи за търсене / ID или URL за поглеждане
|
||||||
|
reloadConfirm: Искате ли да опресните хронологията?
|
||||||
|
enableRecommendedTimeline: Включване на препоръчаната хронология
|
||||||
|
showGapBetweenNotesInTimeline: Показване на празнина между публикациите в хронологията
|
||||||
|
lookup: Поглеждане
|
||||||
|
media: Мултимедия
|
||||||
|
welcomeBackWithName: Добре дошли отново, {name}
|
||||||
|
|
|
@ -1227,6 +1227,8 @@ publishTimelinesDescription: "If enabled, the Local and Global timelines will be
|
||||||
on {url} even when signed out."
|
on {url} even when signed out."
|
||||||
noAltTextWarning: "Some attached file(s) have no description. Did you forget to write?"
|
noAltTextWarning: "Some attached file(s) have no description. Did you forget to write?"
|
||||||
showNoAltTextWarning: "Show a warning if you attempt to post files without a description"
|
showNoAltTextWarning: "Show a warning if you attempt to post files without a description"
|
||||||
|
showAddFileDescriptionAtFirstPost: "Automatically open a form to write a description when you
|
||||||
|
attempt to post files without a description"
|
||||||
|
|
||||||
_emojiModPerm:
|
_emojiModPerm:
|
||||||
unauthorized: "None"
|
unauthorized: "None"
|
||||||
|
|
|
@ -2054,6 +2054,7 @@ searchRangeDescription: "如果您要过滤时间段,请按以下格式输入
|
||||||
messagingUnencryptedInfo: "Firefish 上的聊天没有经过端到端加密,请不要在聊天中分享您的敏感信息。"
|
messagingUnencryptedInfo: "Firefish 上的聊天没有经过端到端加密,请不要在聊天中分享您的敏感信息。"
|
||||||
noAltTextWarning: 有些附件没有描述。您是否忘记写描述了?
|
noAltTextWarning: 有些附件没有描述。您是否忘记写描述了?
|
||||||
showNoAltTextWarning: 当您尝试发布没有描述的帖子附件时显示警告
|
showNoAltTextWarning: 当您尝试发布没有描述的帖子附件时显示警告
|
||||||
|
showAddFileDescriptionAtFirstPost: 当您首次尝试发布没有描述的帖子附件时自动弹出添加描述页面
|
||||||
autocorrectNoteLanguage: 当帖子语言不符合自动检测的结果的时候显示警告
|
autocorrectNoteLanguage: 当帖子语言不符合自动检测的结果的时候显示警告
|
||||||
incorrectLanguageWarning: "看上去您帖子使用的语言是{detected},但您选择的语言是{current}。\n要改为以{detected}发帖吗?"
|
incorrectLanguageWarning: "看上去您帖子使用的语言是{detected},但您选择的语言是{current}。\n要改为以{detected}发帖吗?"
|
||||||
noteEditHistory: "帖子编辑历史"
|
noteEditHistory: "帖子编辑历史"
|
||||||
|
|
|
@ -30,12 +30,15 @@ jsonschema = { workspace = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
parse-display = { workspace = true }
|
parse-display = { workspace = true }
|
||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
|
redis = { workspace = true }
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
|
rmp-serde = { workspace = true }
|
||||||
schemars = { workspace = true, features = ["chrono"] }
|
schemars = { workspace = true, features = ["chrono"] }
|
||||||
sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] }
|
sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
serde_yaml = { workspace = true }
|
serde_yaml = { workspace = true }
|
||||||
|
strum = { workspace = true, features = ["derive"] }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
|
|
@ -6,6 +6,7 @@ SRC += $(call recursive_wildcard, src, *)
|
||||||
|
|
||||||
.PHONY: regenerate-entities
|
.PHONY: regenerate-entities
|
||||||
regenerate-entities:
|
regenerate-entities:
|
||||||
|
rm --recursive --force src/model/entity
|
||||||
sea-orm-cli generate entity \
|
sea-orm-cli generate entity \
|
||||||
--output-dir='src/model/entity' \
|
--output-dir='src/model/entity' \
|
||||||
--database-url='postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@localhost:25432/$(POSTGRES_DB)' \
|
--database-url='postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@localhost:25432/$(POSTGRES_DB)' \
|
||||||
|
@ -16,8 +17,9 @@ regenerate-entities:
|
||||||
jsname=$$(printf '%s\n' "$${base%.*}" | perl -pe 's/(^|_)./uc($$&)/ge;s/_//g'); \
|
jsname=$$(printf '%s\n' "$${base%.*}" | perl -pe 's/(^|_)./uc($$&)/ge;s/_//g'); \
|
||||||
attribute=$$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "$${jsname}"); \
|
attribute=$$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "$${jsname}"); \
|
||||||
sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/$${attribute}/" "$${file}"; \
|
sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/$${attribute}/" "$${file}"; \
|
||||||
|
sed -i 's/#\[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)\]/#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]/' "$${file}"; \
|
||||||
done
|
done
|
||||||
sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \
|
sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \
|
||||||
src/model/entity/sea_orm_active_enums.rs
|
src/model/entity/sea_orm_active_enums.rs
|
||||||
cargo fmt --all --
|
cargo fmt --all --
|
||||||
|
|
||||||
|
|
91
packages/backend-rs/index.d.ts
vendored
91
packages/backend-rs/index.d.ts
vendored
|
@ -12,7 +12,7 @@ export interface EnvConfig {
|
||||||
withLogTime: boolean
|
withLogTime: boolean
|
||||||
slow: boolean
|
slow: boolean
|
||||||
}
|
}
|
||||||
export function readEnvironmentConfig(): EnvConfig
|
export function loadEnv(): EnvConfig
|
||||||
export interface ServerConfig {
|
export interface ServerConfig {
|
||||||
url: string
|
url: string
|
||||||
port: number
|
port: number
|
||||||
|
@ -29,7 +29,7 @@ export interface ServerConfig {
|
||||||
/** `NapiValue` is not implemented for `u64` */
|
/** `NapiValue` is not implemented for `u64` */
|
||||||
maxFileSize?: number
|
maxFileSize?: number
|
||||||
accessLog?: string
|
accessLog?: string
|
||||||
clusterLimits?: WorkerConfig
|
clusterLimits?: WorkerConfigInternal
|
||||||
cuid?: IdConfig
|
cuid?: IdConfig
|
||||||
outgoingAddress?: string
|
outgoingAddress?: string
|
||||||
deliverJobConcurrency?: number
|
deliverJobConcurrency?: number
|
||||||
|
@ -70,13 +70,17 @@ export interface RedisConfig {
|
||||||
pass?: string
|
pass?: string
|
||||||
tls?: TlsConfig
|
tls?: TlsConfig
|
||||||
db: number
|
db: number
|
||||||
prefix: string
|
prefix?: string
|
||||||
}
|
}
|
||||||
export interface TlsConfig {
|
export interface TlsConfig {
|
||||||
host: string
|
host: string
|
||||||
rejectUnauthorized: boolean
|
rejectUnauthorized: boolean
|
||||||
}
|
}
|
||||||
export interface WorkerConfig {
|
export interface WorkerConfig {
|
||||||
|
web: number
|
||||||
|
queue: number
|
||||||
|
}
|
||||||
|
export interface WorkerConfigInternal {
|
||||||
web?: number
|
web?: number
|
||||||
queue?: number
|
queue?: number
|
||||||
}
|
}
|
||||||
|
@ -121,13 +125,89 @@ export interface ObjectStorageConfig {
|
||||||
setPublicReadOnUpload?: boolean
|
setPublicReadOnUpload?: boolean
|
||||||
s3ForcePathStyle?: boolean
|
s3ForcePathStyle?: boolean
|
||||||
}
|
}
|
||||||
export function readServerConfig(): ServerConfig
|
export interface Config {
|
||||||
|
url: string
|
||||||
|
port: number
|
||||||
|
bind?: string
|
||||||
|
disableHsts?: boolean
|
||||||
|
db: DbConfig
|
||||||
|
redis: RedisConfig
|
||||||
|
cacheServer?: RedisConfig
|
||||||
|
proxy?: string
|
||||||
|
proxySmtp?: string
|
||||||
|
proxyBypassHosts?: Array<string>
|
||||||
|
allowedPrivateNetworks?: Array<string>
|
||||||
|
maxFileSize?: number
|
||||||
|
accessLog?: string
|
||||||
|
clusterLimits: WorkerConfig
|
||||||
|
cuid?: IdConfig
|
||||||
|
outgoingAddress?: string
|
||||||
|
deliverJobConcurrency?: number
|
||||||
|
inboxJobConcurrency?: number
|
||||||
|
deliverJobPerSec?: number
|
||||||
|
inboxJobPerSec?: number
|
||||||
|
deliverJobMaxAttempts?: number
|
||||||
|
inboxJobMaxAttempts?: number
|
||||||
|
logLevel?: Array<string>
|
||||||
|
syslog?: SysLogConfig
|
||||||
|
proxyRemoteFiles?: boolean
|
||||||
|
mediaProxy?: string
|
||||||
|
summalyProxyUrl?: string
|
||||||
|
reservedUsernames?: Array<string>
|
||||||
|
maxUserSignups?: number
|
||||||
|
isManagedHosting?: boolean
|
||||||
|
maxNoteLength?: number
|
||||||
|
maxCaptionLength?: number
|
||||||
|
deepl?: DeepLConfig
|
||||||
|
libreTranslate?: LibreTranslateConfig
|
||||||
|
email?: EmailConfig
|
||||||
|
objectStorage?: ObjectStorageConfig
|
||||||
|
version: string
|
||||||
|
host: string
|
||||||
|
hostname: string
|
||||||
|
redisKeyPrefix: string
|
||||||
|
scheme: string
|
||||||
|
wsScheme: string
|
||||||
|
apiUrl: string
|
||||||
|
wsUrl: string
|
||||||
|
authUrl: string
|
||||||
|
driveUrl: string
|
||||||
|
userAgent: string
|
||||||
|
clientEntry: Manifest
|
||||||
|
}
|
||||||
|
export interface Manifest {
|
||||||
|
file: string
|
||||||
|
name: string
|
||||||
|
src: string
|
||||||
|
isEntry: boolean
|
||||||
|
isDynamicEntry: boolean
|
||||||
|
imports: Array<string>
|
||||||
|
dynamicImports: Array<string>
|
||||||
|
css: Array<string>
|
||||||
|
assets: Array<string>
|
||||||
|
}
|
||||||
|
export function loadConfig(): Config
|
||||||
export interface Acct {
|
export interface Acct {
|
||||||
username: string
|
username: string
|
||||||
host: string | null
|
host: string | null
|
||||||
}
|
}
|
||||||
export function stringToAcct(acct: string): Acct
|
export function stringToAcct(acct: string): Acct
|
||||||
export function acctToString(acct: Acct): string
|
export function acctToString(acct: Acct): string
|
||||||
|
/**
|
||||||
|
* @param host punycoded instance host
|
||||||
|
* @returns whether the given host should be blocked
|
||||||
|
*/
|
||||||
|
export function isBlockedServer(host: string): Promise<boolean>
|
||||||
|
/**
|
||||||
|
* @param host punycoded instance host
|
||||||
|
* @returns whether the given host should be limited
|
||||||
|
*/
|
||||||
|
export function isSilencedServer(host: string): Promise<boolean>
|
||||||
|
/**
|
||||||
|
* @param host punycoded instance host
|
||||||
|
* @returns whether the given host is allowlisted (this is always true if private mode is disabled)
|
||||||
|
*/
|
||||||
|
export function isAllowedServer(host: string): Promise<boolean>
|
||||||
/** TODO: handle name collisions better */
|
/** TODO: handle name collisions better */
|
||||||
export interface NoteLikeForCheckWordMute {
|
export interface NoteLikeForCheckWordMute {
|
||||||
fileIds: Array<string>
|
fileIds: Array<string>
|
||||||
|
@ -492,7 +572,6 @@ export interface Meta {
|
||||||
recaptchaSecretKey: string | null
|
recaptchaSecretKey: string | null
|
||||||
localDriveCapacityMb: number
|
localDriveCapacityMb: number
|
||||||
remoteDriveCapacityMb: number
|
remoteDriveCapacityMb: number
|
||||||
antennaLimit: number
|
|
||||||
summalyProxy: string | null
|
summalyProxy: string | null
|
||||||
enableEmail: boolean
|
enableEmail: boolean
|
||||||
email: string | null
|
email: string | null
|
||||||
|
@ -555,6 +634,7 @@ export interface Meta {
|
||||||
donationLink: string | null
|
donationLink: string | null
|
||||||
moreUrls: Json
|
moreUrls: Json
|
||||||
markLocalFilesNsfwByDefault: boolean
|
markLocalFilesNsfwByDefault: boolean
|
||||||
|
antennaLimit: number
|
||||||
}
|
}
|
||||||
export interface Migrations {
|
export interface Migrations {
|
||||||
id: number
|
id: number
|
||||||
|
@ -1039,6 +1119,7 @@ export interface Webhook {
|
||||||
latestSentAt: Date | null
|
latestSentAt: Date | null
|
||||||
latestStatus: number | null
|
latestStatus: number | null
|
||||||
}
|
}
|
||||||
|
export function addNoteToAntenna(antennaId: string, note: Note): void
|
||||||
/** Initializes Cuid2 generator. Must be called before any [create_id]. */
|
/** Initializes Cuid2 generator. Must be called before any [create_id]. */
|
||||||
export function initIdGenerator(length: number, fingerprint: string): void
|
export function initIdGenerator(length: number, fingerprint: string): void
|
||||||
export function getTimestamp(id: string): number
|
export function getTimestamp(id: string): number
|
||||||
|
|
|
@ -310,12 +310,15 @@ if (!nativeBinding) {
|
||||||
throw new Error(`Failed to load native binding`)
|
throw new Error(`Failed to load native binding`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { readEnvironmentConfig, readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
|
const { loadEnv, loadConfig, stringToAcct, acctToString, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, addNoteToAntenna, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
|
||||||
|
|
||||||
module.exports.readEnvironmentConfig = readEnvironmentConfig
|
module.exports.loadEnv = loadEnv
|
||||||
module.exports.readServerConfig = readServerConfig
|
module.exports.loadConfig = loadConfig
|
||||||
module.exports.stringToAcct = stringToAcct
|
module.exports.stringToAcct = stringToAcct
|
||||||
module.exports.acctToString = acctToString
|
module.exports.acctToString = acctToString
|
||||||
|
module.exports.isBlockedServer = isBlockedServer
|
||||||
|
module.exports.isSilencedServer = isSilencedServer
|
||||||
|
module.exports.isAllowedServer = isAllowedServer
|
||||||
module.exports.checkWordMute = checkWordMute
|
module.exports.checkWordMute = checkWordMute
|
||||||
module.exports.getFullApAccount = getFullApAccount
|
module.exports.getFullApAccount = getFullApAccount
|
||||||
module.exports.isSelfHost = isSelfHost
|
module.exports.isSelfHost = isSelfHost
|
||||||
|
@ -349,6 +352,7 @@ module.exports.RelayStatusEnum = RelayStatusEnum
|
||||||
module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum
|
module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum
|
||||||
module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum
|
module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum
|
||||||
module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum
|
module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum
|
||||||
|
module.exports.addNoteToAntenna = addNoteToAntenna
|
||||||
module.exports.initIdGenerator = initIdGenerator
|
module.exports.initIdGenerator = initIdGenerator
|
||||||
module.exports.getTimestamp = getTimestamp
|
module.exports.getTimestamp = getTimestamp
|
||||||
module.exports.genId = genId
|
module.exports.genId = genId
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct EnvConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::export]
|
#[crate::export]
|
||||||
pub fn read_environment_config() -> EnvConfig {
|
pub fn load_env() -> EnvConfig {
|
||||||
let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
|
let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
|
||||||
let is_testing = node_env == "test";
|
let is_testing = node_env == "test";
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
pub use server::CONFIG;
|
||||||
|
|
||||||
pub mod environment;
|
pub mod environment;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::fs;
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[crate::export(object, use_nullable = false)]
|
#[crate::export(object, use_nullable = false)]
|
||||||
pub struct ServerConfig {
|
struct ServerConfig {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
/// host to listen on
|
/// host to listen on
|
||||||
|
@ -25,7 +25,7 @@ pub struct ServerConfig {
|
||||||
/// `NapiValue` is not implemented for `u64`
|
/// `NapiValue` is not implemented for `u64`
|
||||||
pub max_file_size: Option<i64>,
|
pub max_file_size: Option<i64>,
|
||||||
pub access_log: Option<String>,
|
pub access_log: Option<String>,
|
||||||
pub cluster_limits: Option<WorkerConfig>,
|
pub cluster_limits: Option<WorkerConfigInternal>,
|
||||||
pub cuid: Option<IdConfig>,
|
pub cuid: Option<IdConfig>,
|
||||||
pub outgoing_address: Option<String>,
|
pub outgoing_address: Option<String>,
|
||||||
|
|
||||||
|
@ -82,8 +82,7 @@ pub struct RedisConfig {
|
||||||
pub tls: Option<TlsConfig>,
|
pub tls: Option<TlsConfig>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub db: u32,
|
pub db: u32,
|
||||||
#[serde(default)]
|
pub prefix: Option<String>,
|
||||||
pub prefix: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
|
@ -94,10 +93,16 @@ pub struct TlsConfig {
|
||||||
pub reject_unauthorized: bool,
|
pub reject_unauthorized: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[crate::export(object, use_nullable = false)]
|
||||||
|
pub struct WorkerConfig {
|
||||||
|
pub web: u32,
|
||||||
|
pub queue: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[crate::export(object, use_nullable = false)]
|
#[crate::export(object, use_nullable = false)]
|
||||||
pub struct WorkerConfig {
|
pub struct WorkerConfigInternal {
|
||||||
pub web: Option<u32>,
|
pub web: Option<u32>,
|
||||||
pub queue: Option<u32>,
|
pub queue: Option<u32>,
|
||||||
}
|
}
|
||||||
|
@ -167,17 +172,207 @@ pub struct ObjectStorageConfig {
|
||||||
pub s3_force_path_style: Option<bool>,
|
pub s3_force_path_style: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::export]
|
#[crate::export(object, use_nullable = false)]
|
||||||
pub fn read_server_config() -> ServerConfig {
|
pub struct Config {
|
||||||
|
// ServerConfig (from default.yml)
|
||||||
|
pub url: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub bind: Option<String>,
|
||||||
|
pub disable_hsts: Option<bool>,
|
||||||
|
pub db: DbConfig,
|
||||||
|
pub redis: RedisConfig,
|
||||||
|
pub cache_server: Option<RedisConfig>,
|
||||||
|
pub proxy: Option<String>,
|
||||||
|
pub proxy_smtp: Option<String>,
|
||||||
|
pub proxy_bypass_hosts: Option<Vec<String>>,
|
||||||
|
pub allowed_private_networks: Option<Vec<String>>,
|
||||||
|
pub max_file_size: Option<i64>,
|
||||||
|
pub access_log: Option<String>,
|
||||||
|
pub cluster_limits: WorkerConfig,
|
||||||
|
pub cuid: Option<IdConfig>,
|
||||||
|
pub outgoing_address: Option<String>,
|
||||||
|
pub deliver_job_concurrency: Option<u32>,
|
||||||
|
pub inbox_job_concurrency: Option<u32>,
|
||||||
|
pub deliver_job_per_sec: Option<u32>,
|
||||||
|
pub inbox_job_per_sec: Option<u32>,
|
||||||
|
pub deliver_job_max_attempts: Option<u32>,
|
||||||
|
pub inbox_job_max_attempts: Option<u32>,
|
||||||
|
pub log_level: Option<Vec<String>>,
|
||||||
|
pub syslog: Option<SysLogConfig>,
|
||||||
|
pub proxy_remote_files: Option<bool>,
|
||||||
|
pub media_proxy: Option<String>,
|
||||||
|
pub summaly_proxy_url: Option<String>,
|
||||||
|
pub reserved_usernames: Option<Vec<String>>,
|
||||||
|
pub max_user_signups: Option<u32>,
|
||||||
|
pub is_managed_hosting: Option<bool>,
|
||||||
|
pub max_note_length: Option<u32>,
|
||||||
|
pub max_caption_length: Option<u32>,
|
||||||
|
pub deepl: Option<DeepLConfig>,
|
||||||
|
pub libre_translate: Option<LibreTranslateConfig>,
|
||||||
|
pub email: Option<EmailConfig>,
|
||||||
|
pub object_storage: Option<ObjectStorageConfig>,
|
||||||
|
|
||||||
|
// Mixin
|
||||||
|
pub version: String,
|
||||||
|
pub host: String,
|
||||||
|
pub hostname: String,
|
||||||
|
pub redis_key_prefix: String,
|
||||||
|
pub scheme: String,
|
||||||
|
pub ws_scheme: String,
|
||||||
|
pub api_url: String,
|
||||||
|
pub ws_url: String,
|
||||||
|
pub auth_url: String,
|
||||||
|
pub drive_url: String,
|
||||||
|
pub user_agent: String,
|
||||||
|
pub client_entry: Manifest,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Meta {
|
||||||
|
pub version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
|
struct ManifestJson {
|
||||||
|
#[serde(rename = "src/init.ts")]
|
||||||
|
pub init_ts: Manifest,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[crate::export(object, use_nullable = false)]
|
||||||
|
pub struct Manifest {
|
||||||
|
pub file: String,
|
||||||
|
pub name: String,
|
||||||
|
pub src: String,
|
||||||
|
pub is_entry: bool,
|
||||||
|
pub is_dynamic_entry: bool,
|
||||||
|
pub imports: Vec<String>,
|
||||||
|
pub dynamic_imports: Vec<String>,
|
||||||
|
pub css: Vec<String>,
|
||||||
|
pub assets: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_config_file() -> ServerConfig {
|
||||||
let cwd = env::current_dir().unwrap();
|
let cwd = env::current_dir().unwrap();
|
||||||
let yml = fs::File::open(cwd.join("../../.config/default.yml"))
|
let yml = fs::File::open(cwd.join("../../.config/default.yml"))
|
||||||
.expect("Failed to open '.config/default.yml'");
|
.expect("Failed to open '.config/default.yml'");
|
||||||
let mut data: ServerConfig = serde_yaml::from_reader(yml).expect("Failed to parse yaml");
|
let mut data: ServerConfig =
|
||||||
|
serde_yaml::from_reader(yml).expect("Failed to parse .config/default.yml");
|
||||||
|
|
||||||
data.url = url::Url::parse(&data.url)
|
data.url = url::Url::parse(&data.url)
|
||||||
.expect("Config url is invalid")
|
.expect("Config url is invalid")
|
||||||
.origin()
|
.origin()
|
||||||
.ascii_serialization();
|
.ascii_serialization();
|
||||||
|
|
||||||
|
if data.bind.is_none() {
|
||||||
|
data.bind = std::env::var("BIND").ok()
|
||||||
|
}
|
||||||
|
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static SERVER_CONFIG: Lazy<ServerConfig> = Lazy::new(read_server_config);
|
fn read_meta() -> Meta {
|
||||||
|
let cwd = env::current_dir().unwrap();
|
||||||
|
let meta_json = fs::File::open(cwd.join("../../built/meta.json"))
|
||||||
|
.expect("Failed to open 'built/meta.json'");
|
||||||
|
serde_json::from_reader(meta_json).expect("Failed to parse built/meta.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_manifest() -> Manifest {
|
||||||
|
let cwd = env::current_dir().unwrap();
|
||||||
|
let manifest_json = fs::File::open(cwd.join("../../built/_client_dist_/manifest.json"))
|
||||||
|
.expect("Failed to open 'built/_client_dist_/manifest.json'");
|
||||||
|
let manifest: ManifestJson = serde_json::from_reader(manifest_json)
|
||||||
|
.expect("Failed to parse built/_client_dist_/manifest.json");
|
||||||
|
|
||||||
|
manifest.init_ts
|
||||||
|
}
|
||||||
|
|
||||||
|
#[crate::export]
|
||||||
|
fn load_config() -> Config {
|
||||||
|
let server_config = read_config_file();
|
||||||
|
let version = read_meta().version;
|
||||||
|
let manifest = read_manifest();
|
||||||
|
let url = url::Url::parse(&server_config.url).expect("Config url is invalid");
|
||||||
|
let hostname = url
|
||||||
|
.host_str()
|
||||||
|
.expect("Hostname is missing in the config url")
|
||||||
|
.to_owned();
|
||||||
|
let host = match url.port() {
|
||||||
|
Some(port) => format!("{}:{}", hostname, port),
|
||||||
|
None => hostname.clone(),
|
||||||
|
};
|
||||||
|
let scheme = url.scheme().to_owned();
|
||||||
|
let ws_scheme = scheme.replace("http", "ws");
|
||||||
|
|
||||||
|
let cluster_limits = match server_config.cluster_limits {
|
||||||
|
Some(cl) => WorkerConfig {
|
||||||
|
web: cl.web.unwrap_or(1),
|
||||||
|
queue: cl.queue.unwrap_or(1),
|
||||||
|
},
|
||||||
|
None => WorkerConfig { web: 1, queue: 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
let redis_key_prefix = if let Some(cache_server) = &server_config.cache_server {
|
||||||
|
cache_server.prefix.clone()
|
||||||
|
} else {
|
||||||
|
server_config.redis.prefix.clone()
|
||||||
|
}
|
||||||
|
.unwrap_or(hostname.clone());
|
||||||
|
|
||||||
|
Config {
|
||||||
|
url: server_config.url,
|
||||||
|
port: server_config.port,
|
||||||
|
bind: server_config.bind,
|
||||||
|
disable_hsts: server_config.disable_hsts,
|
||||||
|
db: server_config.db,
|
||||||
|
redis: server_config.redis,
|
||||||
|
cache_server: server_config.cache_server,
|
||||||
|
proxy: server_config.proxy,
|
||||||
|
proxy_smtp: server_config.proxy_smtp,
|
||||||
|
proxy_bypass_hosts: server_config.proxy_bypass_hosts,
|
||||||
|
allowed_private_networks: server_config.allowed_private_networks,
|
||||||
|
max_file_size: server_config.max_file_size,
|
||||||
|
access_log: server_config.access_log,
|
||||||
|
cluster_limits,
|
||||||
|
cuid: server_config.cuid,
|
||||||
|
outgoing_address: server_config.outgoing_address,
|
||||||
|
deliver_job_concurrency: server_config.deliver_job_concurrency,
|
||||||
|
inbox_job_concurrency: server_config.inbox_job_concurrency,
|
||||||
|
deliver_job_per_sec: server_config.deliver_job_per_sec,
|
||||||
|
inbox_job_per_sec: server_config.inbox_job_per_sec,
|
||||||
|
deliver_job_max_attempts: server_config.deliver_job_max_attempts,
|
||||||
|
inbox_job_max_attempts: server_config.inbox_job_max_attempts,
|
||||||
|
log_level: server_config.log_level,
|
||||||
|
syslog: server_config.syslog,
|
||||||
|
proxy_remote_files: server_config.proxy_remote_files,
|
||||||
|
media_proxy: server_config.media_proxy,
|
||||||
|
summaly_proxy_url: server_config.summaly_proxy_url,
|
||||||
|
reserved_usernames: server_config.reserved_usernames,
|
||||||
|
max_user_signups: server_config.max_user_signups,
|
||||||
|
is_managed_hosting: server_config.is_managed_hosting,
|
||||||
|
max_note_length: server_config.max_note_length,
|
||||||
|
max_caption_length: server_config.max_caption_length,
|
||||||
|
deepl: server_config.deepl,
|
||||||
|
libre_translate: server_config.libre_translate,
|
||||||
|
email: server_config.email,
|
||||||
|
object_storage: server_config.object_storage,
|
||||||
|
|
||||||
|
ws_url: format!("{}://{}", ws_scheme, host),
|
||||||
|
api_url: format!("{}://{}/api", scheme, host),
|
||||||
|
auth_url: format!("{}://{}/auth", scheme, host),
|
||||||
|
drive_url: format!("{}://{}/files", scheme, host),
|
||||||
|
user_agent: format!("Firefish/{} ({})", version, url),
|
||||||
|
version,
|
||||||
|
host,
|
||||||
|
hostname,
|
||||||
|
redis_key_prefix,
|
||||||
|
scheme,
|
||||||
|
ws_scheme,
|
||||||
|
client_entry: manifest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static CONFIG: Lazy<Config> = Lazy::new(load_config);
|
||||||
|
|
|
@ -1,34 +1,6 @@
|
||||||
use crate::config::server::SERVER_CONFIG;
|
pub use postgresql::db_conn;
|
||||||
use sea_orm::{Database, DbConn, DbErr};
|
pub use redis::key as redis_key;
|
||||||
|
pub use redis::redis_conn;
|
||||||
|
|
||||||
static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
|
pub mod postgresql;
|
||||||
|
pub mod redis;
|
||||||
async fn init_database() -> Result<&'static DbConn, DbErr> {
|
|
||||||
let database_uri = format!(
|
|
||||||
"postgres://{}:{}@{}:{}/{}",
|
|
||||||
SERVER_CONFIG.db.user,
|
|
||||||
urlencoding::encode(&SERVER_CONFIG.db.pass),
|
|
||||||
SERVER_CONFIG.db.host,
|
|
||||||
SERVER_CONFIG.db.port,
|
|
||||||
SERVER_CONFIG.db.db,
|
|
||||||
);
|
|
||||||
let conn = Database::connect(database_uri).await?;
|
|
||||||
Ok(DB_CONN.get_or_init(move || conn))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn db_conn() -> Result<&'static DbConn, DbErr> {
|
|
||||||
match DB_CONN.get() {
|
|
||||||
Some(conn) => Ok(conn),
|
|
||||||
None => init_database().await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod unit_test {
|
|
||||||
use super::db_conn;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn connect_test() {
|
|
||||||
assert!(db_conn().await.is_ok());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
35
packages/backend-rs/src/database/postgresql.rs
Normal file
35
packages/backend-rs/src/database/postgresql.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use crate::config::CONFIG;
|
||||||
|
use sea_orm::{Database, DbConn, DbErr};
|
||||||
|
|
||||||
|
static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
|
||||||
|
|
||||||
|
async fn init_database() -> Result<&'static DbConn, DbErr> {
|
||||||
|
let database_uri = format!(
|
||||||
|
"postgres://{}:{}@{}:{}/{}",
|
||||||
|
CONFIG.db.user,
|
||||||
|
urlencoding::encode(&CONFIG.db.pass),
|
||||||
|
CONFIG.db.host,
|
||||||
|
CONFIG.db.port,
|
||||||
|
CONFIG.db.db,
|
||||||
|
);
|
||||||
|
let conn = Database::connect(database_uri).await?;
|
||||||
|
Ok(DB_CONN.get_or_init(move || conn))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn db_conn() -> Result<&'static DbConn, DbErr> {
|
||||||
|
match DB_CONN.get() {
|
||||||
|
Some(conn) => Ok(conn),
|
||||||
|
None => init_database().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod unit_test {
|
||||||
|
use super::db_conn;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn connect() {
|
||||||
|
assert!(db_conn().await.is_ok());
|
||||||
|
assert!(db_conn().await.is_ok());
|
||||||
|
}
|
||||||
|
}
|
68
packages/backend-rs/src/database/redis.rs
Normal file
68
packages/backend-rs/src/database/redis.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use crate::config::CONFIG;
|
||||||
|
use redis::{Client, Connection, RedisError};
|
||||||
|
|
||||||
|
static REDIS_CLIENT: once_cell::sync::OnceCell<Client> = once_cell::sync::OnceCell::new();
|
||||||
|
|
||||||
|
fn init_redis() -> Result<Client, RedisError> {
|
||||||
|
let redis_url = {
|
||||||
|
let mut params = vec!["redis://".to_owned()];
|
||||||
|
|
||||||
|
let redis = if let Some(cache_server) = &CONFIG.cache_server {
|
||||||
|
cache_server
|
||||||
|
} else {
|
||||||
|
&CONFIG.redis
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(user) = &redis.user {
|
||||||
|
params.push(user.to_string())
|
||||||
|
}
|
||||||
|
if let Some(pass) = &redis.pass {
|
||||||
|
params.push(format!(":{}@", pass))
|
||||||
|
}
|
||||||
|
params.push(redis.host.to_string());
|
||||||
|
params.push(format!(":{}", redis.port));
|
||||||
|
params.push(format!("/{}", redis.db));
|
||||||
|
|
||||||
|
params.concat()
|
||||||
|
};
|
||||||
|
|
||||||
|
Client::open(redis_url)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redis_conn() -> Result<Connection, RedisError> {
|
||||||
|
match REDIS_CLIENT.get() {
|
||||||
|
Some(client) => Ok(client.get_connection()?),
|
||||||
|
None => init_redis()?.get_connection(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// prefix redis key
|
||||||
|
pub fn key(key: impl ToString) -> String {
|
||||||
|
format!("{}:{}", CONFIG.redis_key_prefix, key.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod unit_test {
|
||||||
|
use super::redis_conn;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use redis::Commands;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn connect() {
|
||||||
|
assert!(redis_conn().is_ok());
|
||||||
|
assert!(redis_conn().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn access() {
|
||||||
|
let mut redis = redis_conn().unwrap();
|
||||||
|
|
||||||
|
let key = "CARGO_UNIT_TEST_KEY";
|
||||||
|
let value = "CARGO_UNIT_TEST_VALUE";
|
||||||
|
|
||||||
|
assert_eq!(redis.set::<&str, &str, String>(key, value).unwrap(), "OK");
|
||||||
|
assert_eq!(redis.get::<&str, String>(key).unwrap(), value);
|
||||||
|
assert_eq!(redis.del::<&str, u32>(key).unwrap(), 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,4 +4,5 @@ pub mod config;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
pub mod service;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
49
packages/backend-rs/src/misc/check_server_block.rs
Normal file
49
packages/backend-rs/src/misc/check_server_block.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use crate::misc::meta::fetch_meta;
|
||||||
|
use sea_orm::DbErr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param host punycoded instance host
|
||||||
|
* @returns whether the given host should be blocked
|
||||||
|
*/
|
||||||
|
#[crate::export]
|
||||||
|
pub async fn is_blocked_server(host: &str) -> Result<bool, DbErr> {
|
||||||
|
Ok(fetch_meta(true)
|
||||||
|
.await?
|
||||||
|
.blocked_hosts
|
||||||
|
.iter()
|
||||||
|
.any(|blocked_host| {
|
||||||
|
host == blocked_host || host.ends_with(format!(".{}", blocked_host).as_str())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param host punycoded instance host
|
||||||
|
* @returns whether the given host should be limited
|
||||||
|
*/
|
||||||
|
#[crate::export]
|
||||||
|
pub async fn is_silenced_server(host: &str) -> Result<bool, DbErr> {
|
||||||
|
Ok(fetch_meta(true)
|
||||||
|
.await?
|
||||||
|
.silenced_hosts
|
||||||
|
.iter()
|
||||||
|
.any(|silenced_host| {
|
||||||
|
host == silenced_host || host.ends_with(format!(".{}", silenced_host).as_str())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param host punycoded instance host
|
||||||
|
* @returns whether the given host is allowlisted (this is always true if private mode is disabled)
|
||||||
|
*/
|
||||||
|
#[crate::export]
|
||||||
|
pub async fn is_allowed_server(host: &str) -> Result<bool, DbErr> {
|
||||||
|
let meta = fetch_meta(true).await?;
|
||||||
|
|
||||||
|
if !meta.private_mode.unwrap_or(false) {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
if let Some(allowed_hosts) = meta.allowed_hosts {
|
||||||
|
return Ok(allowed_hosts.contains(&host.to_string()));
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::server::SERVER_CONFIG;
|
use crate::config::CONFIG;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -14,21 +14,21 @@ pub enum Error {
|
||||||
pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result<String, Error> {
|
pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result<String, Error> {
|
||||||
Ok(match host {
|
Ok(match host {
|
||||||
Some(host) => format!("{}@{}", username, to_puny(host)?),
|
Some(host) => format!("{}@{}", username, to_puny(host)?),
|
||||||
None => format!("{}@{}", username, extract_host(&SERVER_CONFIG.url)?),
|
None => format!("{}@{}", username, extract_host(&CONFIG.url)?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::export]
|
#[crate::export]
|
||||||
pub fn is_self_host(host: Option<&str>) -> Result<bool, Error> {
|
pub fn is_self_host(host: Option<&str>) -> Result<bool, Error> {
|
||||||
Ok(match host {
|
Ok(match host {
|
||||||
Some(host) => extract_host(&SERVER_CONFIG.url)? == to_puny(host)?,
|
Some(host) => extract_host(&CONFIG.url)? == to_puny(host)?,
|
||||||
None => true,
|
None => true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::export]
|
#[crate::export]
|
||||||
pub fn is_same_origin(uri: &str) -> Result<bool, Error> {
|
pub fn is_same_origin(uri: &str) -> Result<bool, Error> {
|
||||||
Ok(url::Url::parse(uri)?.origin().ascii_serialization() == SERVER_CONFIG.url)
|
Ok(url::Url::parse(uri)?.origin().ascii_serialization() == CONFIG.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::export]
|
#[crate::export]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod acct;
|
pub mod acct;
|
||||||
|
pub mod check_server_block;
|
||||||
pub mod check_word_mute;
|
pub mod check_word_mute;
|
||||||
pub mod convert_host;
|
pub mod convert_host;
|
||||||
pub mod emoji;
|
pub mod emoji;
|
||||||
|
@ -10,3 +11,4 @@ pub mod meta;
|
||||||
pub mod nyaify;
|
pub mod nyaify;
|
||||||
pub mod password;
|
pub mod password;
|
||||||
pub mod reaction;
|
pub mod reaction;
|
||||||
|
pub mod redis_cache;
|
||||||
|
|
84
packages/backend-rs/src/misc/redis_cache.rs
Normal file
84
packages/backend-rs/src/misc/redis_cache.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
use crate::database::{redis_conn, redis_key};
|
||||||
|
use redis::{Commands, RedisError};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Redis error: {0}")]
|
||||||
|
RedisError(#[from] RedisError),
|
||||||
|
#[error("Data serialization error: {0}")]
|
||||||
|
SerializeError(#[from] rmp_serde::encode::Error),
|
||||||
|
#[error("Data deserialization error: {0}")]
|
||||||
|
DeserializeError(#[from] rmp_serde::decode::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cache<V: for<'a> Deserialize<'a> + Serialize>(
|
||||||
|
key: &str,
|
||||||
|
value: &V,
|
||||||
|
expire_seconds: u64,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
redis_conn()?.set_ex(
|
||||||
|
redis_key(key),
|
||||||
|
rmp_serde::encode::to_vec(&value)?,
|
||||||
|
expire_seconds,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cache<V: for<'a> Deserialize<'a> + Serialize>(key: &str) -> Result<Option<V>, Error> {
|
||||||
|
let serialized_value: Option<Vec<u8>> = redis_conn()?.get(redis_key(key))?;
|
||||||
|
Ok(match serialized_value {
|
||||||
|
Some(v) => Some(rmp_serde::from_slice::<V>(v.as_ref())?),
|
||||||
|
None => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod unit_test {
|
||||||
|
use super::{get_cache, set_cache};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_get_expire() {
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize, PartialEq, Debug)]
|
||||||
|
struct Data {
|
||||||
|
id: u32,
|
||||||
|
kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let key_1 = "CARGO_TEST_CACHE_KEY_1";
|
||||||
|
let value_1: Vec<i32> = vec![1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
let key_2 = "CARGO_TEST_CACHE_KEY_2";
|
||||||
|
let value_2 = "Hello fedizens".to_string();
|
||||||
|
|
||||||
|
let key_3 = "CARGO_TEST_CACHE_KEY_3";
|
||||||
|
let value_3 = Data {
|
||||||
|
id: 1000000007,
|
||||||
|
kind: "prime number".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
set_cache(key_1, &value_1, 1).unwrap();
|
||||||
|
set_cache(key_2, &value_2, 1).unwrap();
|
||||||
|
set_cache(key_3, &value_3, 1).unwrap();
|
||||||
|
|
||||||
|
let cached_value_1: Vec<i32> = get_cache(key_1).unwrap().unwrap();
|
||||||
|
let cached_value_2: String = get_cache(key_2).unwrap().unwrap();
|
||||||
|
let cached_value_3: Data = get_cache(key_3).unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value_1, cached_value_1);
|
||||||
|
assert_eq!(value_2, cached_value_2);
|
||||||
|
assert_eq!(value_3, cached_value_3);
|
||||||
|
|
||||||
|
// wait for the cache to expire
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1100));
|
||||||
|
|
||||||
|
let expired_value_1: Option<Vec<i32>> = get_cache(key_1).unwrap();
|
||||||
|
let expired_value_2: Option<Vec<i32>> = get_cache(key_2).unwrap();
|
||||||
|
let expired_value_3: Option<Vec<i32>> = get_cache(key_3).unwrap();
|
||||||
|
|
||||||
|
assert!(expired_value_1.is_none());
|
||||||
|
assert!(expired_value_2.is_none());
|
||||||
|
assert!(expired_value_3.is_none());
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "abuse_user_report")]
|
#[sea_orm(table_name = "abuse_user_report")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "access_token")]
|
#[sea_orm(table_name = "access_token")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "ad")]
|
#[sea_orm(table_name = "ad")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "announcement")]
|
#[sea_orm(table_name = "announcement")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "announcement_read")]
|
#[sea_orm(table_name = "announcement_read")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::AntennaSrcEnum;
|
use super::sea_orm_active_enums::AntennaSrcEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "antenna")]
|
#[sea_orm(table_name = "antenna")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
|
|
||||||
#[sea_orm(table_name = "antenna_note")]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key, auto_increment = false)]
|
|
||||||
pub id: String,
|
|
||||||
#[sea_orm(column_name = "noteId")]
|
|
||||||
pub note_id: String,
|
|
||||||
#[sea_orm(column_name = "antennaId")]
|
|
||||||
pub antenna_id: String,
|
|
||||||
pub read: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::antenna::Entity",
|
|
||||||
from = "Column::AntennaId",
|
|
||||||
to = "super::antenna::Column::Id",
|
|
||||||
on_update = "NoAction",
|
|
||||||
on_delete = "Cascade"
|
|
||||||
)]
|
|
||||||
Antenna,
|
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::note::Entity",
|
|
||||||
from = "Column::NoteId",
|
|
||||||
to = "super::note::Column::Id",
|
|
||||||
on_update = "NoAction",
|
|
||||||
on_delete = "Cascade"
|
|
||||||
)]
|
|
||||||
Note,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::antenna::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::Antenna.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::note::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::Note.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "app")]
|
#[sea_orm(table_name = "app")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "attestation_challenge")]
|
#[sea_orm(table_name = "attestation_challenge")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "auth_session")]
|
#[sea_orm(table_name = "auth_session")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "blocking")]
|
#[sea_orm(table_name = "blocking")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "channel")]
|
#[sea_orm(table_name = "channel")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "channel_following")]
|
#[sea_orm(table_name = "channel_following")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "channel_note_pining")]
|
#[sea_orm(table_name = "channel_note_pining")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "clip")]
|
#[sea_orm(table_name = "clip")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "clip_note")]
|
#[sea_orm(table_name = "clip_note")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::DriveFileUsageHintEnum;
|
use super::sea_orm_active_enums::DriveFileUsageHintEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "drive_file")]
|
#[sea_orm(table_name = "drive_file")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "drive_folder")]
|
#[sea_orm(table_name = "drive_folder")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "emoji")]
|
#[sea_orm(table_name = "emoji")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "follow_request")]
|
#[sea_orm(table_name = "follow_request")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "following")]
|
#[sea_orm(table_name = "following")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "gallery_like")]
|
#[sea_orm(table_name = "gallery_like")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "gallery_post")]
|
#[sea_orm(table_name = "gallery_post")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "hashtag")]
|
#[sea_orm(table_name = "hashtag")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "instance")]
|
#[sea_orm(table_name = "instance")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "messaging_message")]
|
#[sea_orm(table_name = "messaging_message")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "meta")]
|
#[sea_orm(table_name = "meta")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "migrations")]
|
#[sea_orm(table_name = "migrations")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "moderation_log")]
|
#[sea_orm(table_name = "moderation_log")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::MutedNoteReasonEnum;
|
use super::sea_orm_active_enums::MutedNoteReasonEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "muted_note")]
|
#[sea_orm(table_name = "muted_note")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "muting")]
|
#[sea_orm(table_name = "muting")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::NoteVisibilityEnum;
|
use super::sea_orm_active_enums::NoteVisibilityEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note")]
|
#[sea_orm(table_name = "note")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_edit")]
|
#[sea_orm(table_name = "note_edit")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_favorite")]
|
#[sea_orm(table_name = "note_favorite")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_file")]
|
#[sea_orm(table_name = "note_file")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_reaction")]
|
#[sea_orm(table_name = "note_reaction")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_thread_muting")]
|
#[sea_orm(table_name = "note_thread_muting")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_unread")]
|
#[sea_orm(table_name = "note_unread")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "note_watching")]
|
#[sea_orm(table_name = "note_watching")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::NotificationTypeEnum;
|
use super::sea_orm_active_enums::NotificationTypeEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "notification")]
|
#[sea_orm(table_name = "notification")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::PageVisibilityEnum;
|
use super::sea_orm_active_enums::PageVisibilityEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "page")]
|
#[sea_orm(table_name = "page")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "page_like")]
|
#[sea_orm(table_name = "page_like")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "password_reset_request")]
|
#[sea_orm(table_name = "password_reset_request")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::PollNotevisibilityEnum;
|
use super::sea_orm_active_enums::PollNotevisibilityEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "poll")]
|
#[sea_orm(table_name = "poll")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "poll_vote")]
|
#[sea_orm(table_name = "poll_vote")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "promo_note")]
|
#[sea_orm(table_name = "promo_note")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "promo_read")]
|
#[sea_orm(table_name = "promo_read")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "registration_ticket")]
|
#[sea_orm(table_name = "registration_ticket")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "registry_item")]
|
#[sea_orm(table_name = "registry_item")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::RelayStatusEnum;
|
use super::sea_orm_active_enums::RelayStatusEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "relay")]
|
#[sea_orm(table_name = "relay")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "renote_muting")]
|
#[sea_orm(table_name = "renote_muting")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "reply_muting")]
|
#[sea_orm(table_name = "reply_muting")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")]
|
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")]
|
||||||
|
@ -20,7 +23,10 @@ pub enum AntennaSrcEnum {
|
||||||
#[sea_orm(string_value = "users")]
|
#[sea_orm(string_value = "users")]
|
||||||
Users,
|
Users,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -34,7 +40,10 @@ pub enum DriveFileUsageHintEnum {
|
||||||
#[sea_orm(string_value = "userBanner")]
|
#[sea_orm(string_value = "userBanner")]
|
||||||
UserBanner,
|
UserBanner,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -52,7 +61,10 @@ pub enum MutedNoteReasonEnum {
|
||||||
#[sea_orm(string_value = "word")]
|
#[sea_orm(string_value = "word")]
|
||||||
Word,
|
Word,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -72,7 +84,10 @@ pub enum NoteVisibilityEnum {
|
||||||
#[sea_orm(string_value = "specified")]
|
#[sea_orm(string_value = "specified")]
|
||||||
Specified,
|
Specified,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -106,7 +121,10 @@ pub enum NotificationTypeEnum {
|
||||||
#[sea_orm(string_value = "reply")]
|
#[sea_orm(string_value = "reply")]
|
||||||
Reply,
|
Reply,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -122,7 +140,10 @@ pub enum PageVisibilityEnum {
|
||||||
#[sea_orm(string_value = "specified")]
|
#[sea_orm(string_value = "specified")]
|
||||||
Specified,
|
Specified,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -140,7 +161,10 @@ pub enum PollNotevisibilityEnum {
|
||||||
#[sea_orm(string_value = "specified")]
|
#[sea_orm(string_value = "specified")]
|
||||||
Specified,
|
Specified,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")]
|
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")]
|
||||||
|
@ -152,7 +176,10 @@ pub enum RelayStatusEnum {
|
||||||
#[sea_orm(string_value = "requesting")]
|
#[sea_orm(string_value = "requesting")]
|
||||||
Requesting,
|
Requesting,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -170,7 +197,10 @@ pub enum UserEmojimodpermEnum {
|
||||||
#[sea_orm(string_value = "unauthorized")]
|
#[sea_orm(string_value = "unauthorized")]
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
@ -186,7 +216,10 @@ pub enum UserProfileFfvisibilityEnum {
|
||||||
#[sea_orm(string_value = "public")]
|
#[sea_orm(string_value = "public")]
|
||||||
Public,
|
Public,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
#[derive(
|
||||||
|
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||||
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "signin")]
|
#[sea_orm(table_name = "signin")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "sw_subscription")]
|
#[sea_orm(table_name = "sw_subscription")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "used_username")]
|
#[sea_orm(table_name = "used_username")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::sea_orm_active_enums::UserEmojimodpermEnum;
|
use super::sea_orm_active_enums::UserEmojimodpermEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user")]
|
#[sea_orm(table_name = "user")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_group")]
|
#[sea_orm(table_name = "user_group")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_group_invitation")]
|
#[sea_orm(table_name = "user_group_invitation")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_group_invite")]
|
#[sea_orm(table_name = "user_group_invite")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_group_joining")]
|
#[sea_orm(table_name = "user_group_joining")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_ip")]
|
#[sea_orm(table_name = "user_ip")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_keypair")]
|
#[sea_orm(table_name = "user_keypair")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_list")]
|
#[sea_orm(table_name = "user_list")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_list_joining")]
|
#[sea_orm(table_name = "user_list_joining")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_note_pining")]
|
#[sea_orm(table_name = "user_note_pining")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_pending")]
|
#[sea_orm(table_name = "user_pending")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -4,7 +4,8 @@ use super::sea_orm_active_enums::UserProfileFfvisibilityEnum;
|
||||||
use super::sea_orm_active_enums::UserProfileMutingnotificationtypesEnum;
|
use super::sea_orm_active_enums::UserProfileMutingnotificationtypesEnum;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_profile")]
|
#[sea_orm(table_name = "user_profile")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_publickey")]
|
#[sea_orm(table_name = "user_publickey")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "user_security_key")]
|
#[sea_orm(table_name = "user_security_key")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[sea_orm(table_name = "webhook")]
|
#[sea_orm(table_name = "webhook")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "napi",
|
feature = "napi",
|
||||||
|
|
23
packages/backend-rs/src/service/add_note_to_antenna.rs
Normal file
23
packages/backend-rs/src/service/add_note_to_antenna.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::database::{redis_conn, redis_key};
|
||||||
|
use crate::model::entity::note;
|
||||||
|
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||||
|
use crate::util::id::get_timestamp;
|
||||||
|
use redis::{streams::StreamMaxlen, Commands};
|
||||||
|
|
||||||
|
type Note = note::Model;
|
||||||
|
|
||||||
|
#[crate::export]
|
||||||
|
pub fn add_note_to_antenna(antenna_id: String, note: &Note) -> Result<(), Error> {
|
||||||
|
redis_conn()?.xadd_maxlen(
|
||||||
|
redis_key(format!("antennaTimeline:{}", antenna_id)),
|
||||||
|
StreamMaxlen::Approx(200),
|
||||||
|
format!("{}-*", get_timestamp(¬e.id)),
|
||||||
|
&[("note", ¬e.id)],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
publish_to_stream(
|
||||||
|
&Stream::Antenna { antenna_id },
|
||||||
|
Some("note"),
|
||||||
|
Some(serde_json::to_string(note)?),
|
||||||
|
)
|
||||||
|
}
|
2
packages/backend-rs/src/service/mod.rs
Normal file
2
packages/backend-rs/src/service/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod add_note_to_antenna;
|
||||||
|
pub mod stream;
|
93
packages/backend-rs/src/service/stream.rs
Normal file
93
packages/backend-rs/src/service/stream.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use crate::config::CONFIG;
|
||||||
|
use crate::database::redis_conn;
|
||||||
|
use redis::{Commands, RedisError};
|
||||||
|
|
||||||
|
#[derive(strum::Display)]
|
||||||
|
pub enum Stream {
|
||||||
|
#[strum(serialize = "internal")]
|
||||||
|
Internal,
|
||||||
|
#[strum(serialize = "broadcast")]
|
||||||
|
Broadcast,
|
||||||
|
#[strum(to_string = "adminStream:{user_id}")]
|
||||||
|
Admin { user_id: String },
|
||||||
|
#[strum(to_string = "user:{user_id}")]
|
||||||
|
User { user_id: String },
|
||||||
|
#[strum(to_string = "channelStream:{channel_id}")]
|
||||||
|
Channel { channel_id: String },
|
||||||
|
#[strum(to_string = "noteStream:{note_id}")]
|
||||||
|
Note { note_id: String },
|
||||||
|
#[strum(serialize = "notesStream")]
|
||||||
|
Notes,
|
||||||
|
#[strum(to_string = "userListStream:{list_id}")]
|
||||||
|
UserList { list_id: String },
|
||||||
|
#[strum(to_string = "mainStream:{user_id}")]
|
||||||
|
Main { user_id: String },
|
||||||
|
#[strum(to_string = "driveStream:{user_id}")]
|
||||||
|
Drive { user_id: String },
|
||||||
|
#[strum(to_string = "antennaStream:{antenna_id}")]
|
||||||
|
Antenna { antenna_id: String },
|
||||||
|
#[strum(to_string = "messagingStream:{sender_user_id}-{receiver_user_id}")]
|
||||||
|
Chat {
|
||||||
|
sender_user_id: String,
|
||||||
|
receiver_user_id: String,
|
||||||
|
},
|
||||||
|
#[strum(to_string = "messagingStream:{group_id}")]
|
||||||
|
GroupChat { group_id: String },
|
||||||
|
#[strum(to_string = "messagingIndexStream:{user_id}")]
|
||||||
|
MessagingIndex { user_id: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Redis error: {0}")]
|
||||||
|
RedisError(#[from] RedisError),
|
||||||
|
#[error("Json (de)serialization error: {0}")]
|
||||||
|
JsonError(#[from] serde_json::Error),
|
||||||
|
#[error("Value error: {0}")]
|
||||||
|
ValueError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn publish_to_stream(
|
||||||
|
stream: &Stream,
|
||||||
|
kind: Option<&str>,
|
||||||
|
value: Option<String>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let message = if let Some(kind) = kind {
|
||||||
|
format!(
|
||||||
|
"{{ \"type\": \"{}\", \"body\": {} }}",
|
||||||
|
kind,
|
||||||
|
value.unwrap_or("null".to_string()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
value.ok_or(Error::ValueError("Invalid streaming message".to_string()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
redis_conn()?.publish(
|
||||||
|
&CONFIG.host,
|
||||||
|
format!(
|
||||||
|
"{{ \"channel\": \"{}\", \"message\": {} }}",
|
||||||
|
stream, message,
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod unit_test {
|
||||||
|
use super::Stream;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn channel_to_string() {
|
||||||
|
assert_eq!(Stream::Internal.to_string(), "internal");
|
||||||
|
assert_eq!(Stream::Broadcast.to_string(), "broadcast");
|
||||||
|
assert_eq!(
|
||||||
|
Stream::Admin {
|
||||||
|
user_id: "9tb42br63g5apjcq".to_string()
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
"adminStream:9tb42br63g5apjcq"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -178,6 +178,7 @@
|
||||||
"ts-loader": "9.5.1",
|
"ts-loader": "9.5.1",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
|
"type-fest": "4.15.0",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.4.5",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.91.0",
|
||||||
"ws": "8.16.0"
|
"ws": "8.16.0"
|
||||||
|
|
|
@ -3,7 +3,7 @@ import chalk from "chalk";
|
||||||
import Xev from "xev";
|
import Xev from "xev";
|
||||||
|
|
||||||
import Logger from "@/services/logger.js";
|
import Logger from "@/services/logger.js";
|
||||||
import { envOption } from "@/config/index.js";
|
import { envOption } from "@/config.js";
|
||||||
import { inspect } from "node:util";
|
import { inspect } from "node:util";
|
||||||
|
|
||||||
// for typeorm
|
// for typeorm
|
||||||
|
|
|
@ -8,9 +8,9 @@ import chalkTemplate from "chalk-template";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
|
||||||
import Logger from "@/services/logger.js";
|
import Logger from "@/services/logger.js";
|
||||||
import loadConfig from "@/config/load.js";
|
import type { Config } from "backend-rs";
|
||||||
import type { Config } from "@/config/types.js";
|
import { fetchMeta } from "backend-rs";
|
||||||
import { envOption } from "@/config/index.js";
|
import { config, envOption } from "@/config.js";
|
||||||
import { showMachineInfo } from "@/misc/show-machine-info.js";
|
import { showMachineInfo } from "@/misc/show-machine-info.js";
|
||||||
import { db, initDb } from "@/db/postgre.js";
|
import { db, initDb } from "@/db/postgre.js";
|
||||||
import { inspect } from "node:util";
|
import { inspect } from "node:util";
|
||||||
|
@ -87,15 +87,12 @@ function greet() {
|
||||||
* Init master process
|
* Init master process
|
||||||
*/
|
*/
|
||||||
export async function masterMain() {
|
export async function masterMain() {
|
||||||
let config!: Config;
|
|
||||||
|
|
||||||
// initialize app
|
// initialize app
|
||||||
try {
|
try {
|
||||||
greet();
|
greet();
|
||||||
showEnvironment();
|
showEnvironment();
|
||||||
await showMachineInfo(bootLogger);
|
await showMachineInfo(bootLogger);
|
||||||
showNodejsVersion();
|
showNodejsVersion();
|
||||||
config = loadConfigBoot();
|
|
||||||
await connectDb();
|
await connectDb();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
bootLogger.error(
|
bootLogger.error(
|
||||||
|
@ -127,6 +124,9 @@ export async function masterMain() {
|
||||||
import("../daemons/queue-stats.js").then((x) => x.default());
|
import("../daemons/queue-stats.js").then((x) => x.default());
|
||||||
import("../daemons/janitor.js").then((x) => x.default());
|
import("../daemons/janitor.js").then((x) => x.default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update meta cache every 5 minitues
|
||||||
|
setInterval(() => fetchMeta(false), 1000 * 60 * 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEnvironment(): void {
|
function showEnvironment(): void {
|
||||||
|
@ -154,28 +154,6 @@ function showNodejsVersion(): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadConfigBoot(): Config {
|
|
||||||
const configLogger = bootLogger.createSubLogger("config");
|
|
||||||
let config;
|
|
||||||
|
|
||||||
try {
|
|
||||||
config = loadConfig();
|
|
||||||
} catch (exception) {
|
|
||||||
if (exception.code === "ENOENT") {
|
|
||||||
configLogger.error("Configuration file not found", null, true);
|
|
||||||
process.exit(1);
|
|
||||||
} else if (e instanceof Error) {
|
|
||||||
configLogger.error(e.message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
configLogger.succ("Loaded");
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function connectDb(): Promise<void> {
|
async function connectDb(): Promise<void> {
|
||||||
const dbLogger = bootLogger.createSubLogger("db");
|
const dbLogger = bootLogger.createSubLogger("db");
|
||||||
|
|
||||||
|
@ -195,23 +173,31 @@ async function connectDb(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function spawnWorkers(
|
async function spawnWorkers(
|
||||||
clusterLimits: Required<Config["clusterLimits"]>,
|
clusterLimits: Config["clusterLimits"],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const modes = ["web", "queue"];
|
|
||||||
const cpus = os.cpus().length;
|
const cpus = os.cpus().length;
|
||||||
for (const mode of modes.filter((mode) => clusterLimits[mode] > cpus)) {
|
|
||||||
|
if (clusterLimits.queue > cpus) {
|
||||||
bootLogger.warn(
|
bootLogger.warn(
|
||||||
`configuration warning: cluster limit for ${mode} exceeds number of cores (${cpus})`,
|
"config: queue cluster limit exceeds the number of cpu cores",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const total = modes.reduce((acc, mode) => acc + clusterLimits[mode], 0);
|
if (clusterLimits.web > cpus) {
|
||||||
|
bootLogger.warn(
|
||||||
|
"config: web cluster limit exceeds the number of cpu cores",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = clusterLimits.queue + clusterLimits.web;
|
||||||
|
|
||||||
|
// workers = ["web", "web", ..., "web", "queue", "queue", ..., "queue"]
|
||||||
const workers = new Array(total);
|
const workers = new Array(total);
|
||||||
workers.fill("web", 0, clusterLimits?.web);
|
workers.fill("web", 0, clusterLimits.web);
|
||||||
workers.fill("queue", clusterLimits?.web);
|
workers.fill("queue", clusterLimits.web);
|
||||||
|
|
||||||
bootLogger.info(
|
bootLogger.info(
|
||||||
`Starting ${clusterLimits?.web} web workers and ${clusterLimits?.queue} queue workers (total ${total})...`,
|
`Starting ${clusterLimits.web} web workers and ${clusterLimits.queue} queue workers (total ${total})...`,
|
||||||
);
|
);
|
||||||
await Promise.all(workers.map((mode) => spawnWorker(mode)));
|
await Promise.all(workers.map((mode) => spawnWorker(mode)));
|
||||||
bootLogger.succ("All workers started");
|
bootLogger.succ("All workers started");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import cluster from "node:cluster";
|
import cluster from "node:cluster";
|
||||||
import config from "@/config/index.js";
|
import { config } from "@/config.js";
|
||||||
import { initDb } from "@/db/postgre.js";
|
import { initDb } from "@/db/postgre.js";
|
||||||
import { initIdGenerator } from "backend-rs";
|
import { initIdGenerator } from "backend-rs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue