优化代码,去除MQ

main
gzydong 2021-07-08 19:09:06 +08:00
parent 5579b16548
commit a3b5033cab
35 changed files with 389 additions and 866 deletions

View File

@ -41,10 +41,3 @@ MAIL_PASSWORD=xxxx
MAIL_FROM_ADDRESS=xxxx@163.com
MAIL_FROM_NAME="xxxxx"
MAIL_ENCRYPTION=ssl
# ---- Rabbit MQ 配置 ----
AMQP_HOST=127.0.0.1
AMQP_PORT=5672
AMQP_USER=guest
AMQP_PASSWORD=guest
AMQP_VHOST=/im

View File

@ -24,7 +24,6 @@ Lumen-IM 是一个网页版在线即时聊天项目,前端使用 Element-ui +
- JSON
- PDO
- Redis >= 5.0.0
- AMQP
## 4、相关文档
[Hyperf 框架](https://hyperf.wiki/2.0/#/README)
@ -32,11 +31,11 @@ Lumen-IM 是一个网页版在线即时聊天项目,前端使用 Element-ui +
## 5、项目安装
1. 下载源码包
2. 安装框架依赖包执行 `compsoer install` 命令 [项目根目录下执行]
2. 拷贝项目根目录下 .env.example 文件为 .env 并正确配置相关参数mysql、redis、rabbitmq
2. 拷贝项目根目录下 .env.example 文件为 .env 并正确配置相关参数mysql、redis
3. 执行数据库迁移文件命令生成相关数据表 `php bin/hyperf.php migrate`
4. 启动运行项目 `php bin/hyperf.php start`
[项目运行之前请确保 Mysql、Redis、RabbitMQ 及 Nginx 服务]
[项目运行之前请确保 Mysql、Redis 及 Nginx 服务]
## Nginx 相关配置(代理 swoole 服务)
##### 配置 Http 服务
@ -129,7 +128,7 @@ server {
```
### 注意事项
1. 请确保 PHP 安装 openssl、redis、amqp 扩展
1. 请确保 PHP 安装 openssl、redis 扩展
2. 请确保 Swoole 扩展开启 openssl 扩展
```
[root@iZuf6cs69fbc86cwpu9iv3Z vhost]# php --ri swoole

View File

@ -1,62 +0,0 @@
<?php
declare(strict_types=1);
/**
* This is my open source code, please do not use it for commercial applications.
* For the full copyright and license information,
* please view the LICENSE file that was distributed with this source code
*
* @author Yuandong<837215079@qq.com>
* @link https://github.com/gzydong/hyperf-chat
*/
namespace App\Amqp\Producer;
use App\Constants\SocketConstants;
use Hyperf\Amqp\Message\ProducerMessage;
use Hyperf\Amqp\Message\Type;
/**
* 消息生产者
*
* @package App\Amqp\Producer
*/
class ChatMessageProducer extends ProducerMessage
{
/**
* 交换机类型
*
* @var string
*/
public $type = Type::FANOUT;
/**
* 交换机名称
*
* @var string
*/
public $exchange = SocketConstants::CONSUMER_MESSAGE_EXCHANGE;
/**
* 实例化处理
*
* @param string $event 事件名
* @param array $data 数据
* @param array $options 其它参数
*/
public function __construct(string $event, array $data, array $options = [])
{
$message = [
'uuid' => uniqid((strval(mt_rand(0, 1000)))),
'event' => $event,
'data' => $data,
'options' => $options
];
$this->payload = $message;
}
public function getPayload()
{
return $this->payload;
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\Constants;
class RedisSubscribeChan
{
const WEBSOCKET_CHAN = 'websocket';
}

View File

@ -9,6 +9,7 @@ use App\Constants\SocketConstants;
use App\Model\UsersFriendsApply;
use App\Service\SocketClientService;
use App\Service\UserService;
use App\Support\MessageProducer;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
@ -70,10 +71,12 @@ class ContactsApplyController extends CController
// 判断对方是否在线。如果在线发送消息通知
if ($this->socketClientService->isOnlineAll($params['friend_id'])) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_FRIEND_APPLY, [
'apply_id' => $result->id,
'type' => 1,
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_FRIEND_APPLY, [
'apply_id' => $result->id,
'type' => 1,
])
);
}
return $this->response->success([], '发送好友申请成功...');
@ -101,10 +104,12 @@ class ContactsApplyController extends CController
// 判断对方是否在线。如果在线发送消息通知
if ($this->socketClientService->isOnlineAll($friend_id)) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_FRIEND_APPLY, [
'apply_id' => (int)$params['apply_id'],
'type' => 2,
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_FRIEND_APPLY, [
'apply_id' => (int)$params['apply_id'],
'type' => 2,
])
);
}
return $this->response->success([], '处理成功...');

View File

@ -13,6 +13,7 @@ namespace App\Controller\Api\V1;
use App\Cache\SocketRoom;
use App\Constants\TalkType;
use App\Service\UserService;
use App\Support\MessageProducer;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
@ -76,13 +77,14 @@ class GroupController extends CController
SocketRoom::getInstance()->addRoomMember(strval($data['group_id']), $uid);
}
// ... 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$data['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => (int)$data['record_id']
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$data['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => (int)$data['record_id']
])
);
return $this->response->success([
'group_id' => $data['group_id']
@ -141,13 +143,14 @@ class GroupController extends CController
SocketRoom::getInstance()->addRoomMember($params['group_id'], $uid);
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
])
);
return $this->response->success([], '好友已成功加入群聊...');
}
@ -174,13 +177,14 @@ class GroupController extends CController
// 移出聊天室
SocketRoom::getInstance()->delRoomMember($params['group_id'], $user_id);
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
])
);
return $this->response->success([], '已成功退出群组...');
}
@ -245,13 +249,14 @@ class GroupController extends CController
SocketRoom::getInstance()->delRoomMember($params['group_id'], strval($uid));
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
])
);
return $this->response->success([], '已成功退出群组...');
}

View File

