Skip to main content

privchat_protocol/
message.rs

1// Copyright 2025 Shanghai Boyu Information Technology Co., Ltd.
2// https://privchat.dev
3//
4// Author: zoujiaqing <zoujiaqing@gmail.com>
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10//     http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! 消息类型与 Payload 解析结构体
19//!
20//! 仅定义已知消息类型,服务端与客户端统一使用本模块定义解析 payload。
21
22use serde::{Deserialize, Serialize};
23
24/// 内容消息类型(u32,仅已知类型)
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
26#[repr(u32)]
27pub enum ContentMessageType {
28    /// 文本消息
29    Text = 0,
30    /// 图片消息
31    Image = 1,
32    /// 文件消息
33    File = 2,
34    /// 语音消息
35    Voice = 3,
36    /// 视频消息
37    Video = 4,
38    /// 系统消息
39    System = 5,
40    /// 音频消息
41    Audio = 6,
42    /// 位置消息
43    Location = 7,
44    /// 名片消息
45    ContactCard = 8,
46    /// 表情包消息
47    Sticker = 9,
48    /// 转发消息
49    Forward = 10,
50}
51
52impl ContentMessageType {
53    pub fn from_u32(value: u32) -> Option<Self> {
54        match value {
55            0 => Some(ContentMessageType::Text),
56            1 => Some(ContentMessageType::Image),
57            2 => Some(ContentMessageType::File),
58            3 => Some(ContentMessageType::Voice),
59            4 => Some(ContentMessageType::Video),
60            5 => Some(ContentMessageType::System),
61            6 => Some(ContentMessageType::Audio),
62            7 => Some(ContentMessageType::Location),
63            8 => Some(ContentMessageType::ContactCard),
64            9 => Some(ContentMessageType::Sticker),
65            10 => Some(ContentMessageType::Forward),
66            _ => None,
67        }
68    }
69
70    pub fn as_u32(self) -> u32 {
71        self as u32
72    }
73
74    /// 转换为字符串(用于显示、RPC 等)
75    pub fn as_str(self) -> &'static str {
76        match self {
77            ContentMessageType::Text => "text",
78            ContentMessageType::Image => "image",
79            ContentMessageType::File => "file",
80            ContentMessageType::Voice => "voice",
81            ContentMessageType::Video => "video",
82            ContentMessageType::System => "system",
83            ContentMessageType::Audio => "audio",
84            ContentMessageType::Location => "location",
85            ContentMessageType::ContactCard => "contact_card",
86            ContentMessageType::Sticker => "sticker",
87            ContentMessageType::Forward => "forward",
88        }
89    }
90}
91
92// ---------- Payload 顶层信封(与 message_type 无关的公共字段) ----------
93
94/// 消息来源(非好友消息时使用)
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct MessageSource {
97    #[serde(rename = "type")]
98    pub source_type: String, // "search" | "group" | "card_share" | "qrcode" | "phone"
99    pub source_id: String,
100}
101
102/// Payload 解析后的顶层结构(content + metadata + 公共扩展)
103#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104pub struct MessagePayloadEnvelope {
105    /// 消息显示内容
106    #[serde(default)]
107    pub content: String,
108    /// 类型相关元数据,按 ContentMessageType 解析为对应 *Metadata 结构体
109    pub metadata: Option<serde_json::Value>,
110    /// 引用消息 ID(可选)
111    pub reply_to_message_id: Option<String>,
112    /// @ 提及的用户 ID 列表(可选)
113    pub mentioned_user_ids: Option<Vec<u64>>,
114    /// 非好友消息来源(可选)
115    pub message_source: Option<MessageSource>,
116}
117
118// ---------- 各消息类型对应的 metadata 解析结构体 ----------
119
120/// 图片消息 metadata
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ImageMetadata {
123    pub file_id: u64,
124    pub url: Option<String>,
125    pub width: Option<u32>,
126    pub height: Option<u32>,
127}
128
129/// 文件 / 语音 / 视频 / 音频消息 metadata(共用 file_id)
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct FileLikeMetadata {
132    pub file_id: u64,
133}
134
135/// 位置消息 metadata
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct LocationMetadata {
138    pub latitude: f64,
139    pub longitude: f64,
140}
141
142/// 名片消息 metadata
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct ContactCardMetadata {
145    pub user_id: u64,
146}
147
148/// 表情包消息 metadata
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct StickerMetadata {
151    pub sticker_id: String,
152    pub image_url: String,
153}
154
155/// 转发单条引用
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct ForwardMessageRef {
158    pub message_id: Option<u64>,
159    pub content: Option<String>,
160    #[serde(flatten)]
161    pub extra: Option<serde_json::Value>,
162}
163
164/// 转发消息 metadata
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct ForwardMetadata {
167    pub messages: Vec<ForwardMessageRef>,
168}