feat: search for links and author type

Signed-off-by: Zomatree <me@zomatree.live>
This commit is contained in:
Zomatree
2026-04-09 03:54:14 +01:00
parent b7ed543156
commit 9c62568132
27 changed files with 615 additions and 368 deletions

View File

@@ -1,15 +1,15 @@
[package]
name = "revolt-searchd"
version = "0.11.5"
version = "0.12.0"
edition = "2024"
license = "AGPL-3.0-or-later"
publish = false
[dependencies]
tokio = { version = "1.50.0", features = ["macros"] }
revolt-database = { version = "0.11.5", path = "../../core/database" }
revolt-config = { version = "0.11.5", path = "../../core/config" }
revolt-search = { version = "0.11.5", path = "../../core/search" }
revolt-database = { version = "0.12.0", path = "../../core/database" }
revolt-config = { version = "0.12.0", path = "../../core/config" }
revolt-search = { version = "0.12.0", path = "../../core/search" }
amqprs = "1.7.0"
async-trait = "0.1.89"
log = "0.4.29"

View File

@@ -1,11 +1,16 @@
use amqprs::{BasicProperties, Deliver, channel::{BasicAckArguments, Channel}, consumer::AsyncConsumer};
use amqprs::{
BasicProperties, Deliver,
channel::{BasicAckArguments, BasicRejectArguments, Channel},
consumer::AsyncConsumer,
};
use async_trait::async_trait;
use revolt_database::{Database, events::rabbit::ChannelDeletePayload};
use revolt_search::ElasticsearchClient;
#[allow(unused)]
pub struct ChannelDeleteConsumer {
client: ElasticsearchClient,
database: Database
database: Database,
}
impl ChannelDeleteConsumer {
@@ -23,13 +28,25 @@ impl AsyncConsumer for ChannelDeleteConsumer {
_basic_properties: BasicProperties,
content: Vec<u8>,
) {
let payload = serde_json::from_slice::<ChannelDeletePayload>(&content).expect("Failed to decode message");
let payload = serde_json::from_slice::<ChannelDeletePayload>(&content)
.expect("Failed to decode message");
log::debug!("Received channel delete {payload:?}");
if self.client.delete_channel(&payload.channel_id).await.is_ok() {
channel.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false)).await.expect("Failed to ack");
if self
.client
.delete_channel(&payload.channel_id)
.await
.is_ok()
{
channel
.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false))
.await
.expect("Failed to ack");
} else {
// todo requeue
channel
.basic_reject(BasicRejectArguments::new(deliver.delivery_tag(), true))
.await
.expect("Failed to reject");
}
}
}
}

View File

@@ -1,11 +1,15 @@
use amqprs::{BasicProperties, Deliver, channel::{BasicAckArguments, Channel}, consumer::AsyncConsumer};
use amqprs::{
BasicProperties, Deliver,
channel::{BasicAckArguments, BasicRejectArguments, Channel},
consumer::AsyncConsumer,
};
use async_trait::async_trait;
use revolt_database::{Database, Message};
use revolt_database::{Database, events::rabbit::MessageCreatePayload};
use revolt_search::ElasticsearchClient;
pub struct MessageConsumer {
client: ElasticsearchClient,
database: Database
database: Database,
}
impl MessageConsumer {
@@ -23,13 +27,25 @@ impl AsyncConsumer for MessageConsumer {
_basic_properties: BasicProperties,
content: Vec<u8>,
) {
let message = serde_json::from_slice::<Message>(&content).expect("Failed to decode message");
log::debug!("Received message {message:?}");
let payload = serde_json::from_slice::<MessageCreatePayload>(&content)
.expect("Failed to decode message");
log::debug!("Received message {payload:?}");
if self.client.index_message(&self.database, message).await.is_ok() {
channel.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false)).await.expect("Failed to ack");
if self
.client
.index_message(&self.database, payload.message, payload.user)
.await
.is_ok()
{
channel
.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false))
.await
.expect("Failed to ack");
} else {
// todo requeue
channel
.basic_reject(BasicRejectArguments::new(deliver.delivery_tag(), true))
.await
.expect("Failed to reject");
}
}
}
}

View File