@ -10,6 +10,7 @@ use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use App\Model\EmoticonItem;
use App\Model\FileSplitUpload;
use App\Support\MessageProducer;
use App\Support\UserRelation;
use App\Service\EmoticonService;
use App\Service\TalkService;
@ -67,13 +68,14 @@ class TalkMessageController extends CController
if (!$record_id) return $this->response->fail('消息发送失败!');
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
])
);
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[代码消息]',
@ -133,13 +135,14 @@ class TalkMessageController extends CController
if (!$record_id) return $this->response->fail('图片上传失败!');
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id,
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id,
])
);
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[图片消息]',
@ -195,13 +198,14 @@ class TalkMessageController extends CController
if (!$record_id) return $this->response->fail('表情发送失败!');
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
])
);
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[文件消息]',
@ -259,13 +263,14 @@ class TalkMessageController extends CController
if (!$record_id) return $this->response->fail('表情发送失败!');
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
])
);
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[表情包消息]',
@ -321,12 +326,14 @@ class TalkMessageController extends CController
// 消息推送队列
foreach ($ids as $value) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => $value['receiver_id'],
'talk_type' => $value['talk_type'],
'record_id' => $value['record_id'],
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => $value['receiver_id'],
'talk_type' => $value['talk_type'],
'record_id' => $value['record_id'],
])
);
}
return $this->response->success([], '转发成功...');
@ -366,9 +373,11 @@ class TalkMessageController extends CController
[$isTrue, $message,] = $this->talkService->revokeRecord($this->uid(), $params['record_id']);
if (!$isTrue) return $this->response->fail($message);
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_REVOKE_TALK, [
'record_id' => $params['record_id']
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_REVOKE_TALK, [
'record_id' => $params['record_id']
])
);
return $this->response->success([], $message);
}

View File

