Files
YwxAppThink/addon/wxchat/worker/handle/RelationHandle.php
T

264 lines
9.2 KiB
PHP

<?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\WxchatFriend;
use addon\wxchat\model\WxchatGroup;
use addon\wxchat\model\WxchatGroupMember;
use addon\wxchat\worker\enum\MsgFrame;
use addon\wxchat\worker\enum\MsgType;
use addon\wxchat\worker\MsgReply;
use GatewayWorker\Lib\Gateway;
use ywxapp\model\MemberUser;
/**
* 关系消息处理(加好友 / 同意 / 拒绝 / 加群 / 邀请)
* 真实落库:wxapp_wxchat_friend / wxapp_wxchat_group_members / wxapp_wxchat_groups
*
* 协议约定(客户端上行):
* {
* "header": { "type":"rel", "timestamp":... },
* "payload": { "type":"friend_request"|"friend_agree"|"friend_refuse"|"group_join"|"group_invite",
* "receiver":<对方UID>, "session_id":<群ID>, "remark":"备注/招呼语" }
* }
*/
class RelationHandle
{
public static function handle($client_id, $header, $payload)
{
$uid = Gateway::getUidByClientId($client_id);
if (empty($uid)) {
MsgReply::sendError($client_id, '未认证,请先登录');
return;
}
// 关系子类型:优先 payload.type(与 ChatHandle 一致),兼容 header.type
$subType = (string) ($payload->type ?? ($header->type ?? ''));
$peer = (int) ($payload->receiver ?? 0);
$groupId = (int) ($payload->session_id ?? ($payload->group_id ?? 0));
$remark = trim((string) ($payload->remark ?? ($payload->content ?? '')));
switch ($subType) {
case MsgType::FRIEND_REQUEST->value:
self::friendRequest($client_id, $uid, $peer, $remark);
break;
case MsgType::FRIEND_AGREE->value:
self::friendAgree($client_id, $uid, $peer);
break;
case MsgType::FRIEND_REFUSE->value:
self::friendRefuse($client_id, $uid, $peer);
break;
case MsgType::GROUP_JOIN->value:
self::groupJoin($client_id, $uid, $groupId);
break;
case MsgType::GROUP_INVITE->value:
self::groupInvite($client_id, $uid, $groupId, $peer);
break;
default:
MsgReply::sendError($client_id, '不支持的关系消息类型: ' . $subType);
}
}
/**
* 好友申请:写入待处理好友记录(status=0),并实时通知对方
*/
private static function friendRequest($client_id, $uid, $peer, $remark)
{
if (! $peer) {
MsgReply::sendError($client_id, '对方 UID 无效');
return;
}
if ($peer == $uid) {
MsgReply::sendError($client_id, '不能添加自己为好友');
return;
}
// 已是好友(双向任一存在 status=1)
if (self::isFriend($uid, $peer)) {
MsgReply::sendError($client_id, '你们已是好友');
return;
}
// 去重:已存在待处理请求则不重复写入
$exist = WxchatFriend::where('uid', $uid)->where('fid', $peer)->where('status', 0)->find();
if (! $exist) {
$fr = new WxchatFriend();
$fr->uid = $uid;
$fr->fid = $peer;
$fr->remark = $remark;
$fr->status = 0; // 0-请求中
$fr->create_at = time();
$fr->save();
}
$myName = self::nickname($uid);
// 实时通知对方
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::FRIEND_REQUEST->value, '收到好友申请', [
'from' => $uid,
'from_name' => $myName,
'remark' => $remark,
]);
// 回执发送方
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::FRIEND_REQUEST->value, '已发送好友申请', [
'to' => $peer,
]);
}
/**
* 同意申请:$uid 同意 $peer 发来的请求,建立双向好友
*/
private static function friendAgree($client_id, $uid, $peer)
{
if (! $peer) {
MsgReply::sendError($client_id, '对方 UID 无效');
return;
}
$req = WxchatFriend::where('uid', $peer)->where('fid', $uid)->where('status', 0)->find();
if (! $req) {
MsgReply::sendError($client_id, '无待处理的好友申请');
return;
}
$req->status = 1; // 1-已通过
$req->update_at = time();
$req->save();
// 写入反向好友记录(保证双向查询一致)
if (! self::isFriend($uid, $peer)) {
$reverse = new WxchatFriend();
$reverse->uid = $uid;
$reverse->fid = $peer;
$reverse->status = 1;
$reverse->create_at = time();
$reverse->save();
}
// 通知申请方
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::FRIEND_AGREE->value, '对方已通过你的好友申请', [
'from' => $uid,
'from_name' => self::nickname($uid),
]);
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::FRIEND_AGREE->value, '已同意', [
'to' => $peer,
]);
}
/**
* 拒绝申请
*/
private static function friendRefuse($client_id, $uid, $peer)
{
if (! $peer) {
MsgReply::sendError($client_id, '对方 UID 无效');
return;
}
$req = WxchatFriend::where('uid', $peer)->where('fid', $uid)->where('status', 0)->find();
if (! $req) {
MsgReply::sendError($client_id, '无待处理的好友申请');
return;
}
$req->status = 2; // 2-已拒绝
$req->update_at = time();
$req->save();
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::FRIEND_REFUSE->value, '对方拒绝了你的好友申请', [
'from' => $uid,
]);
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::FRIEND_REFUSE->value, '已拒绝', [
'to' => $peer,
]);
}
/**
* 主动加群:加入 group_members
*/
private static function groupJoin($client_id, $uid, $groupId)
{
if (! $groupId) {
MsgReply::sendError($client_id, '群组 ID 无效');
return;
}
$group = WxchatGroup::find($groupId);
if (! $group) {
MsgReply::sendError($client_id, '群组不存在');
return;
}
if (WxchatGroupMember::where('gid', $groupId)->where('uid', $uid)->find()) {
MsgReply::sendError($client_id, '你已在群内');
return;
}
self::addGroupMember($groupId, $uid, 0);
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::GROUP_JOIN->value, '已加入群组', [
'group_id' => $groupId,
]);
}
/**
* 邀请加群:$uid 邀请 $peer 加入群组
*/
private static function groupInvite($client_id, $uid, $groupId, $peer)
{
if (! $groupId || ! $peer) {
MsgReply::sendError($client_id, '群组或受邀人无效');
return;
}
$group = WxchatGroup::find($groupId);
if (! $group) {
MsgReply::sendError($client_id, '群组不存在');
return;
}
if (! WxchatGroupMember::where('gid', $groupId)->where('uid', $peer)->find()) {
self::addGroupMember($groupId, $peer, 0);
}
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::GROUP_INVITE->value, '你被邀请加入群组', [
'group_id' => $groupId,
'from' => $uid,
'from_name' => self::nickname($uid),
]);
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::GROUP_INVITE->value, '邀请已发送', [
'group_id' => $groupId,
'to' => $peer,
]);
}
/**
* 写入群成员并自增群人数
*/
private static function addGroupMember($groupId, $uid, $role)
{
$m = new WxchatGroupMember();
$m->gid = $groupId;
$m->uid = $uid;
$m->role = $role;
$m->join_time = date('Y-m-d H:i:s');
$m->save();
WxchatGroup::where('id', $groupId)->inc('member_count')->update();
}
private static function isFriend($uid, $fid): bool
{
return (bool) WxchatFriend::where('uid', $uid)
->where('fid', $fid)
->where('status', 1)
->find();
}
private static function nickname($uid): string
{
try {
$name = MemberUser::where('uid', $uid)->value('nickname');
return $name ?: '';
} catch (\Throwable $e) {
return '';
}
}
}