Add january support.

This commit is contained in:
Paul
2021-05-07 18:00:21 +01:00
parent cf7bb832da
commit 7293abfc53
20 changed files with 280 additions and 208 deletions

View File

@@ -94,9 +94,7 @@ impl Channel {
let channel_id = self.id().to_string();
ClientboundNotification::ChannelCreate(self)
.publish(channel_id)
.await
.ok();
.publish(channel_id);
Ok(())
}
@@ -108,9 +106,7 @@ impl Channel {
data,
clear: None
}
.publish(id)
.await
.ok();
.publish(id);
Ok(())
}
@@ -193,9 +189,7 @@ impl Channel {
})?;
ClientboundNotification::ChannelDelete { id: id.to_string() }
.publish(id.to_string())
.await
.ok();
.publish(id.to_string());
if let Channel::Group { icon, .. } = self {
if let Some(attachment) = icon {

View File

@@ -0,0 +1,71 @@
use serde::{Serialize, Deserialize};
use linkify::{LinkFinder, LinkKind};
use crate::util::{result::{Error, Result}, variables::JANUARY_URL};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum MediaSize {
Large,
Preview,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Media {
pub url: String,
pub width: isize,
pub height: isize,
pub size: MediaSize,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Metadata {
#[serde(skip_serializing_if = "Option::is_none")]
title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
image: Option<Media>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum Embed {
Website(Metadata),
Image(Media),
None,
}
impl Embed {
pub async fn generate(content: String) -> Result<Vec<Embed>> {
// FIXME: allow multiple links
let mut finder = LinkFinder::new();
finder.kinds(&[LinkKind::Url]);
let links: Vec<_> = finder.links(&content).collect();
if links.len() == 0 {
return Err(Error::LabelMe);
}
let link = &links[0];
let client = reqwest::Client::new();
let result = client
.get(&format!("{}/embed", *JANUARY_URL))
.query(&[("url", link.as_str())])
.send()
.await;
match result {
Err(_) => return Err(Error::LabelMe),
Ok(result) => match result.status() {
reqwest::StatusCode::OK => {
let res: Embed = result.json()
.await
.map_err(|_| Error::InvalidOperation)?;
Ok(vec![ res ])
},
_ => return Err(Error::LabelMe),
},
}
}
}

View File

@@ -17,12 +17,6 @@ use web_push::{
ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder,
};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum MessageEmbed {
Dummy,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum SystemMessage {
@@ -60,7 +54,7 @@ pub struct Message {
#[serde(skip_serializing_if = "Option::is_none")]
pub edited: Option<DateTime>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embeds: Option<MessageEmbed>,
pub embeds: Option<Vec<Embed>>,
}
impl Message {
@@ -138,11 +132,12 @@ impl Message {
_ => {}
}
self.process_embed();
let enc = serde_json::to_string(&self).unwrap();
ClientboundNotification::Message(self)
.publish(channel.id().to_string())
.await
.unwrap();
.publish(channel.id().to_string());
/*
Web Push Test Code
@@ -162,78 +157,114 @@ impl Message {
_ => {}
}
// Fetch their corresponding sessions.
if let Ok(mut cursor) = get_collection("accounts")
.find(
doc! {
"_id": {
"$in": target_ids
async_std::task::spawn(async move {
// Fetch their corresponding sessions.
if let Ok(mut cursor) = get_collection("accounts")
.find(
doc! {
"_id": {
"$in": target_ids
},
"sessions.subscription": {
"$exists": true
}
},
"sessions.subscription": {
"$exists": true
}
},
FindOptions::builder()
.projection(doc! { "sessions": 1 })
.build(),
)
.await
{
let mut subscriptions = vec![];
while let Some(result) = cursor.next().await {
if let Ok(doc) = result {
if let Ok(sessions) = doc.get_array("sessions") {
for session in sessions {
if let Some(doc) = session.as_document() {
if let Ok(sub) = doc.get_document("subscription") {
let endpoint = sub.get_str("endpoint").unwrap().to_string();
let p256dh = sub.get_str("p256dh").unwrap().to_string();
let auth = sub.get_str("auth").unwrap().to_string();
FindOptions::builder()
.projection(doc! { "sessions": 1 })
.build(),
)
.await
{
let mut subscriptions = vec![];
while let Some(result) = cursor.next().await {
if let Ok(doc) = result {
if let Ok(sessions) = doc.get_array("sessions") {
for session in sessions {
if let Some(doc) = session.as_document() {
if let Ok(sub) = doc.get_document("subscription") {
let endpoint = sub.get_str("endpoint").unwrap().to_string();
let p256dh = sub.get_str("p256dh").unwrap().to_string();
let auth = sub.get_str("auth").unwrap().to_string();
subscriptions
.push(SubscriptionInfo::new(endpoint, p256dh, auth));
subscriptions
.push(SubscriptionInfo::new(endpoint, p256dh, auth));
}
}
}
}
}
}
}
if subscriptions.len() > 0 {
let client = WebPushClient::new();
let key =
base64::decode_config(VAPID_PRIVATE_KEY.clone(), base64::URL_SAFE).unwrap();
if subscriptions.len() > 0 {
let client = WebPushClient::new();
let key =
base64::decode_config(VAPID_PRIVATE_KEY.clone(), base64::URL_SAFE).unwrap();
for subscription in subscriptions {
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
let sig_builder =
VapidSignatureBuilder::from_pem(std::io::Cursor::new(&key), &subscription)
.unwrap();
let signature = sig_builder.build().unwrap();
builder.set_vapid_signature(signature);
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
let m = builder.build().unwrap();
client.send(m).await.ok();
for subscription in subscriptions {
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
let sig_builder =
VapidSignatureBuilder::from_pem(std::io::Cursor::new(&key), &subscription)
.unwrap();
let signature = sig_builder.build().unwrap();
builder.set_vapid_signature(signature);
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
let m = builder.build().unwrap();
client.send(m).await.ok();
}
}
}
}
});
Ok(())
}
pub async fn publish_update(&self, data: JsonValue) -> Result<()> {
pub async fn publish_update(self, data: JsonValue) -> Result<()> {
let channel = self.channel.clone();
ClientboundNotification::MessageUpdate {
id: self.id.clone(),
data,
}
.publish(channel)
.await
.ok();
.publish(channel);
self.process_embed();
Ok(())
}
pub fn process_embed(&self) {
if let Content::Text(text) = &self.content {
let id = self.id.clone();
let content = text.clone();
let channel = self.channel.clone();
async_std::task::spawn(async move {
if let Ok(embeds) = Embed::generate(content).await {
if let Ok(bson) = to_bson(&embeds) {
if let Ok(_) = get_collection("messages")
.update_one(
doc! {
"_id": &id
},
doc! {
"$set": {
"embeds": bson
}
},
None,
)
.await {
ClientboundNotification::MessageUpdate {
id,
data: json!({
"embeds": embeds
}),
}
.publish(channel);
}
}
}
});
}
}
pub async fn delete(&self) -> Result<()> {
if let Some(attachment) = &self.attachment {
attachment.delete().await?;
@@ -256,9 +287,7 @@ impl Message {
ClientboundNotification::MessageDelete {
id: self.id.clone(),
}
.publish(channel)
.await
.ok();
.publish(channel);
if let Some(attachment) = &self.attachment {
get_collection("attachments")

View File

@@ -1,9 +1,11 @@
mod autumn;
mod channel;
mod guild;
mod autumn;
mod january;
mod channel;
mod message;
mod user;
pub use january::*;
pub use autumn::*;
pub use channel::*;
pub use guild::*;

View File

@@ -107,9 +107,11 @@ pub enum ClientboundNotification {
}
impl ClientboundNotification {
pub async fn publish(self, topic: String) -> Result<(), String> {
prehandle_hook(&self); // ! TODO: this should be moved to pubsub
hive_pubsub::backend::mongo::publish(get_hive(), &topic, self).await
pub fn publish(self, topic: String) {
async_std::task::spawn(async move {
prehandle_hook(&self); // ! TODO: this should be moved to pubsub
hive_pubsub::backend::mongo::publish(get_hive(), &topic, self).await.ok();
});
}
}

View File

@@ -133,9 +133,7 @@ async fn accept(stream: TcpStream) {
id: id.clone(),
online: true,
}
.publish(id)
.await
.ok();
.publish(id);
}
}
Err(_) => {
@@ -173,9 +171,7 @@ async fn accept(stream: TcpStream) {
id: channel.clone(),
user,
}
.publish(channel)
.await
.ok();
.publish(channel);
} else {
send(ClientboundNotification::Error(
WebSocketError::AlreadyAuthenticated,
@@ -196,9 +192,7 @@ async fn accept(stream: TcpStream) {
id: channel.clone(),
user,
}
.publish(channel)
.await
.ok();
.publish(channel);
} else {
send(ClientboundNotification::Error(
WebSocketError::AlreadyAuthenticated,
@@ -238,9 +232,7 @@ async fn accept(stream: TcpStream) {
id: id.clone(),
online: false,
}
.publish(id)
.await
.ok();
.publish(id);
}
}

View File

@@ -95,9 +95,7 @@ pub async fn req(user: User, target: Ref) -> Result<()> {
id: id.clone(),
user: user.id.clone(),
}
.publish(id.clone())
.await
.ok();
.publish(id.clone());
Message::create(
"00000000000000000000000000".to_string(),

View File

@@ -101,9 +101,7 @@ pub async fn req(user: User, target: Ref, data: Json<Data>) -> Result<()> {
data: json!(set),
clear: data.remove
}
.publish(id.clone())
.await
.ok();
.publish(id.clone());
if let Some(name) = data.name {
Message::create(

View File

@@ -52,9 +52,7 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
id: id.clone(),
user: member.id.clone(),
}
.publish(id.clone())
.await
.ok();
.publish(id.clone());
Message::create(
"00000000000000000000000000".to_string(),

View File

@@ -49,9 +49,7 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
id: id.clone(),
user: member.id.clone(),
}
.publish(id.clone())
.await
.ok();
.publish(id.clone());
Message::create(
"00000000000000000000000000".to_string(),

View File

@@ -74,21 +74,19 @@ pub async fn req(user: User, username: String) -> Result<JsonValue> {
.from_override(&target_user, RelationshipStatus::Friend)
.await?;
try_join!(
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target_user,
status: RelationshipStatus::Friend
}
.publish(user.id.clone()),
ClientboundNotification::UserRelationship {
id: target_id.to_string(),
user,
status: RelationshipStatus::Friend
}
.publish(target_id.to_string())
)
.ok();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target_user,
status: RelationshipStatus::Friend
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.to_string(),
user,
status: RelationshipStatus::Friend
}
.publish(target_id.to_string());
Ok(json!({ "status": "Friend" }))
}
@@ -136,21 +134,20 @@ pub async fn req(user: User, username: String) -> Result<JsonValue> {
let user = user
.from_override(&target_user, RelationshipStatus::Incoming)
.await?;
try_join!(
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target_user,
status: RelationshipStatus::Outgoing
}
.publish(user.id.clone()),
ClientboundNotification::UserRelationship {
id: target_id.to_string(),
user,
status: RelationshipStatus::Incoming
}
.publish(target_id.to_string())
)
.ok();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target_user,
status: RelationshipStatus::Outgoing
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.to_string(),
user,
status: RelationshipStatus::Incoming
}
.publish(target_id.to_string());
Ok(json!({ "status": "Outgoing" }))
}

View File

@@ -38,9 +38,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
user: target,
status: RelationshipStatus::Blocked,
}
.publish(user.id.clone())
.await
.ok();
.publish(user.id.clone());
Ok(json!({ "status": "Blocked" }))
}
@@ -84,21 +82,19 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
.await?;
let target_id = target.id.clone();
try_join!(
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked
}
.publish(user.id.clone()),
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::BlockedOther
}
.publish(target_id)
)
.ok();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::BlockedOther
}
.publish(target_id);
Ok(json!({ "status": "Blocked" }))
}
@@ -146,21 +142,19 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
.await?;
let target_id = target.id.clone();
try_join!(
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked
}
.publish(user.id.clone()),
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::BlockedOther
}
.publish(target_id)
)
.ok();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::Blocked
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::BlockedOther
}
.publish(target_id);
Ok(json!({ "status": "Blocked" }))
}

View File

@@ -60,9 +60,7 @@ pub async fn req(
data: json!(data.0),
clear: None
}
.publish(user.id.clone())
.await
.ok();
.publish(user.id.clone());
Ok(())
}

View File

@@ -135,9 +135,7 @@ pub async fn req(user: User, data: Json<Data>, _ignore_id: String) -> Result<()>
data: json!({ "status": status }),
clear: None
}
.publish(user.id.clone())
.await
.ok();
.publish(user.id.clone());
}
if let Some(avatar) = attachment {
@@ -146,9 +144,7 @@ pub async fn req(user: User, data: Json<Data>, _ignore_id: String) -> Result<()>
data: json!({ "avatar": avatar }),
clear: None
}
.publish(user.id.clone())
.await
.ok();
.publish(user.id.clone());
}
if let Some(clear) = data.remove {
@@ -157,9 +153,7 @@ pub async fn req(user: User, data: Json<Data>, _ignore_id: String) -> Result<()>
data: json!({}),
clear: Some(clear)
}
.publish(user.id.clone())
.await
.ok();
.publish(user.id.clone());
}
if remove_avatar {

View File

@@ -53,21 +53,19 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
.await?;
let target_id = target.id.clone();
try_join!(
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::None
}
.publish(user.id.clone()),
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::None
}
.publish(target_id)
)
.ok();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::None
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user,
status: RelationshipStatus::None
}
.publish(target_id);
Ok(json!({ "status": "None" }))
}

View File

@@ -40,9 +40,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
user: target,
status: RelationshipStatus::BlockedOther,
}
.publish(user.id.clone())
.await
.ok();
.publish(user.id.clone());
Ok(json!({ "status": "BlockedOther" }))
}
@@ -84,21 +82,19 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
.await?;
let target_id = target.id.clone();
try_join!(
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::None
}
.publish(user.id.clone()),
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user: user,
status: RelationshipStatus::None
}
.publish(target_id)
)
.ok();
ClientboundNotification::UserRelationship {
id: user.id.clone(),
user: target,
status: RelationshipStatus::None
}
.publish(user.id.clone());
ClientboundNotification::UserRelationship {
id: target_id.clone(),
user: user,
status: RelationshipStatus::None
}
.publish(target_id);
Ok(json!({ "status": "None" }))
}

View File

@@ -18,6 +18,8 @@ lazy_static! {
pub static ref AUTUMN_URL: String =
env::var("AUTUMN_PUBLIC_URL").unwrap_or_else(|_| "https://example.com".to_string());
pub static ref JANUARY_URL: String =
env::var("JANUARY_PUBLIC_URL").unwrap_or_else(|_| "https://example.com".to_string());
pub static ref VOSO_URL: String =
env::var("VOSO_PUBLIC_URL").unwrap_or_else(|_| "https://example.com".to_string());
pub static ref VOSO_WS_HOST: String =