Optimizations (#676)
This commit is contained in:
parent
f21c756793
commit
df83fcc5b9
1
.env
1
.env
@ -15,6 +15,7 @@ MEILISEARCH_ADDR=http://localhost:7700
|
||||
MEILISEARCH_KEY=modrinth
|
||||
|
||||
REDIS_URL=redis://localhost
|
||||
REDIS_MAX_CONNECTIONS=10000
|
||||
|
||||
BIND_ADDR=127.0.0.1:8000
|
||||
SELF_ADDR=http://localhost:8000
|
||||
|
||||
4
migrations/20230808043323_threads-index.sql
Normal file
4
migrations/20230808043323_threads-index.sql
Normal file
@ -0,0 +1,4 @@
|
||||
CREATE INDEX threads_report_id
|
||||
ON threads (report_id);
|
||||
CREATE INDEX threads_mod_id
|
||||
ON threads (mod_id);
|
||||
133
sqlx-data.json
133
sqlx-data.json
@ -1381,51 +1381,6 @@
|
||||
},
|
||||
"query": "\n UPDATE users\n SET password = $1\n WHERE (id = $2)\n "
|
||||
},
|
||||
"447350097928db863d47d756354cd52668f52f7156dd7f3673a826f7b9aca2fd": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"name": "version_",
|
||||
"ordinal": 1,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "type_",
|
||||
"ordinal": 2,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "created",
|
||||
"ordinal": 3,
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"name": "major",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv\n WHERE major = $1 AND type = $2\n ORDER BY created DESC\n "
|
||||
},
|
||||
"4514723bdc1eb8a781215075bec51af1cc6fabe88a469338d5a59533eabf80c5": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
@ -2962,50 +2917,6 @@
|
||||
},
|
||||
"query": "\n DELETE FROM dependencies WHERE mod_dependency_id = $1\n "
|
||||
},
|
||||
"78a60cf0febcc6e35b8ffe38f2c021c13ab660c81c4775bbb26004d30242a1a8": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"name": "version_",
|
||||
"ordinal": 1,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "type_",
|
||||
"ordinal": 2,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "created",
|
||||
"ordinal": 3,
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"name": "major",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Bool"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv\n WHERE major = $1\n ORDER BY created DESC\n "
|
||||
},
|
||||
"7916fe4f04067324ae05598ec9dc6f97f18baf9eda30c64f32677158ada87478": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@ -5616,50 +5527,6 @@
|
||||
},
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM team_members WHERE id=$1)"
|
||||
},
|
||||
"e8ad94314ec2972c3102041b1bf06872c8e4c8a55156a17334a0e317fe41b784": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"name": "version_",
|
||||
"ordinal": 1,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "type_",
|
||||
"ordinal": 2,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "created",
|
||||
"ordinal": 3,
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"name": "major",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv\n WHERE type = $1\n ORDER BY created DESC\n "
|
||||
},
|
||||
"e8d4589132b094df1e7a3ca0440344fc8013c0d20b3c71a1142ccbee91fb3c70": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
|
||||
@ -3,7 +3,11 @@ use super::DatabaseError;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use futures::TryStreamExt;
|
||||
use serde::Deserialize;
|
||||
use redis::cmd;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const TAGS_NAMESPACE: &str = "tags";
|
||||
const DEFAULT_EXPIRY: i64 = 1800; // 30 minutes
|
||||
|
||||
pub struct ProjectType {
|
||||
pub id: ProjectTypeId,
|
||||
@ -15,6 +19,7 @@ pub struct SideType {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Loader {
|
||||
pub id: LoaderId,
|
||||
pub loader: String,
|
||||
@ -22,7 +27,7 @@ pub struct Loader {
|
||||
pub supported_project_types: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Debug)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct GameVersion {
|
||||
pub id: GameVersionId,
|
||||
pub version: String,
|
||||
@ -32,6 +37,7 @@ pub struct GameVersion {
|
||||
pub major: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Category {
|
||||
pub id: CategoryId,
|
||||
pub category: String,
|
||||
@ -45,6 +51,7 @@ pub struct ReportType {
|
||||
pub report_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DonationPlatform {
|
||||
pub id: DonationPlatformId,
|
||||
pub short: String,
|
||||
@ -91,10 +98,24 @@ impl Category {
|
||||
Ok(result.map(|r| CategoryId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<Category>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<Category>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:category", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<Category>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT c.id id, c.category category, c.icon icon, c.header category_header, pt.name project_type
|
||||
@ -116,6 +137,14 @@ impl Category {
|
||||
.try_collect::<Vec<Category>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:category", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -138,10 +167,24 @@ impl Loader {
|
||||
Ok(result.map(|r| LoaderId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<Loader>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<Loader>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:loader", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<Loader>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT l.id id, l.loader loader, l.icon icon,
|
||||
@ -169,6 +212,14 @@ impl Loader {
|
||||
.try_collect::<Vec<_>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:loader", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -205,10 +256,24 @@ impl GameVersion {
|
||||
Ok(result.map(|r| GameVersionId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<GameVersion>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<GameVersion>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:game_version", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<GameVersion>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major FROM game_versions gv
|
||||
@ -226,6 +291,14 @@ impl GameVersion {
|
||||
.try_collect::<Vec<GameVersion>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:game_version", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@ -233,75 +306,27 @@ impl GameVersion {
|
||||
version_type_option: Option<&str>,
|
||||
major_option: Option<bool>,
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<GameVersion>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let result;
|
||||
let result = Self::list(exec, redis)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|x| {
|
||||
let mut bool = true;
|
||||
|
||||
if let Some(version_type) = version_type_option {
|
||||
if let Some(major) = major_option {
|
||||
result = sqlx::query!(
|
||||
"
|
||||
SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv
|
||||
WHERE major = $1 AND type = $2
|
||||
ORDER BY created DESC
|
||||
",
|
||||
major,
|
||||
version_type
|
||||
)
|
||||
.fetch_many(exec)
|
||||
.try_filter_map(|e| async { Ok(e.right().map(|c| GameVersion {
|
||||
id: GameVersionId(c.id),
|
||||
version: c.version_,
|
||||
type_: c.type_,
|
||||
created: c.created,
|
||||
major: c.major,
|
||||
})) })
|
||||
.try_collect::<Vec<GameVersion>>()
|
||||
.await?;
|
||||
} else {
|
||||
result = sqlx::query!(
|
||||
"
|
||||
SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv
|
||||
WHERE type = $1
|
||||
ORDER BY created DESC
|
||||
",
|
||||
version_type
|
||||
)
|
||||
.fetch_many(exec)
|
||||
.try_filter_map(|e| async { Ok(e.right().map(|c| GameVersion {
|
||||
id: GameVersionId(c.id),
|
||||
version: c.version_,
|
||||
type_: c.type_,
|
||||
created: c.created,
|
||||
major: c.major,
|
||||
})) })
|
||||
.try_collect::<Vec<GameVersion>>()
|
||||
.await?;
|
||||
}
|
||||
} else if let Some(major) = major_option {
|
||||
result = sqlx::query!(
|
||||
"
|
||||
SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv
|
||||
WHERE major = $1
|
||||
ORDER BY created DESC
|
||||
",
|
||||
major
|
||||
)
|
||||
.fetch_many(exec)
|
||||
.try_filter_map(|e| async { Ok(e.right().map(|c| GameVersion {
|
||||
id: GameVersionId(c.id),
|
||||
version: c.version_,
|
||||
type_: c.type_,
|
||||
created: c.created,
|
||||
major: c.major,
|
||||
})) })
|
||||
.try_collect::<Vec<GameVersion>>()
|
||||
.await?;
|
||||
} else {
|
||||
result = Vec::new();
|
||||
}
|
||||
if let Some(version_type) = version_type_option {
|
||||
bool &= &*x.type_ == version_type;
|
||||
}
|
||||
if let Some(major) = major_option {
|
||||
bool &= x.major == major;
|
||||
}
|
||||
|
||||
bool
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@ -381,10 +406,24 @@ impl DonationPlatform {
|
||||
Ok(result.map(|r| DonationPlatformId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<DonationPlatform>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<DonationPlatform>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:donation_platform", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<DonationPlatform>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT id, short, name FROM donation_platforms
|
||||
@ -401,6 +440,14 @@ impl DonationPlatform {
|
||||
.try_collect::<Vec<DonationPlatform>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:donation_platform", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -423,10 +470,24 @@ impl ReportType {
|
||||
Ok(result.map(|r| ReportTypeId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<String>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<String>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:report_type", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<String>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT name FROM report_types
|
||||
@ -437,6 +498,14 @@ impl ReportType {
|
||||
.try_collect::<Vec<String>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:report_type", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -459,10 +528,24 @@ impl ProjectType {
|
||||
Ok(result.map(|r| ProjectTypeId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<String>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<String>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:project_type", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<String>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT name FROM project_types
|
||||
@ -473,6 +556,14 @@ impl ProjectType {
|
||||
.try_collect::<Vec<String>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:project_type", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -495,10 +586,24 @@ impl SideType {
|
||||
Ok(result.map(|r| SideTypeId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E) -> Result<Vec<String>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &deadpool_redis::Pool,
|
||||
) -> Result<Vec<String>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.get().await?;
|
||||
let res = cmd("GET")
|
||||
.arg(format!("{}:side_type", TAGS_NAMESPACE))
|
||||
.query_async::<_, Option<String>>(&mut redis)
|
||||
.await?
|
||||
.and_then(|x| serde_json::from_str::<Vec<String>>(&x).ok());
|
||||
|
||||
if let Some(res) = res {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT name FROM side_types
|
||||
@ -509,6 +614,14 @@ impl SideType {
|
||||
.try_collect::<Vec<String>>()
|
||||
.await?;
|
||||
|
||||
cmd("SET")
|
||||
.arg(format!("{}:side_type", TAGS_NAMESPACE))
|
||||
.arg(serde_json::to_string(&result)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
.query_async::<_, ()>(&mut redis)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,13 +161,13 @@ pub struct DonationPlatformId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct VersionId(pub i64);
|
||||
#[derive(Copy, Clone, Debug, Type, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, Type, Deserialize, Serialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct GameVersionId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type)]
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct LoaderId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type)]
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct CategoryId(pub i32);
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||
const PROJECTS_NAMESPACE: &str = "projects";
|
||||
const PROJECTS_SLUGS_NAMESPACE: &str = "projects_slugs";
|
||||
const PROJECTS_DEPENDENCIES_NAMESPACE: &str = "projects_dependencies";
|
||||
const DEFAULT_EXPIRY: i64 = 3600; // 60 minutes
|
||||
const DEFAULT_EXPIRY: i64 = 1800; // 30 minutes
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DonationUrl {
|
||||
@ -524,7 +524,8 @@ impl Project {
|
||||
{
|
||||
remaining_strings.retain(|x| {
|
||||
&to_base62(project.inner.id.0 as u64) != x
|
||||
&& project.inner.slug.as_ref() != Some(x)
|
||||
&& project.inner.slug.as_ref().map(|x| x.to_lowercase())
|
||||
!= Some(x.to_lowercase())
|
||||
});
|
||||
found_projects.push(project);
|
||||
continue;
|
||||
|
||||
@ -185,8 +185,10 @@ impl User {
|
||||
|
||||
for user in users {
|
||||
if let Some(user) = user.and_then(|x| serde_json::from_str::<User>(&x).ok()) {
|
||||
remaining_strings
|
||||
.retain(|x| &to_base62(user.id.0 as u64) != x && &user.username != x);
|
||||
remaining_strings.retain(|x| {
|
||||
&to_base62(user.id.0 as u64) != x
|
||||
&& user.username.to_lowercase() != x.to_lowercase()
|
||||
});
|
||||
found_users.push(user);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -716,7 +716,7 @@ impl Version {
|
||||
|
||||
for (key, mut files) in save_files {
|
||||
cmd("SET")
|
||||
.arg(format!("{}:{}", VERSIONS_NAMESPACE, key))
|
||||
.arg(format!("{}:{}", VERSION_FILES_NAMESPACE, key))
|
||||
.arg(serde_json::to_string(&files)?)
|
||||
.arg("EX")
|
||||
.arg(DEFAULT_EXPIRY)
|
||||
|
||||
17
src/main.rs
17
src/main.rs
@ -79,9 +79,17 @@ async fn main() -> std::io::Result<()> {
|
||||
.expect("Database connection failed");
|
||||
|
||||
// Redis connector
|
||||
let redis_cfg = Config::from_url(dotenvy::var("REDIS_URL").expect("Redis URL not set"));
|
||||
let redis_pool = redis_cfg
|
||||
.create_pool(Some(Runtime::Tokio1))
|
||||
let redis_pool = Config::from_url(dotenvy::var("REDIS_URL").expect("Redis URL not set"))
|
||||
.builder()
|
||||
.expect("Error building Redis pool")
|
||||
.max_size(
|
||||
dotenvy::var("DATABASE_MAX_CONNECTIONS")
|
||||
.ok()
|
||||
.and_then(|x| x.parse().ok())
|
||||
.unwrap_or(10000),
|
||||
)
|
||||
.runtime(Runtime::Tokio1)
|
||||
.build()
|
||||
.expect("Redis connection failed");
|
||||
|
||||
let storage_backend = dotenvy::var("STORAGE_BACKEND").unwrap_or_else(|_| "local".to_string());
|
||||
@ -175,6 +183,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
// Reminding moderators to review projects which have been in the queue longer than 40hr
|
||||
let pool_ref = pool.clone();
|
||||
let redis_ref = redis_pool.clone();
|
||||
let webhook_message_sent = Arc::new(Mutex::new(Vec::<(
|
||||
database::models::ProjectId,
|
||||
DateTime<Utc>,
|
||||
@ -182,6 +191,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
scheduler.run(std::time::Duration::from_secs(10 * 60), move || {
|
||||
let pool_ref = pool_ref.clone();
|
||||
let redis_ref = redis_ref.clone();
|
||||
let webhook_message_sent_ref = webhook_message_sent.clone();
|
||||
info!("Checking reviewed projects submitted more than 40hrs ago");
|
||||
|
||||
@ -217,6 +227,7 @@ async fn main() -> std::io::Result<()> {
|
||||
util::webhook::send_discord_webhook(
|
||||
project.into(),
|
||||
&pool_ref,
|
||||
&redis_ref,
|
||||
webhook_url,
|
||||
Some("<@&783155186491195394> This project has been in the queue for over 40 hours!".to_string()),
|
||||
)
|
||||
|
||||
@ -367,8 +367,8 @@ async fn project_create_inner(
|
||||
let mut versions_map = std::collections::HashMap::new();
|
||||
let mut gallery_urls = Vec::new();
|
||||
|
||||
let all_game_versions = models::categories::GameVersion::list(&mut *transaction).await?;
|
||||
let all_loaders = models::categories::Loader::list(&mut *transaction).await?;
|
||||
let all_game_versions = models::categories::GameVersion::list(&mut *transaction, redis).await?;
|
||||
let all_loaders = models::categories::Loader::list(&mut *transaction, redis).await?;
|
||||
|
||||
{
|
||||
// The first multipart field must be named "data" and contain a
|
||||
@ -836,9 +836,15 @@ async fn project_create_inner(
|
||||
|
||||
if status == ProjectStatus::Processing {
|
||||
if let Ok(webhook_url) = dotenvy::var("MODERATION_DISCORD_WEBHOOK") {
|
||||
crate::util::webhook::send_discord_webhook(response.id, pool, webhook_url, None)
|
||||
.await
|
||||
.ok();
|
||||
crate::util::webhook::send_discord_webhook(
|
||||
response.id,
|
||||
pool,
|
||||
redis,
|
||||
webhook_url,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -504,6 +504,7 @@ pub async fn project_edit(
|
||||
crate::util::webhook::send_discord_webhook(
|
||||
project_item.inner.id.into(),
|
||||
&pool,
|
||||
&redis,
|
||||
webhook_url,
|
||||
None,
|
||||
)
|
||||
@ -530,6 +531,7 @@ pub async fn project_edit(
|
||||
crate::util::webhook::send_discord_webhook(
|
||||
project_item.inner.id.into(),
|
||||
&pool,
|
||||
&redis,
|
||||
webhook_url,
|
||||
None,
|
||||
)
|
||||
@ -1251,8 +1253,9 @@ pub async fn projects_edit(
|
||||
let team_members =
|
||||
database::models::TeamMember::get_from_team_full_many(&team_ids, &**pool, &redis).await?;
|
||||
|
||||
let categories = database::models::categories::Category::list(&**pool).await?;
|
||||
let donation_platforms = database::models::categories::DonationPlatform::list(&**pool).await?;
|
||||
let categories = database::models::categories::Category::list(&**pool, &redis).await?;
|
||||
let donation_platforms =
|
||||
database::models::categories::DonationPlatform::list(&**pool, &redis).await?;
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
|
||||
|
||||
@ -30,8 +30,11 @@ pub struct CategoryData {
|
||||
}
|
||||
|
||||
#[get("category")]
|
||||
pub async fn category_list(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let results = Category::list(&**pool)
|
||||
pub async fn category_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results = Category::list(&**pool, &redis)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| CategoryData {
|
||||
@ -53,8 +56,11 @@ pub struct LoaderData {
|
||||
}
|
||||
|
||||
#[get("loader")]
|
||||
pub async fn loader_list(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let mut results = Loader::list(&**pool)
|
||||
pub async fn loader_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let mut results = Loader::list(&**pool, &redis)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| LoaderData {
|
||||
@ -88,11 +94,12 @@ pub struct GameVersionQuery {
|
||||
pub async fn game_version_list(
|
||||
pool: web::Data<PgPool>,
|
||||
query: web::Query<GameVersionQuery>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results: Vec<GameVersionQueryData> = if query.type_.is_some() || query.major.is_some() {
|
||||
GameVersion::list_filter(query.type_.as_deref(), query.major, &**pool).await?
|
||||
GameVersion::list_filter(query.type_.as_deref(), query.major, &**pool, &redis).await?
|
||||
} else {
|
||||
GameVersion::list(&**pool).await?
|
||||
GameVersion::list(&**pool, &redis).await?
|
||||
}
|
||||
.into_iter()
|
||||
.map(|x| GameVersionQueryData {
|
||||
@ -163,8 +170,11 @@ pub struct DonationPlatformQueryData {
|
||||
}
|
||||
|
||||
#[get("donation_platform")]
|
||||
pub async fn donation_platform_list(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let results: Vec<DonationPlatformQueryData> = DonationPlatform::list(&**pool)
|
||||
pub async fn donation_platform_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results: Vec<DonationPlatformQueryData> = DonationPlatform::list(&**pool, &redis)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| DonationPlatformQueryData {
|
||||
@ -176,19 +186,28 @@ pub async fn donation_platform_list(pool: web::Data<PgPool>) -> Result<HttpRespo
|
||||
}
|
||||
|
||||
#[get("report_type")]
|
||||
pub async fn report_type_list(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let results = ReportType::list(&**pool).await?;
|
||||
pub async fn report_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results = ReportType::list(&**pool, &redis).await?;
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
|
||||
#[get("project_type")]
|
||||
pub async fn project_type_list(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let results = ProjectType::list(&**pool).await?;
|
||||
pub async fn project_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results = ProjectType::list(&**pool, &redis).await?;
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
|
||||
#[get("side_type")]
|
||||
pub async fn side_type_list(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let results = SideType::list(&**pool).await?;
|
||||
pub async fn side_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results = SideType::list(&**pool, &redis).await?;
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
|
||||
@ -135,8 +135,8 @@ async fn version_create_inner(
|
||||
let mut initial_version_data = None;
|
||||
let mut version_builder = None;
|
||||
|
||||
let all_game_versions = models::categories::GameVersion::list(&mut *transaction).await?;
|
||||
let all_loaders = models::categories::Loader::list(&mut *transaction).await?;
|
||||
let all_game_versions = models::categories::GameVersion::list(&mut *transaction, redis).await?;
|
||||
let all_loaders = models::categories::Loader::list(&mut *transaction, redis).await?;
|
||||
|
||||
let user = get_user_from_headers(
|
||||
&req,
|
||||
@ -561,7 +561,8 @@ async fn upload_file_to_version_inner(
|
||||
.await?
|
||||
.name;
|
||||
|
||||
let all_game_versions = models::categories::GameVersion::list(&mut *transaction).await?;
|
||||
let all_game_versions =
|
||||
models::categories::GameVersion::list(&mut *transaction, &redis).await?;
|
||||
|
||||
let mut error = None;
|
||||
while let Some(item) = payload.next().await {
|
||||
|
||||
@ -115,8 +115,13 @@ pub async fn version_list(
|
||||
// Attempt to populate versions with "auto featured" versions
|
||||
if response.is_empty() && !versions.is_empty() && filters.featured.unwrap_or(false) {
|
||||
let (loaders, game_versions) = futures::future::try_join(
|
||||
database::models::categories::Loader::list(&**pool),
|
||||
database::models::categories::GameVersion::list_filter(None, Some(true), &**pool),
|
||||
database::models::categories::Loader::list(&**pool, &redis),
|
||||
database::models::categories::GameVersion::list_filter(
|
||||
None,
|
||||
Some(true),
|
||||
&**pool,
|
||||
&redis,
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@ -72,10 +72,11 @@ const PLUGIN_LOADERS: &[&str] = &[
|
||||
pub async fn send_discord_webhook(
|
||||
project_id: ProjectId,
|
||||
pool: &PgPool,
|
||||
redis: &deadpool_redis::Pool,
|
||||
webhook_url: String,
|
||||
message: Option<String>,
|
||||
) -> Result<(), ApiError> {
|
||||
let all_game_versions = GameVersion::list(pool).await?;
|
||||
let all_game_versions = GameVersion::list(pool, redis).await?;
|
||||
|
||||
let row =
|
||||
sqlx::query!(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user