@ -12,6 +12,8 @@ declare(strict_types=1);
namespace App\Controller;
use App\Cache\SocketRoom;
use App\Service\Message\ReceiveHandleService;
use App\Support\MessageProducer;
use Hyperf\Di\Annotation\Inject;
use App\Constants\SocketConstants;
use Hyperf\Contract\OnCloseInterface;
@ -22,9 +24,7 @@ use Swoole\Websocket\Frame;
use Swoole\Http\Response;
use Swoole\WebSocket\Server;
use App\Service\SocketClientService;
use App\Service\MessageHandleService;
use App\Model\Group\GroupMember;
use App\Amqp\Producer\ChatMessageProducer;
/**
* Class WebSocketController
@ -41,9 +41,9 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
/**
* @inject
* @var MessageHandleService
* @var ReceiveHandleService
*/
private $messageHandleService;
private $receiveHandleService;
/**
* 消息事件绑定
@ -84,11 +84,12 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
}
if (!$isOnline) {
// 推送消息至队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 1,
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 1,
])
);
}
}
@ -108,7 +109,7 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
// 回调事件处理函数
call_user_func_array([
$this->messageHandleService,
$this->receiveHandleService,
self::EVENTS[$result['event']]
], [$server, $frame, $result['data']]);
}
@ -132,11 +133,12 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
// 判断是否存在异地登录
$isOnline = $this->socketClientService->isOnlineAll($user_id);
if (!$isOnline) {
// 推送消息至队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 0,
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 0,
])
);
}
}
}

View File

@ -4,21 +4,7 @@ declare(strict_types=1);
namespace App\Process;
use App\Cache\SocketRoom;
use App\Constants\SocketConstants;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsCode;
use App\Model\Chat\TalkRecordsFile;
use App\Model\Chat\TalkRecordsForward;
use App\Model\Chat\TalkRecordsInvite;
use App\Model\Group\Group;
use App\Model\User;
use App\Model\UsersFriendsApply;
use App\Service\SocketClientService;
use App\Service\UserService;
use Hyperf\Amqp\Result;
use App\Service\Message\SubscribeHandleService;
use Hyperf\Process\AbstractProcess;
use Hyperf\Process\Annotation\Process;
@ -35,35 +21,13 @@ class RedisWebsocketSubscribe extends AbstractProcess
private $chans = ['websocket'];
/**
* 消息事件与回调事件绑定
*
* @var array
* @var SubscribeHandleService
*/
const EVENTS = [
// 聊天消息事件
SocketConstants::EVENT_TALK => 'onConsumeTalk',
// 键盘输入事件
SocketConstants::EVENT_KEYBOARD => 'onConsumeKeyboard',
// 用户在线状态事件
SocketConstants::EVENT_ONLINE_STATUS => 'onConsumeOnlineStatus',
// 聊天消息推送事件
SocketConstants::EVENT_REVOKE_TALK => 'onConsumeRevokeTalk',
// 好友申请相关事件
SocketConstants::EVENT_FRIEND_APPLY => 'onConsumeFriendApply'
];
/**
* @var SocketClientService
*/
private $socketClientService;
private $handleService;
public function handle(): void
{
$this->socketClientService = container()->get(SocketClientService::class);
$this->handleService = container()->get(SubscribeHandleService::class);
redis()->subscribe($this->chans, [$this, 'subscribe']);
}
@ -80,306 +44,13 @@ class RedisWebsocketSubscribe extends AbstractProcess
//echo PHP_EOL . "chan : $chan , msg : $message";
$data = json_decode($message, true);
$this->{self::EVENTS[$data['event']]}($data);
if (!isset(SubscribeHandleService::EVENTS[$data['event']])) return;
$this->handleService->{SubscribeHandleService::EVENTS[$data['event']]}($data);
}
public function isEnable($server): bool
{
return true;
}
/**
* 对话聊天消息
*
* @param array $data 队列消息
* @return string
*/
public function onConsumeTalk(array $data): string
{
$talk_type = $data['data']['talk_type'];
$sender_id = $data['data']['sender_id'];
$receiver_id = $data['data']['receiver_id'];
$record_id = $data['data']['record_id'];
$fds = [];
$groupInfo = null;
if ($talk_type == TalkType::PRIVATE_CHAT) {
$fds = array_merge(
$this->socketClientService->findUserFds($sender_id),
$this->socketClientService->findUserFds($receiver_id)
);
} else if ($talk_type == TalkType::GROUP_CHAT) {
foreach (SocketRoom::getInstance()->getRoomMembers(strval($receiver_id)) as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds(intval($uid)));
}
$groupInfo = Group::where('id', $receiver_id)->first(['group_name', 'avatar']);
}
// 客户端ID去重
if (!$fds = array_unique($fds)) {
return Result::ACK;
}
$result = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
->where('talk_records.id', $record_id)
->first([
'talk_records.id',
'talk_records.talk_type',
'talk_records.msg_type',
'talk_records.user_id',
'talk_records.receiver_id',
'talk_records.content',
'talk_records.is_revoke',
'talk_records.created_at',
'users.nickname',
'users.avatar',
]);
if (!$result) return Result::ACK;
$file = $code_block = $forward = $invite = [];
switch ($result->msg_type) {
case TalkMsgType::FILE_MESSAGE:
$file = TalkRecordsFile::where('record_id', $result->id)->first([
'id', 'record_id', 'user_id', 'file_source', 'file_type',
'save_type', 'original_name', 'file_suffix', 'file_size', 'save_dir'
]);
$file = $file ? $file->toArray() : [];
$file && $file['file_url'] = get_media_url($file['save_dir']);
break;
case TalkMsgType::FORWARD_MESSAGE:
$forward = ['num' => 0, 'list' => []];
$forwardInfo = TalkRecordsForward::where('record_id', $result->id)->first(['records_id', 'text']);
if ($forwardInfo) {
$forward = [
'num' => count(parse_ids($forwardInfo->records_id)),
'list' => json_decode($forwardInfo->text, true) ?? []
];
}
break;
case TalkMsgType::CODE_MESSAGE:
$code_block = TalkRecordsCode::where('record_id', $result->id)->first(['record_id', 'code_lang', 'code']);
$code_block = $code_block ? $code_block->toArray() : [];
break;
case TalkMsgType::GROUP_INVITE_MESSAGE:
$notifyInfo = TalkRecordsInvite::where('record_id', $result->id)->first([
'record_id', 'type', 'operate_user_id', 'user_ids'
]);
$userInfo = User::where('id', $notifyInfo->operate_user_id)->first(['nickname', 'id']);
$invite = [
'type' => $notifyInfo->type,
'operate_user' => ['id' => $userInfo->id, 'nickname' => $userInfo->nickname],
'users' => User::whereIn('id', parse_ids($notifyInfo->user_ids))->get(['id', 'nickname'])->toArray()
];
unset($notifyInfo, $userInfo);
break;
}
$notify = [
'sender_id' => $sender_id,
'receiver_id' => $receiver_id,
'talk_type' => $talk_type,
'data' => $this->formatTalkMessage([
'id' => $result->id,
'talk_type' => $result->talk_type,
'msg_type' => $result->msg_type,
"user_id" => $result->user_id,
"receiver_id" => $result->receiver_id,
'avatar' => $result->avatar,
'nickname' => $result->nickname,
'group_name' => $groupInfo ? $groupInfo->group_name : '',
'group_avatar' => $groupInfo ? $groupInfo->avatar : '',
"created_at" => $result->created_at,
"content" => $result->content,
"file" => $file,
"code_block" => $code_block,
'forward' => $forward,
'invite' => $invite
])
];
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_TALK, $notify]));
return Result::ACK;
}
/**
* 键盘输入事件消息
*
* @param array $data 队列消息
* @return string
*/
public function onConsumeKeyboard(array $data): string
{
$fds = $this->socketClientService->findUserFds($data['data']['receiver_id']);
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_KEYBOARD, $data['data']]));
return Result::ACK;
}
/**
* 用户上线或下线消息
*
* @param array $data 队列消息
* @return string
*/
public function onConsumeOnlineStatus(array $data): string
{
$user_id = (int)$data['data']['user_id'];
$status = (int)$data['data']['status'];
$fds = [];
$ids = container()->get(UserService::class)->getFriendIds($user_id);
foreach ($ids as $friend_id) {
$fds = array_merge($fds, $this->socketClientService->findUserFds(intval($friend_id)));
}
$this->socketPushNotify(array_unique($fds), json_encode([
SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => $status
]
]));
return Result::ACK;
}
/**
* 撤销聊天消息
*
* @param array $data 队列消息
* @return string
*/
public function onConsumeRevokeTalk(array $data): string
{
$record = TalkRecords::where('id', $data['data']['record_id'])->first(['id', 'talk_type', 'user_id', 'receiver_id']);
$fds = [];
if ($record->talk_type == TalkType::PRIVATE_CHAT) {
$fds = array_merge($fds, $this->socketClientService->findUserFds($record->user_id));
$fds = array_merge($fds, $this->socketClientService->findUserFds($record->receiver_id));
} else if ($record->talk_type == TalkType::GROUP_CHAT) {
$userIds = SocketRoom::getInstance()->getRoomMembers(strval($record->receiver_id));
foreach ($userIds as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$uid));
}
}
$fds = array_unique($fds);
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_REVOKE_TALK, [
'talk_type' => $record->talk_type,
'sender_id' => $record->user_id,
'receiver_id' => $record->receiver_id,
'record_id' => $record->id,
]]));
return Result::ACK;
}
/**
* 好友申请消息
*
* @param array $data 队列消息
* @return string
*/
public function onConsumeFriendApply(array $data): string
{
$data = $data['data'];
$applyInfo = UsersFriendsApply::where('id', $data['apply_id'])->first();
if (!$applyInfo) return Result::ACK;
$fds = $this->socketClientService->findUserFds($data['type'] == 1 ? $applyInfo->friend_id : $applyInfo->user_id);
if ($data['type'] == 1) {
$msg = [
'sender_id' => $applyInfo->user_id,
'receiver_id' => $applyInfo->friend_id,
'remark' => $applyInfo->remark,
];
} else {
$msg = [
'sender_id' => $applyInfo->friend_id,
'receiver_id' => $applyInfo->user_id,
'status' => $applyInfo->status,
'remark' => $applyInfo->remark,
];
}
$friendInfo = User::select(['id', 'avatar', 'nickname', 'mobile', 'motto'])->find($data['type'] == 1 ? $applyInfo->user_id : $applyInfo->friend_id);
$msg['friend'] = [
'user_id' => $friendInfo->id,
'avatar' => $friendInfo->avatar,
'nickname' => $friendInfo->nickname,
'mobile' => $friendInfo->mobile,
];
$this->socketPushNotify(array_unique($fds), json_encode([SocketConstants::EVENT_FRIEND_APPLY, $msg]));
return Result::ACK;
}
/**
* WebSocket 消息推送
*
* @param $fds
* @param $message
*/
private function socketPushNotify($fds, $message)
{
$server = server();
foreach ($fds as $fd) {
$server->exist(intval($fd)) && $server->push(intval($fd), $message);
}
}
/**
* 格式化对话的消息体
*
* @param array $data 对话的消息
* @return array
*/
private function formatTalkMessage(array $data): array
{
$message = [
"id" => 0, // 消息记录ID
"talk_type" => 1, // 消息来源[1:好友私信;2:群聊]
"msg_type" => 1, // 消息类型
"user_id" => 0, // 发送者用户ID
"receiver_id" => 0, // 接收者ID[好友ID或群ID]
// 发送消息人的信息
"nickname" => "",// 用户昵称
"avatar" => "",// 用户头像
"group_name" => "",// 群组名称
"group_avatar" => "",// 群组头像
// 不同的消息类型
"file" => [],
"code_block" => [],
"forward" => [],
"invite" => [],
// 消息创建时间
"content" => '',// 文本消息
"created_at" => "",
// 消息属性
"is_revoke" => 0, // 消息是否撤销
];
return array_merge($message, array_intersect_key($data, $message));
}
}

View File

@ -223,6 +223,7 @@ class GroupService extends BaseService
}
}
Db::beginTransaction();
try {
if ($updateArr) {
GroupMember::whereIn('id', $updateArr)->update([

View File

@ -1,29 +1,33 @@
<?php
namespace App\Service;
namespace App\Service\Message;
use App\Cache\LastMessage;
use App\Cache\UnreadTalk;
use App\Constants\SocketConstants;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use Hyperf\Di\Annotation\Inject;
use Swoole\Http\Response;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
use App\Amqp\Producer\ChatMessageProducer;
use App\Model\Chat\TalkRecords;
use App\Model\Group\Group;
use App\Model\UsersFriend;
use App\Cache\LastMessage;
use App\Cache\UnreadTalk;
use App\Service\SocketClientService;
use App\Support\MessageProducer;
use Swoole\Http\Response;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
class MessageHandleService
class ReceiveHandleService
{
/**
* @inject
* @var SocketClientService
*/
private $socketClientService;
public function __construct(SocketClientService $clientService)
{
$this->socketClientService = $clientService;
}
/**
* 对话消息
*
@ -81,12 +85,14 @@ class MessageHandleService
'created_at' => $result->created_at
]);
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $result->user_id,
'receiver_id' => $result->receiver_id,
'talk_type' => $result->talk_type,
'record_id' => $result->id
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_TALK, [
'sender_id' => $result->user_id,
'receiver_id' => $result->receiver_id,
'talk_type' => $result->talk_type,
'record_id' => $result->id
])
);
}
/**
@ -99,9 +105,11 @@ class MessageHandleService
*/
public function onKeyboard($server, Frame $frame, $data)
{
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_KEYBOARD, [
'sender_id' => intval($data['sender_id']),
'receiver_id' => intval($data['receiver_id']),
]));
MessageProducer::publish(
MessageProducer::create(SocketConstants::EVENT_KEYBOARD, [
'sender_id' => intval($data['sender_id']),
'receiver_id' => intval($data['receiver_id']),
])
);
}
}

View File

@ -1,70 +1,25 @@
<?php
declare(strict_types=1);
/**
* This is my open source code, please do not use it for commercial applications.
* For the full copyright and license information,
* please view the LICENSE file that was distributed with this source code
*
* @author Yuandong<837215079@qq.com>
* @link https://github.com/gzydong/hyperf-chat
*/
namespace App\Amqp\Consumer;
namespace App\Service\Message;
use App\Cache\SocketRoom;
use App\Constants\SocketConstants;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use App\Model\UsersFriendsApply;
use App\Service\UserService;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\Amqp\Message\Type;
use Hyperf\Amqp\Builder\QueueBuilder;
use PhpAmqpLib\Message\AMQPMessage;
use App\Model\User;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsCode;
use App\Model\Chat\TalkRecordsFile;
use App\Model\Chat\TalkRecordsInvite;
use App\Model\Chat\TalkRecordsForward;
use App\Model\Chat\TalkRecordsInvite;
use App\Model\Group\Group;
use App\Model\User;
use App\Model\UsersFriendsApply;
use App\Service\SocketClientService;
use App\Constants\SocketConstants;
use App\Cache\Repository\LockRedis;
use App\Cache\SocketRoom;
use App\Service\UserService;
use Hyperf\Amqp\Result;
/**
* 消息推送消费者队列
* @Consumer(name="ConsumerChat",enable=false)
*/
class ChatMessageConsumer extends ConsumerMessage
class SubscribeHandleService
{
/**
* 交换机名称
*
* @var string
*/
public $exchange = SocketConstants::CONSUMER_MESSAGE_EXCHANGE;
/**
* 交换机类型
*
* @var string
*/
public $type = Type::FANOUT;
/**
* 路由key
*
* @var string
*/
public $routingKey = 'consumer:im:message';
/**
* @var SocketClientService
*/
private $socketClientService;
/**
* 消息事件与回调事件绑定
*
@ -88,60 +43,22 @@ class ChatMessageConsumer extends ConsumerMessage
];
/**
* ChatMessageConsumer constructor.
*
* @param SocketClientService $socketClientService
* @var SocketClientService
*/
public function __construct(SocketClientService $socketClientService)
private $clientService;
public function __construct(SocketClientService $clientService)
{
$this->socketClientService = $socketClientService;
// 动态设置 Rabbit MQ 消费队列名称
$this->setQueue('queue:im_message:' . SERVER_RUN_ID);
}
/**
* 重写创建队列生成类
* 注释:设置自动删除队列
*
* @return QueueBuilder
*/
public function getQueueBuilder(): QueueBuilder
{
return parent::getQueueBuilder()->setAutoDelete(true);
}
/**
* 消费队列消息
*
* @param $data
* @param AMQPMessage $message
* @return string
*/
public function consumeMessage($data, AMQPMessage $message): string
{
if (isset($data['event'])) {
// [加锁]防止消息重复消费
$lockName = sprintf('ws-message:%s-%s', SERVER_RUN_ID, $data['uuid']);
if (!LockRedis::getInstance()->lock($lockName, 60)) {
return Result::ACK;
}
// 调用对应事件绑定的回调方法
return $this->{self::EVENTS[$data['event']]}($data, $message);
}
return Result::ACK;
$this->clientService = $clientService;
}
/**
* 对话聊天消息
*
* @param array $data 队列消息
* @param AMQPMessage $message
* @param array $data 队列消息
* @return string
*/
public function onConsumeTalk(array $data, AMQPMessage $message): string
public function onConsumeTalk(array $data): string
{
$talk_type = $data['data']['talk_type'];
$sender_id = $data['data']['sender_id'];
@ -153,12 +70,12 @@ class ChatMessageConsumer extends ConsumerMessage
if ($talk_type == TalkType::PRIVATE_CHAT) {
$fds = array_merge(
$this->socketClientService->findUserFds($sender_id),
$this->socketClientService->findUserFds($receiver_id)
$this->clientService->findUserFds($sender_id),
$this->clientService->findUserFds($receiver_id)
);
} else if ($talk_type == TalkType::GROUP_CHAT) {
foreach (SocketRoom::getInstance()->getRoomMembers(strval($receiver_id)) as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds(intval($uid)));
$fds = array_merge($fds, $this->clientService->findUserFds(intval($uid)));
}
$groupInfo = Group::where('id', $receiver_id)->first(['group_name', 'avatar']);
@ -166,7 +83,7 @@ class ChatMessageConsumer extends ConsumerMessage
// 客户端ID去重
if (!$fds = array_unique($fds)) {
return Result::ACK;
return true;
}
$result = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
@ -184,7 +101,7 @@ class ChatMessageConsumer extends ConsumerMessage
'users.avatar',
]);
if (!$result) return Result::ACK;
if (!$result) return true;
$file = $code_block = $forward = $invite = [];
@ -256,33 +173,31 @@ class ChatMessageConsumer extends ConsumerMessage
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_TALK, $notify]));
return Result::ACK;
return true;
}
/**
* 键盘输入事件消息
*
* @param array $data 队列消息
* @param AMQPMessage $message
* @param array $data 队列消息
* @return string
*/
public function onConsumeKeyboard(array $data, AMQPMessage $message): string
public function onConsumeKeyboard(array $data): string
{
$fds = $this->socketClientService->findUserFds($data['data']['receiver_id']);
$fds = $this->clientService->findUserFds($data['data']['receiver_id']);
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_KEYBOARD, $data['data']]));
return Result::ACK;
return true;
}
/**
* 用户上线或下线消息
*
* @param array $data 队列消息
* @param AMQPMessage $message
* @param array $data 队列消息
* @return string
*/
public function onConsumeOnlineStatus(array $data, AMQPMessage $message): string
public function onConsumeOnlineStatus(array $data): string
{
$user_id = (int)$data['data']['user_id'];
$status = (int)$data['data']['status'];
@ -291,7 +206,7 @@ class ChatMessageConsumer extends ConsumerMessage
$ids = container()->get(UserService::class)->getFriendIds($user_id);
foreach ($ids as $friend_id) {
$fds = array_merge($fds, $this->socketClientService->findUserFds(intval($friend_id)));
$fds = array_merge($fds, $this->clientService->findUserFds(intval($friend_id)));
}
$this->socketPushNotify(array_unique($fds), json_encode([
@ -301,28 +216,27 @@ class ChatMessageConsumer extends ConsumerMessage
]
]));
return Result::ACK;
return true;
}
/**
* 撤销聊天消息
*
* @param array $data 队列消息
* @param AMQPMessage $message
* @param array $data 队列消息
* @return string
*/
public function onConsumeRevokeTalk(array $data, AMQPMessage $message): string
public function onConsumeRevokeTalk(array $data): string
{
$record = TalkRecords::where('id', $data['data']['record_id'])->first(['id', 'talk_type', 'user_id', 'receiver_id']);
$fds = [];
if ($record->talk_type == TalkType::PRIVATE_CHAT) {
$fds = array_merge($fds, $this->socketClientService->findUserFds($record->user_id));
$fds = array_merge($fds, $this->socketClientService->findUserFds($record->receiver_id));
$fds = array_merge($fds, $this->clientService->findUserFds($record->user_id));
$fds = array_merge($fds, $this->clientService->findUserFds($record->receiver_id));
} else if ($record->talk_type == TalkType::GROUP_CHAT) {
$userIds = SocketRoom::getInstance()->getRoomMembers(strval($record->receiver_id));
foreach ($userIds as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$uid));
$fds = array_merge($fds, $this->clientService->findUserFds((int)$uid));
}
}
@ -334,24 +248,23 @@ class ChatMessageConsumer extends ConsumerMessage
'record_id' => $record->id,
]]));
return Result::ACK;
return true;
}
/**
* 好友申请消息
*
* @param array $data 队列消息
* @param AMQPMessage $message
* @param array $data 队列消息
* @return string
*/
public function onConsumeFriendApply(array $data, AMQPMessage $message): string
public function onConsumeFriendApply(array $data): string
{
$data = $data['data'];
$applyInfo = UsersFriendsApply::where('id', $data['apply_id'])->first();
if (!$applyInfo) return Result::ACK;
if (!$applyInfo) return true;
$fds = $this->socketClientService->findUserFds($data['type'] == 1 ? $applyInfo->friend_id : $applyInfo->user_id);
$fds = $this->clientService->findUserFds($data['type'] == 1 ? $applyInfo->friend_id : $applyInfo->user_id);
if ($data['type'] == 1) {
$msg = [
@ -379,7 +292,7 @@ class ChatMessageConsumer extends ConsumerMessage
$this->socketPushNotify(array_unique($fds), json_encode([SocketConstants::EVENT_FRIEND_APPLY, $msg]));
return Result::ACK;
return true;
}
/**

View File

@ -0,0 +1,34 @@
<?php
namespace App\Support;
use App\Constants\RedisSubscribeChan;
class MessageProducer
{
/**
* @param string $event
* @param array $data
* @param array $options
* @return array
*/
public static function create(string $event, array $data, array $options = [])
{
return [
'uuid' => uniqid((strval(mt_rand(0, 1000)))),
'event' => $event,
'data' => $data,
'options' => $options
];
}
/**
* @param array $message
*/
public static function publish(array $message)
{
push_redis_subscribe(RedisSubscribeChan::WEBSOCKET_CHAN, $message);
}
}

View File

@ -251,7 +251,6 @@ function parse_ids($ids)
*/
function push_amqp(ProducerMessage $message, bool $confirm = false, int $timeout = 5)
{
push_redis_subscribe('websocket', $message->getPayload());
return container()->get(Producer::class)->produce($message, $confirm, $timeout);
}

View File

@ -27,7 +27,6 @@
"hyperf/redis": "~2.0.0",
"hyperf/database": "~2.0.0",
"hyperf/async-queue": "~2.0.0",
"hyperf/amqp": "~2.0.0",
"hyperf/websocket-server": "^2.0",
"hyperf/constants": "^2.0",
"hyperf/validation": "^2.0",

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'host' => env('AMQP_HOST','127.0.0.1'),
'port' => intval(env('AMQP_PORT',5672)),
'user' => env('AMQP_USER','guest'),
'password' => env('AMQP_PASSWORD','guest'),
'vhost' => env('AMQP_VHOST','/'),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
],
'params' => [
'insist' => false,
'login_method' => 'AMQPLAIN',
'login_response' => null,
'locale' => 'en_US',
'connection_timeout' => 3.0,
'read_write_timeout' => 8.0,
'context' => null,
'keepalive' => false,
'heartbeat' => 3,
],
],
];

