send mime type and size with memes
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
cd1875240d
commit
6322919e6d
|
@ -1,2 +1,4 @@
|
||||||
# 0.2.2
|
# 0.2.2
|
||||||
|
- DATABASE FORMAT CHANGE
|
||||||
- meme cache is now updated after reponse has been sent to reduce latency
|
- meme cache is now updated after reponse has been sent to reduce latency
|
||||||
|
- MIME type and file size is now sent with memes
|
||||||
|
|
|
@ -40,6 +40,7 @@ use serde_json::json;
|
||||||
mod config;
|
mod config;
|
||||||
mod meme;
|
mod meme;
|
||||||
mod responder;
|
mod responder;
|
||||||
|
mod util;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
|
|
|
@ -1,55 +1,66 @@
|
||||||
use crate::Bot;
|
use crate::{util, Bot};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
api::r0::media::create_content,
|
api::r0::media::create_content,
|
||||||
events::{
|
events::{
|
||||||
room::message::{
|
room::{
|
||||||
ImageMessageEventContent,
|
message::{
|
||||||
MessageEventContent,
|
ImageMessageEventContent,
|
||||||
MessageType,
|
MessageEventContent,
|
||||||
VideoMessageEventContent,
|
MessageType,
|
||||||
|
VideoInfo,
|
||||||
|
VideoMessageEventContent,
|
||||||
|
},
|
||||||
|
ImageInfo,
|
||||||
},
|
},
|
||||||
AnyMessageEventContent,
|
AnyMessageEventContent,
|
||||||
},
|
},
|
||||||
identifiers::MxcUri,
|
identifiers::MxcUri,
|
||||||
room::{Joined, Room},
|
room::{Joined, Room},
|
||||||
|
UInt,
|
||||||
};
|
};
|
||||||
|
use mime::Mime;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{io::Cursor, sync::atomic::Ordering};
|
use std::{io::Cursor, sync::atomic::Ordering};
|
||||||
|
|
||||||
|
/// A meme stored in the cache database
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
struct CachedMeme {
|
struct CachedMeme {
|
||||||
|
/// mxc url of the meme
|
||||||
mxc: MxcUri,
|
mxc: MxcUri,
|
||||||
ty: CachedMemeType,
|
/// MIME type of the meme
|
||||||
|
#[serde(with = "util::mime_serialize")]
|
||||||
|
mime: Mime,
|
||||||
|
/// file size of the meme
|
||||||
|
size: UInt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CachedMeme {
|
impl CachedMeme {
|
||||||
fn into_message_type(self, name: String) -> MessageType {
|
fn into_message_type(self, name: String) -> Option<MessageType> {
|
||||||
match self {
|
let Self { mxc, mime, size } = self;
|
||||||
Self {
|
|
||||||
mxc,
|
|
||||||
ty: CachedMemeType::Image,
|
|
||||||
} => MessageType::Image(ImageMessageEventContent::plain(name, mxc, None)),
|
|
||||||
Self {
|
|
||||||
mxc,
|
|
||||||
ty: CachedMemeType::Video,
|
|
||||||
} => MessageType::Video(VideoMessageEventContent::plain(name, mxc, None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
match mime.type_() {
|
||||||
enum CachedMemeType {
|
mime::IMAGE => Some(MessageType::Image(ImageMessageEventContent::plain(
|
||||||
Image,
|
name,
|
||||||
Video,
|
mxc,
|
||||||
}
|
Some(Box::new({
|
||||||
|
let mut info = ImageInfo::new();
|
||||||
impl CachedMemeType {
|
info.mimetype = Some(mime.to_string());
|
||||||
fn from_mime_name(name: &mime::Name) -> Option<Self> {
|
info.size = Some(size);
|
||||||
match *name {
|
info
|
||||||
mime::VIDEO => Some(Self::Video),
|
})),
|
||||||
mime::IMAGE => Some(Self::Image),
|
))),
|
||||||
|
mime::VIDEO => Some(MessageType::Video(VideoMessageEventContent::plain(
|
||||||
|
name,
|
||||||
|
mxc,
|
||||||
|
Some(Box::new({
|
||||||
|
let mut info = VideoInfo::new();
|
||||||
|
info.mimetype = Some(mime.to_string());
|
||||||
|
info.size = Some(size);
|
||||||
|
info
|
||||||
|
})),
|
||||||
|
))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,8 +111,7 @@ pub async fn on_msg(msg: &str, room: Room, bot: &Bot) -> anyhow::Result<()> {
|
||||||
let resp = resp.bytes().await?;
|
let resp = resp.bytes().await?;
|
||||||
|
|
||||||
if let Some(mime) = mime_guess::from_path(&meme.link).first() {
|
if let Some(mime) = mime_guess::from_path(&meme.link).first() {
|
||||||
let ty = CachedMemeType::from_mime_name(&mime.type_())
|
let size = resp.len();
|
||||||
.context("Found meme that is neither video nor image!")?;
|
|
||||||
let create_content::Response { content_uri, .. } = bot
|
let create_content::Response { content_uri, .. } = bot
|
||||||
.client
|
.client
|
||||||
.read()
|
.read()
|
||||||
|
@ -111,7 +121,9 @@ pub async fn on_msg(msg: &str, room: Room, bot: &Bot) -> anyhow::Result<()> {
|
||||||
|
|
||||||
let cached = CachedMeme {
|
let cached = CachedMeme {
|
||||||
mxc: content_uri,
|
mxc: content_uri,
|
||||||
ty,
|
mime,
|
||||||
|
size: UInt::new(size as u64)
|
||||||
|
.context("Meme has file size over allowed limit!")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
bot.memecache
|
bot.memecache
|
||||||
|
@ -146,7 +158,9 @@ pub async fn on_msg(msg: &str, room: Room, bot: &Bot) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_meme(room: &Joined, cached: CachedMeme, meme_name: String) -> anyhow::Result<()> {
|
async fn send_meme(room: &Joined, cached: CachedMeme, meme_name: String) -> anyhow::Result<()> {
|
||||||
let msg_ty = cached.into_message_type(meme_name);
|
let msg_ty = cached
|
||||||
|
.into_message_type(meme_name)
|
||||||
|
.context("Found meme that is neither image nor video!")?;
|
||||||
|
|
||||||
room.send(
|
room.send(
|
||||||
AnyMessageEventContent::RoomMessage(MessageEventContent::new(msg_ty)),
|
AnyMessageEventContent::RoomMessage(MessageEventContent::new(msg_ty)),
|
||||||
|
|
39
src/util.rs
Normal file
39
src/util.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
pub mod mime_serialize {
|
||||||
|
use mime::Mime;
|
||||||
|
use serde::{
|
||||||
|
de::{self, Unexpected, Visitor},
|
||||||
|
Deserializer,
|
||||||
|
Serializer,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn serialize<S>(data: &Mime, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&data.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Mime, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Vis;
|
||||||
|
impl<'de> Visitor<'de> for Vis {
|
||||||
|
type Value = Mime;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("a MIME type")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
v.parse()
|
||||||
|
.map_err(|_| de::Error::invalid_value(Unexpected::Str(v), &Vis))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(Vis)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue