chore: 重写初始提交(清空历史,整理后全量提交)

This commit is contained in:
ywxapp
2026-08-16 16:54:14 +08:00
commit 6c1a106bc1
1808 changed files with 238144 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace addon\wxchat\worker\handle;
use addon\wxchat\model\WxchatMessage;
use addon\wxchat\model\WxchatUnreadCount;
use addon\wxchat\service\SafetyService;
use addon\wxchat\worker\enum\MsgFrame;
use addon\wxchat\worker\enum\MsgType;
use addon\wxchat\worker\Message;
use addon\wxchat\worker\MsgReply;
use GatewayWorker\Lib\Gateway;
/**
* 聊天消息处理(实时落库 + 转发 + ACK)
*
* 协议约定(客户端上行):
* {
* "header": { "type":"chat", "target":"single"|"group", "timestamp":... },
* "payload": { "uid":123, "receiver":456, "session_id":789, "type":"text"|"image"|"voice"|"video"|"file"|"gift", "content":"...", "ext":{} }
* }
*/
class ChatHandle
{
// 内容类型字符串 -> 数据库 content_type(int)
private const CONTENT_TYPE_MAP = [
'text' => 0,
'image' => 1,
'voice' => 2,
'video' => 3,
'file' => 4,
'gift' => 5,
];
public static function handle($client_id, $header, $payload)
{
$uid = Gateway::getUidByClientId($client_id);
if (empty($uid)) {
MsgReply::sendError($client_id, '未认证,请先登录');
return;
}
$payloadUid = (int)($payload->uid ?? 0);
if ($payloadUid && $payloadUid != $uid) {
MsgReply::sendError($client_id, '身份不一致');
return;
}
$contentType = (string)($payload->type ?? 'text');
if (! isset(self::CONTENT_TYPE_MAP[$contentType])) {
MsgReply::sendError($client_id, '不支持的消息类型: ' . $contentType);
return;
}
// 礼物消息:仅做实时通知,落库由 HTTP Gift::send 负责
if ($contentType === 'gift') {
self::relayGift($client_id, $uid, $payload);
return;
}
$target = (string)($header->target ?? 'single');
$receiverType = ($target === 'group') ? 1 : 0;
$receiverId = (int)($target === 'group'
? ($payload->session_id ?? 0)
: ($payload->receiver ?? 0));
if (! $receiverId) {
MsgReply::sendError($client_id, '接收者无效');
return;
}
$content = $payload->content ?? '';
// 文本类消息做敏感词过滤
if ($contentType === 'text') {
$content = SafetyService::instance()->filter($content);
}
$msgId = self::saveMessage($uid, $receiverType, $receiverId, self::CONTENT_TYPE_MAP[$contentType], $content);
// 单聊:对方未读 +1
if ($receiverType == 0) {
WxchatUnreadCount::increment($receiverId, 0, $uid);
}
// 构造下发消息并转发
$out = self::buildOutbound($msgId, $uid, $contentType, $content, $payload);
if ($receiverType == 0) {
if (Gateway::isUidOnline($receiverId)) {
Gateway::sendToUid($receiverId, json_encode($out));
}
// 离线:消息已落库,接收方下次拉取 history 获取
} else {
Gateway::sendToGroup((string)$receiverId, json_encode($out));
}
// 发送方回执
MsgReply::send($client_id, MsgFrame::STATUS->value, MsgType::DELIVERED->value, 'delivered', [
'msg_id' => $msgId,
'receiver' => $receiverId,
'session_id' => $receiverId,
]);
}
/**
* 消息落库(可被 HTTP / WebSocket 共用,返回消息ID
*/
public static function saveMessage($senderId, $receiverType, $receiverId, $contentType, $content)
{
$msg = new WxchatMessage();
$msg->sender_id = $senderId;
$msg->receiver_type = $receiverType;
$msg->receiver_id = $receiverId;
$msg->content = $content;
$msg->content_type = $contentType;
$msg->save();
return $msg->id;
}
private static function buildOutbound($msgId, $senderId, $contentType, $content, $payload)
{
$out = new Message();
$out->header->frame = MsgFrame::CHAT->value;
$out->header->type = MsgFrame::CHAT->value;
$out->payload->msg_id = $msgId;
$out->payload->uid = $senderId;
$out->payload->type = $contentType; // 文本类为字符串,媒体类为URL
$out->payload->content = $content;
$out->payload->receiver = $payload->receiver ?? 0;
$out->payload->session_id = $payload->session_id ?? 0;
$out->payload->status = 'delivered';
if (! empty($payload->ext)) {
$out->payload->ext = $payload->ext;
}
return $out;
}
private static function relayGift($client_id, $uid, $payload)
{
$receiver = (int)($payload->receiver ?? 0);
if (! $receiver) {
MsgReply::sendError($client_id, '礼物接收者无效');
return;
}
$out = new Message();
$out->header->frame = MsgFrame::CHAT->value;
$out->header->type = 'gift';
$out->payload->uid = $uid;
$out->payload->receiver = $receiver;
$out->payload->content = $payload->content ?? '';
$out->payload->ext = $payload->ext ?? null;
if (Gateway::isUidOnline($receiver)) {
Gateway::sendToUid($receiver, json_encode($out));
}
MsgReply::send($client_id, MsgFrame::STATUS->value, MsgType::DELIVERED->value, 'delivered', [
'receiver' => $receiver,
]);
}
}