feat: prepare for push notification II
This commit is contained in:
@@ -9,6 +9,13 @@ use crate::schema;
|
||||
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use rocket::form::Form;
|
||||
use rocket::serde::json::json;
|
||||
use rocket::serde::json::serde_json;
|
||||
use rocket::serde::Serialize;
|
||||
use std::fs::File;
|
||||
use url::Url;
|
||||
use web_push::{
|
||||
ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder,
|
||||
};
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct AttentionInput {
|
||||
@@ -76,3 +83,57 @@ pub async fn get_attention(user: CurrentUser, db: Db, rconn: RdsConn) -> JsonApi
|
||||
|
||||
code0!(ps_data)
|
||||
}
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct NotificatinInput {
|
||||
enable: bool,
|
||||
endpoint: String,
|
||||
auth: String,
|
||||
p256dh: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
struct PushData {
|
||||
title: String,
|
||||
pid: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[post("/post/<pid>/notification", data = "<ni>")]
|
||||
pub async fn set_notification(pid: i32, ni: Form<NotificatinInput>, _user: CurrentUser) -> JsonApi {
|
||||
let url_host = Url::parse(&ni.endpoint)
|
||||
.map_err(|_| UnknownPushEndpoint)?
|
||||
.host()
|
||||
.ok_or(UnknownPushEndpoint)?
|
||||
.to_string();
|
||||
(url_host.ends_with("googleapis.com") || url_host.ends_with("mozilla.com"))
|
||||
.then(|| ())
|
||||
.ok_or(UnknownPushEndpoint)?;
|
||||
|
||||
if ni.enable {
|
||||
let subscription_info = SubscriptionInfo::new(&ni.endpoint, &ni.p256dh, &ni.auth);
|
||||
|
||||
let file = File::open("keys/private.pem").unwrap();
|
||||
let sig_builder = VapidSignatureBuilder::from_pem(file, &subscription_info)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut builder = WebPushMessageBuilder::new(&subscription_info).unwrap();
|
||||
let data = PushData {
|
||||
title: "测试".to_owned(),
|
||||
pid,
|
||||
text: format!("#{} 开启提醒测试成功,消息提醒功能即将正式上线", &pid),
|
||||
};
|
||||
let content = serde_json::to_string(&data).unwrap();
|
||||
builder.set_payload(ContentEncoding::Aes128Gcm, content.as_bytes());
|
||||
builder.set_vapid_signature(sig_builder);
|
||||
|
||||
let client = WebPushClient::new()?;
|
||||
|
||||
client.send(builder.build()?).await?;
|
||||
}
|
||||
|
||||
code0!()
|
||||
}
|
||||
|
||||
@@ -119,12 +119,14 @@ pub enum PolicyError {
|
||||
YouAreTmp,
|
||||
NoReason,
|
||||
OldApi,
|
||||
UnknownPushEndpoint,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ApiError {
|
||||
Db(diesel::result::Error),
|
||||
Rds(redis::RedisError),
|
||||
WebPush(web_push::WebPushError),
|
||||
Pc(PolicyError),
|
||||
IO(std::io::Error),
|
||||
}
|
||||
@@ -134,6 +136,7 @@ impl<'r> Responder<'r, 'static> for ApiError {
|
||||
match self {
|
||||
ApiError::Db(e) => e2s!(e).respond_to(req),
|
||||
ApiError::Rds(e) => e2s!(e).respond_to(req),
|
||||
ApiError::WebPush(e) => e2s!(e).respond_to(req),
|
||||
ApiError::IO(e) => e2s!(e).respond_to(req),
|
||||
ApiError::Pc(e) => json!({
|
||||
"code": -1,
|
||||
@@ -144,7 +147,8 @@ impl<'r> Responder<'r, 'static> for ApiError {
|
||||
PolicyError::TitleUsed => "头衔已被使用",
|
||||
PolicyError::YouAreTmp => "临时用户只可发布内容和进入单个洞",
|
||||
PolicyError::NoReason => "未填写理由",
|
||||
PolicyError::OldApi => "请使用最新版前端地址并检查更新"
|
||||
PolicyError::OldApi => "请使用最新版前端地址并检查更新",
|
||||
PolicyError::UnknownPushEndpoint => "未知的浏览器推送地址",
|
||||
}
|
||||
})
|
||||
.respond_to(req),
|
||||
@@ -152,6 +156,12 @@ impl<'r> Responder<'r, 'static> for ApiError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<web_push::WebPushError> for ApiError {
|
||||
fn from(err: web_push::WebPushError) -> ApiError {
|
||||
ApiError::WebPush(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diesel::result::Error> for ApiError {
|
||||
fn from(err: diesel::result::Error) -> ApiError {
|
||||
ApiError::Db(err)
|
||||
|
||||
@@ -90,6 +90,7 @@ async fn main() -> Result<(), rocket::Error> {
|
||||
api::comment::add_comment,
|
||||
api::upload::local_upload,
|
||||
cors::options_handler,
|
||||
api::attention::set_notification,
|
||||
],
|
||||
)
|
||||
.mount(
|
||||
|
||||
Reference in New Issue
Block a user