View File

@ -17,10 +17,11 @@ class CreateUsersTable extends Migration
$table->string('mobile', 11)->default('')->unique()->comment('手机号');
$table->string('nickname', 20)->default('')->comment('用户昵称');
$table->string('avatar', 255)->default('')->comment('用户头像地址');
$table->unsignedTinyInteger('gender')->default(0)->comment('用户性别[0:未知;1:男;2:女]');
$table->unsignedTinyInteger('gender')->default(0)->comment('用户性别[0:未知;1:男;2:女;]');
$table->string('password', 255)->default('')->comment('用户密码');
$table->string('motto', 100)->default('')->comment('用户座右铭');
$table->string('email', 30)->default('')->comment('用户邮箱');
$table->unsignedTinyInteger('is_robot')->default(0)->comment('是否机器人[0:否;1:是;]');
$table->dateTime('created_at')->nullable()->comment('注册时间');
$table->dateTime('updated_at')->nullable()->comment('更新时间');

View File

@ -17,16 +17,16 @@ class CreateArticleAnnexTable extends Migration
$table->unsignedInteger('user_id')->unsigned()->comment('上传文件的用户ID');
$table->unsignedInteger('article_id')->default(0)->comment('笔记ID');
$table->string('file_suffix', 10)->default('')->comment('文件后缀名');
$table->bigInteger('file_size')->default(0)->unsigned()->comment('文件大小(单位字节)');
$table->string('save_dir', 500)->nullable()->comment('文件保存地址(相对地址)');
$table->string('original_name', 100)->nullable()->comment('原文件名');
$table->tinyInteger('status')->default(1)->unsigned()->comment('附件状态[1:正常;2:已删除]');
$table->unsignedBigInteger('file_size')->default(0)->comment('文件大小(单位字节)');
$table->string('save_dir', 500)->nullable(false)->default('')->comment('文件保存地址(相对地址)');
$table->string('original_name', 100)->nullable(false)->default('')->comment('原文件名');
$table->unsignedTinyInteger('status')->default(1)->comment('附件状态[1:正常;2:已删除]');
$table->dateTime('created_at')->nullable(true)->comment('附件上传时间');
$table->dateTime('deleted_at')->nullable(true)->comment('附件删除时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['user_id', 'article_id'], 'idx_user_id_article_id');
});