@@ -1,11 +1,16 @@
use amqprs::{BasicProperties, Deliver, channel::{BasicAckArguments, Channel}, consumer::AsyncConsumer};
use amqprs::{
BasicProperties, Deliver,
channel::{BasicAckArguments, BasicRejectArguments, Channel},
consumer::AsyncConsumer,
};
use async_trait::async_trait;
use revolt_database::{Database, events::rabbit::MessageDeletePayload};
use revolt_search::ElasticsearchClient;
#[allow(unused)]
pub struct MessageDeleteConsumer {
client: ElasticsearchClient,
database: Database
database: Database,
}
impl MessageDeleteConsumer {
@@ -23,13 +28,25 @@ impl AsyncConsumer for MessageDeleteConsumer {
_basic_properties: BasicProperties,
content: Vec<u8>,
) {
let payload = serde_json::from_slice::<MessageDeletePayload>(&content).expect("Failed to decode message");
let payload = serde_json::from_slice::<MessageDeletePayload>(&content)
.expect("Failed to decode message");
log::debug!("Received message delete {payload:?}");
if self.client.delete_message(&payload.message_id).await.is_ok() {
channel.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false)).await.expect("Failed to ack");
if self
.client
.delete_message(&payload.message_id)
.await
.is_ok()
{
channel
.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false))
.await
.expect("Failed to ack");
} else {
// todo requeue
channel
.basic_reject(BasicRejectArguments::new(deliver.delivery_tag(), true))
.await
.expect("Failed to reject");
}
}
}
}

View File

@@ -1,11 +1,15 @@
use amqprs::{BasicProperties, Deliver, channel::{BasicAckArguments, Channel}, consumer::AsyncConsumer};
use amqprs::{
BasicProperties, Deliver,
channel::{BasicAckArguments, BasicRejectArguments, Channel},
consumer::AsyncConsumer,
};
use async_trait::async_trait;
use revolt_database::{Database, Message};
use revolt_database::{Database, events::rabbit::MessageEditPayload};
use revolt_search::ElasticsearchClient;
pub struct MessageEditConsumer {
client: ElasticsearchClient,
database: Database
database: Database,
}
impl MessageEditConsumer {
@@ -23,13 +27,25 @@ impl AsyncConsumer for MessageEditConsumer {
_basic_properties: BasicProperties,
content: Vec<u8>,
) {
let message = serde_json::from_slice::<Message>(&content).expect("Failed to decode message");
log::debug!("Received edit message {message:?}");
let payload = serde_json::from_slice::<MessageEditPayload>(&content)
.expect("Failed to decode message");
log::debug!("Received edit message {payload:?}");
if self.client.edit_message(&self.database, message).await.is_ok() {
channel.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false)).await.expect("Failed to ack");
if self
.client
.edit_message(&self.database, payload.message, payload.user)
.await
.is_ok()
{
channel
.basic_ack(BasicAckArguments::new(deliver.delivery_tag(), false))
.await
.expect("Failed to ack");
} else {
// todo requeue
channel
.basic_reject(BasicRejectArguments::new(deliver.delivery_tag(), true))
.await
.expect("Failed to reject");
}
}
}
}

View File

@@ -12,7 +12,7 @@ pub async fn index_existing_messages(db: Database, client: ElasticsearchClient)
let mut chunk = Vec::new();
while let Some(message) = generator.next().await {
while let Some(message) = generator.next().await.expect("Failed to fetch batch") {
chunk.push(message);
if chunk.len() >= 1000

View File

@@ -1,4 +1,5 @@
use amqprs::{
FieldTable,
channel::{
BasicConsumeArguments, Channel, ExchangeDeclareArguments, QueueBindArguments,
QueueDeclareArguments,
@@ -26,7 +27,10 @@ async fn _main() {
config.elasticsearch.api_key.clone(),
);
if std::env::var("REMAKE_MESSAGES_INDEX").as_deref().is_ok_and(|v| v == "1") {
if std::env::var("REMAKE_MESSAGES_INDEX")
.as_deref()
.is_ok_and(|v| v == "1")
{
if client.delete_indexes().await.is_err() {
log::info!("Index does not existing, skipping.")
};
@@ -87,7 +91,10 @@ async fn _main() {
let mut task = None;
if std::env::var("INDEX_ALL_MESSAGES").as_deref().is_ok_and(|v| v == "1") {
if std::env::var("INDEX_ALL_MESSAGES")
.as_deref()
.is_ok_and(|v| v == "1")
{
task = Some(spawn(index::index_existing_messages(db, client.clone())));
}
@@ -119,8 +126,16 @@ async fn make_queue_and_consume<F: AsyncConsumer + Send + 'static>(
.await
.expect("Failed to declare pushd exchange");
let mut table = FieldTable::new();
table.insert("x-queue-type".try_into().unwrap(), "quorum".into());
_ = channel
.queue_declare(QueueDeclareArguments::new(queue).durable(true).finish())
.queue_declare(
QueueDeclareArguments::new(queue)
.durable(true)
.arguments(table)
.finish(),
)
.await
.unwrap()
.unwrap();