liyong
4 小时以前 7a23c450f3ac85de7dca1b908de273ff636ce218
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package cn.iocoder.yudao.module.im.framework.config;
 
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
 
/**
 * IM 模块全局配置
 * <p>
 * 各子模块用嵌套 inner class 区分(friend / group / face / message / rtc 等),
 * yaml 路径保持 yudao.im.{module}.{key} 与原有部署保持兼容
 *
 * @author 芋道源码
 */
@Component
@ConfigurationProperties(prefix = "yudao.im")
@Validated
@Data
public class ImProperties {
 
    private Friend friend = new Friend();
 
    private Group group = new Group();
 
    private Face face = new Face();
 
    private Message message = new Message();
 
    @Valid
    private Rtc rtc = new Rtc();
 
    /**
     * 好友模块配置
     */
    @Data
    public static class Friend {
 
        /**
         * 是否自动通过所有好友申请(全局开关)
         * <p>
         * 默认 false,普通用户必须走申请-审批流程;开启后所有用户的好友申请会立即同意,主要用于全员开放型 IM 部署。
         * 如需细化到「仅特定用户自动通过」(如机器人 / AI 账号),请在 system 用户表加字段,并在 applyFriend 内按用户级开关短路
         */
        private boolean autoAccept = false;
 
    }
 
    /**
     * 群模块配置
     */
    @Data
    public static class Group {
 
        /**
         * 群最大成员人数
         */
        private int maxMember = 500;
 
        /**
         * 单群管理员人数上限
         */
        private int adminMaxCount = 3;
 
        /**
         * 单群置顶消息条数上限
         */
        private int pinMaxCount = 5;
 
    }
 
    /**
     * 表情模块配置
     */
    @Data
    public static class Face {
 
        /**
         * 个人表情数量上限
         */
        private int userItemMaxCount = 200;
 
    }
 
    /**
     * 消息模块配置
     */
    @Data
    public static class Message {
 
        /**
         * 是否启用私聊已读功能
         * <p>
         * 关闭后:private read 接口直接抛业务异常;服务端不再下发私聊 READ / RECEIPT 事件信号。
         * 客户端侧需镜像此开关,隐藏私聊气泡的「已读 / 未读」标签
         */
        private boolean privateReadEnabled = true;
 
        /**
         * 是否启用群聊已读功能(含群消息回执)
         * <p>
         * 关闭后:group read 接口直接抛业务异常;服务端不再下发群 READ / RECEIPT 事件信号;
         * 群消息回执 receiptStatus 一并停用(即使发送方传 receipt=true 也强制落 NO_RECEIPT,不再算「N 人已读」)。
         * 客户端侧需镜像此开关,隐藏群回执 popover 与「发送回执消息」入口
         */
        private boolean groupReadEnabled = true;
 
        /**
         * pull 最大拉取数量
         */
        private int maxPullSize = 1000;
 
        /**
         * 消息撤回时间限制(分钟)
         */
        private int recallTimeoutMinutes = 5;
 
        /**
         * 私聊离线消息最大拉取天数
         * <p>
         * 客户端通过 pull 接口增量拉取私聊离线消息时,仅返回最近 N 天内产生的消息,
         * 超过该窗口的老消息不再主动推送(可通过历史消息接口按需倒翻)。
         */
        private int privatePullMaxDays = 30;
 
        /**
         * 群聊离线消息最大拉取天数
         * <p>
         * 客户端通过 pull 接口增量拉取群聊离线消息时,仅返回最近 N 天内产生的消息;
         * 退群前消息的补齐也以该窗口为基准(早于窗口的退群群不再扫描),避免老用户首次
         * 拉取时对历史退群群做大量查询。
         */
        private int groupPullMaxDays = 30;
 
    }
 
    /**
     * 实时通话模块配置
     * <p>
     * 媒体走 LiveKit SFU;后端只签 Token + 通过 IM 长连接推送来电 / 接通 / 结束三种信令。
     * 关闭后所有 RTC 接口直接抛 RTC_NOT_ENABLED;前端可据此隐藏通话按钮。
     */
    @Data
    public static class Rtc {
 
        /**
         * 是否启用实时通话功能
         */
        private boolean enabled = true;
 
        /**
         * LiveKit Server WebSocket 地址;客户端 connect 时使用,通常 ws://host:7880 或 wss://host
         */
        @NotBlank(message = "LiveKit URL 不能为空")
        private String livekitUrl = "ws://127.0.0.1:7880";
 
        /**
         * LiveKit API Key
         */
        @NotBlank(message = "LiveKit API Key 不能为空")
        private String apiKey = "devkey";
 
        /**
         * LiveKit API Secret;生产必须改为强随机值
         */
        @NotBlank(message = "LiveKit API Secret 不能为空")
        @Size(min = 32, message = "LiveKit API Secret 长度需 ≥ 32 位")
        private String apiSecret = "secret-poc-key-min-32-chars-required-here";
 
        /**
         * 单次签发的 Token 有效期(小时)
         */
        private int tokenTtlHours = 6;
 
        /**
         * 群通话最大同时在房成员数;超过 invite 直接拒绝
         */
        private int groupMaxParticipants = 16;
 
        /**
         * 僵尸通话清理阈值(分钟);通话创建超过此值仍未结束才纳入扫描,避开「刚发起还在响铃」的合理零人态
         */
        private int cleanupZombieThresholdMinutes = 5;
 
        /**
         * 振铃超时阈值(分钟);被叫 INVITING 超过此值未接通 → 标 NO_ANSWER + 推 RTC_CALL(REJECT) 让 banner 收敛
         */
        private int inviteTimeoutMinutes = 1;
 
    }
 
}