View File

@ -22,6 +22,8 @@ class CreateEmoticonTable extends Migration
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->unique(['name'], 'uk_name');
});
$prefix = config('databases.default.prefix');

View File

@ -15,7 +15,7 @@ class CreateFileSplitUploadTable extends Migration
$table->unsignedInteger('id', true)->comment('临时文件ID');
$table->unsignedTinyInteger('file_type')->default(2)->comment('数据类型[1:合并文件;2:拆分文件]');
$table->unsignedInteger('user_id')->default(0)->comment('上传的用户ID');
$table->string('hash_name', 30)->default('')->comment('临时文件hash名');
$table->string('hash_name', 32)->default('')->comment('临时文件hash名');
$table->string('original_name', 100)->default('')->comment('原文件名');
$table->unsignedTinyInteger('split_index')->default(0)->comment('当前索引块');
$table->unsignedTinyInteger('split_num')->default(0)->comment('总上传索引块');

View File

@ -1,35 +0,0 @@
<?php
use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateUserLoginLogTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('user_login_log', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('登录日志ID');
$table->unsignedInteger('user_id')->default(0)->comment('用户ID');
$table->string('ip', 20)->comment('登录地址IP');
$table->dateTime('created_at')->nullable(true)->comment('登录时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}user_login_log` comment '用户登录日志表'");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_login_log');
}
}

View File

@ -0,0 +1,45 @@
<?php
use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateTalkListTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('talk_list', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('聊天列表ID');
$table->unsignedTinyInteger('talk_type')->default(1)->comment('聊天类型[1:私信;2:群聊;]');
$table->unsignedInteger('user_id')->default(0)->comment('用户ID');
$table->unsignedInteger('receiver_id')->default(0)->comment('接收者ID用户ID 或 群ID');
$table->unsignedTinyInteger('is_top')->default(0)->comment('是否置顶[0:否;1:是]');
$table->unsignedTinyInteger('is_robot')->default(0)->comment('是否机器人[0:否;1:是;]');
$table->unsignedTinyInteger('is_delete')->default(0)->comment('是否删除[0:否;1:是;]');
$table->unsignedTinyInteger('is_disturb')->default(0)->comment('消息免打扰[0:否;1:是;]');
$table->dateTime('created_at')->nullable(true)->comment('创建时间');
$table->dateTime('updated_at')->nullable(true)->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->index(['user_id', 'receiver_id', 'talk_type'], 'idx_user_id_receiver_id_talk_type');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}talk_list` comment '用户聊天列表'");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('talk_list');
}
}

View File

@ -1,44 +0,0 @@
<?php
use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateUsersChatListTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users_chat_list', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('聊天列表ID');
$table->unsignedTinyInteger('type')->default(1)->comment('聊天类型[1:好友;2:群聊]');
$table->unsignedInteger('uid')->default(0)->comment('用户ID');
$table->unsignedInteger('friend_id')->default(0)->comment('朋友的用户ID');
$table->unsignedInteger('group_id')->default(0)->comment('聊天分组ID');
$table->unsignedInteger('status')->default(1)->default(1)->comment('状态[0:已删除;1:正常]');
$table->unsignedTinyInteger('is_top')->default(0)->comment('是否置顶[0:否;1:是]');
$table->unsignedTinyInteger('not_disturb')->default(0)->comment('是否消息免打扰[0:否;1:是]');
$table->dateTime('created_at')->nullable(true)->comment('创建时间');
$table->dateTime('updated_at')->nullable(true)->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->index(['uid', 'friend_id', 'group_id', 'type'], 'idx_uid_type_friend_id_group_id');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}users_chat_list` comment '用户聊天列表'");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users_chat_list');
}
}

View File

@ -1,42 +0,0 @@
<?php
use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateChatRecordsTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_records', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('聊天记录ID');
$table->tinyInteger('source')->unsigned()->default(1)->comment('消息来源[1:好友消息;2:群聊消息]');
$table->tinyInteger('msg_type')->unsigned()->default(1)->comment('消息类型[1:文本消息;2:文件消息;3:系统提示好友入群消息或系统提示好友退群消息;4:会话记录转发]');
$table->unsignedInteger('user_id')->default(0)->comment('发送消息的用户ID[0:代表系统消息]');
$table->unsignedInteger('receive_id')->default(0)->comment('接收消息的用户ID或群聊ID');
$table->text('content')->nullable(true)->charset('utf8mb4')->comment('文本消息');
$table->tinyInteger('is_revoke')->default(0)->comment('是否撤回消息[0:否;1:是]');
$table->dateTime('created_at')->nullable(true)->comment('发送消息的时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->index(['user_id', 'receive_id'], 'idx_userid_receiveid');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}chat_records` comment '用户聊天记录表'");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('chat_records');
}
}

View File

@ -0,0 +1,48 @@
<?php
use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateTalkRecordsTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('talk_records', function (Blueprint $table) {
$table->unsignedBigInteger('id', true)->comment('聊天记录ID');
$table->unsignedTinyInteger('talk_type')->unsigned()->default(1)->comment('对话类型[1:私信;2:群聊;]');
$table->unsignedTinyInteger('msg_type')->unsigned()->default(1)->comment('消息类型[1:文本消息;2:文件消息;3:会话消息;4:代码消息;5:投票消息;6:群公告;7:好友申请;8:登录通知;9:入群消息/退群消息;]');
$table->unsignedInteger('user_id')->default(0)->comment('发送者ID0:代表系统消息 >0: 用户ID');
$table->unsignedInteger('receiver_id')->default(0)->comment('接收者ID用户ID 或 群ID');
$table->tinyInteger('is_revoke')->default(0)->comment('是否撤回消息[0:否;1:是]');
$table->tinyInteger('is_mark')->default(0)->comment('是否重要消息[0:否;1:是;]');
$table->tinyInteger('is_read')->default(0)->comment('是否已读[0:否;1:是;]');
$table->unsignedBigInteger('quote_id')->default(0)->comment('引用消息ID');
$table->text('content')->nullable(true)->charset('utf8mb4')->comment('文本消息 {@nickname@}');
$table->string('warn_users', 200)->default('')->comment('@好友 、 多个用英文逗号 “,” 拼接 (0:代表所有人)');
$table->dateTime('created_at')->nullable(true)->comment('创建时间');
$table->dateTime('updated_at')->nullable(true)->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->index(['user_id', 'receiver_id'], 'idx_user_id_receiver_id');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}talk_records` comment '用户聊天记录表'");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('talk_records');
}
}

View File

@ -4,14 +4,15 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateChatRecordsFileTable extends Migration
class CreateTalkRecordsFileTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_records_file', function (Blueprint $table) {
Schema::create('talk_records_file', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('文件ID');
$table->unsignedInteger('record_id')->default(0)->comment('消息记录ID');
$table->unsignedInteger('user_id')->default(0)->comment('上传文件的用户ID');
@ -25,15 +26,15 @@ class CreateChatRecordsFileTable extends Migration
$table->tinyInteger('is_delete')->default(0)->unsigned()->comment('文件是否已删除[0:否;1:已删除]');
$table->dateTime('created_at')->nullable(true)->comment('创建时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->unique(['record_id'], 'idx_record_id');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}chat_records_file` comment '用户聊天记录_文件消息表'");
DB::statement("ALTER TABLE `{$prefix}talk_records_file` comment '用户聊天记录_文件消息表'");
}
/**
@ -41,6 +42,6 @@ class CreateChatRecordsFileTable extends Migration
*/
public function down(): void
{
Schema::dropIfExists('chat_records_file');
Schema::dropIfExists('talk_records_file');
}
}

View File

@ -5,28 +5,28 @@ use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateChatRecordsDeleteTable extends Migration
class CreateTalkRecordsDeleteTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_records_delete', function (Blueprint $table) {
Schema::create('talk_records_delete', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('聊天删除记录ID');
$table->unsignedInteger('record_id')->default(0)->comment('聊天记录ID');
$table->unsignedInteger('user_id')->default(0)->comment('用户ID');
$table->dateTime('created_at')->nullable(true)->comment('删除时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['record_id', 'user_id'], 'idx_record_user_id');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}chat_records_delete` comment '用户聊天记录_删除记录表'");
DB::statement("ALTER TABLE `{$prefix}talk_records_delete` comment '用户聊天记录_删除记录表'");
}
/**
@ -34,6 +34,6 @@ class CreateChatRecordsDeleteTable extends Migration
*/
public function down(): void
{
Schema::dropIfExists('chat_records_delete_file');
Schema::dropIfExists('talk_records_delete');
}
}

View File

@ -4,14 +4,14 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateChatRecordsForwardTable extends Migration
class CreateTalkRecordsForwardTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_records_forward', function (Blueprint $table) {
Schema::create('talk_records_forward', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('合并转发ID');
$table->unsignedInteger('record_id')->default(0)->comment('消息记录ID');
$table->unsignedInteger('user_id')->default(0)->comment('转发用户ID');
@ -27,7 +27,7 @@ class CreateChatRecordsForwardTable extends Migration
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}chat_records_forward` comment '用户聊天记录_转发信息表'");
DB::statement("ALTER TABLE `{$prefix}talk_records_forward` comment '用户聊天记录_转发信息表'");
}
/**
@ -35,6 +35,6 @@ class CreateChatRecordsForwardTable extends Migration
*/
public function down(): void
{
Schema::dropIfExists('chat_records_forward');
Schema::dropIfExists('talk_records_forward');
}
}

View File

@ -4,29 +4,30 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateChatRecordsInviteTable extends Migration
class CreateTalkRecordsInviteTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_records_invite', function (Blueprint $table) {
Schema::create('talk_records_invite', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('入群或退群通知ID');
$table->unsignedInteger('record_id')->default(0)->comment('消息记录ID');
$table->tinyInteger('type')->default(1)->comment('通知类型[1:入群通知;2:自动退群;3:管理员踢群]');
$table->unsignedInteger('operate_user_id')->default(0)->comment('操作人的用户ID(邀请人)');
$table->string('user_ids', 255)->default('')->comment("用户ID多个用','分割");
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['record_id'], 'idx_recordid');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}chat_records_invite` comment '用户聊天记录_入群或退群消息表'");
DB::statement("ALTER TABLE `{$prefix}talk_records_invite` comment '用户聊天记录_入群或退群消息表'");
}
/**
@ -34,6 +35,6 @@ class CreateChatRecordsInviteTable extends Migration
*/
public function down(): void
{
Schema::dropIfExists('chat_records_invite');
Schema::dropIfExists('talk_records_invite');
}
}

View File

@ -4,14 +4,15 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateChatRecordsCodeTable extends Migration
class CreateTalkRecordsCodeTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_records_code', function (Blueprint $table) {
Schema::create('talk_records_code', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('入群或退群通知ID');
$table->unsignedInteger('record_id')->default(0)->comment('消息记录ID');
$table->unsignedInteger('user_id')->default(0)->comment('上传文件的用户ID');
@ -19,15 +20,15 @@ class CreateChatRecordsCodeTable extends Migration
$table->text('code')->charset('utf8mb4')->comment('代码片段内容');
$table->dateTime('created_at')->nullable(true)->comment('创建时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['record_id'], 'idx_recordid');
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}chat_records_code` comment '用户聊天记录_代码块消息表'");
DB::statement("ALTER TABLE `{$prefix}talk_records_code` comment '用户聊天记录_代码块消息表'");
}
/**
@ -35,6 +36,6 @@ class CreateChatRecordsCodeTable extends Migration
*/
public function down(): void
{
Schema::dropIfExists('chat_records_code');
Schema::dropIfExists('talk_records_code');
}
}

View File

@ -14,21 +14,18 @@ class CreateUsersFriendsTable extends Migration
{
Schema::create('users_friends', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('关系ID');
$table->unsignedInteger('user1')->default(0)->comment('用户1(user1 一定比 user2 小)');
$table->unsignedInteger('user2')->default(0)->comment('用户2(user1 一定比 user2 小)');
$table->string('user1_remark', 20)->default('')->comment('好友备注');
$table->string('user2_remark', 20)->default('')->comment('好友备注');
$table->unsignedTinyInteger('active')->default(1)->default(1)->comment('主动邀请方[1:user1;2:user2]');
$table->unsignedTinyInteger('status')->default(1)->comment('好友状态[0:已解除好友关系;1:好友状态]');
$table->dateTime('agree_time')->comment('成为好友时间');
$table->unsignedInteger('user_id')->default(0)->comment('用户ID');
$table->unsignedInteger('friend_id')->default(0)->comment('好友ID');
$table->string('remark', 30)->default('')->comment('好友备注');
$table->unsignedTinyInteger('status')->default(0)->comment('好友状态[0:否;1:是;]');
$table->dateTime('created_at')->nullable(true)->comment('创建时间');
$table->dateTime('updated_at')->nullable(true)->comment('更新时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['user1', 'user2'], 'idx_user1_user2');
$table->index(['user2', 'user1'], 'idx_user2_user1');
$table->index(['user_id', 'friend_id'], 'idx_user_id_friend_id');
});
$prefix = config('databases.default.prefix');

View File

@ -4,6 +4,7 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateUsersFriendsApplyTable extends Migration
{
/**
@ -14,15 +15,16 @@ class CreateUsersFriendsApplyTable extends Migration
Schema::create('users_friends_apply', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('申请ID');
$table->unsignedInteger('user_id')->default(0)->comment('申请人ID');
$table->unsignedInteger('friend_id')->default(0)->comment('被申请人');
$table->unsignedTinyInteger('status')->default(0)->comment('申请状态[0:等待处理;1:已同意]');
$table->string('remarks', 50)->default('')->comment('申请人备注信息');
$table->unsignedInteger('friend_id')->default(0)->comment('好友ID');
$table->unsignedTinyInteger('status')->default(0)->comment('申请状态[0:等待处理;1:已同意;2:已拒绝;]');
$table->string('remark', 50)->default('')->comment('备注信息');
$table->string('reason', 50)->default('')->comment('拒绝的原因');
$table->dateTime('created_at')->nullable()->comment('申请时间');
$table->dateTime('updated_at')->nullable()->comment('处理时间');
$table->dateTime('updated_at')->nullable()->comment('更新时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['user_id'], 'idx_user_id');
$table->index(['friend_id'], 'idx_friend_id');

View File

@ -25,9 +25,9 @@ class CreateGroupTable extends Migration
$table->dateTime('created_at')->nullable()->comment('创建时间');
$table->dateTime('dismissed_at')->nullable()->comment('解散时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
});
$prefix = config('databases.default.prefix');

View File

@ -23,12 +23,12 @@ class CreateGroupMemberTable extends Migration
$table->dateTime('created_at')->nullable()->comment('入群时间');
$table->dateTime('deleted_at')->nullable()->comment('退群时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->unique(['group_id', 'user_id'], 'uk_group_id_user_id');
$table->index(['user_id', 'group_id'], 'idx_user_id_group_id');
$table->index(['user_id'], 'idx_user_id');
});
$prefix = config('databases.default.prefix');

View File

@ -26,9 +26,9 @@ class CreateGroupNoticeTable extends Migration
$table->dateTime('updated_at')->nullable()->comment('更新时间');
$table->dateTime('deleted_at')->nullable()->comment('删除时间');
$table->charset = 'utf8';
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->engine = 'InnoDB';
$table->index(['group_id', 'is_delete', 'is_top', 'updated_at'], 'idx_group_id_is_delete_is_top_updated_at');
});