初始化
parent
84e1dfc7a8
commit
0e2787f240
|
@ -12,7 +12,7 @@ use Hyperf\Amqp\Message\Type;
|
||||||
use Hyperf\Amqp\Builder\QueueBuilder;
|
use Hyperf\Amqp\Builder\QueueBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Consumer(name=" ChatMessage ",enable=true)
|
* @Consumer(name="聊天消息消费者",enable=true)
|
||||||
*/
|
*/
|
||||||
class ChatMessageConsumer extends ConsumerMessage
|
class ChatMessageConsumer extends ConsumerMessage
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace App\Amqp\Producer;
|
||||||
|
|
||||||
use Hyperf\Amqp\Message\ProducerMessage;
|
use Hyperf\Amqp\Message\ProducerMessage;
|
||||||
use Hyperf\Amqp\Message\Type;
|
use Hyperf\Amqp\Message\Type;
|
||||||
|
use Hyperf\Utils\Str;
|
||||||
|
|
||||||
class ChatMessageProducer extends ProducerMessage
|
class ChatMessageProducer extends ProducerMessage
|
||||||
{
|
{
|
||||||
|
@ -16,13 +17,24 @@ class ChatMessageProducer extends ProducerMessage
|
||||||
public function __construct($data)
|
public function __construct($data)
|
||||||
{
|
{
|
||||||
$message = [
|
$message = [
|
||||||
|
'uuid' => $this->uuid(),
|
||||||
'method' => '', //
|
'method' => '', //
|
||||||
'sender'=>'', // 发送者
|
'sender' => '', //发送者ID
|
||||||
'receive'=>'', // 接收者
|
'receive' => '', //接收者ID
|
||||||
'receiveType'=>'',
|
'receiveType' => '', //接收者类型 1:好友;2:群组
|
||||||
'message' => []
|
'message' => []
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->payload = $data;
|
$this->payload = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成唯一ID
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function uuid()
|
||||||
|
{
|
||||||
|
return Str::random() . rand(100000, 999999);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Bootstrap;
|
||||||
|
|
||||||
|
use App\Service\SocketFDService;
|
||||||
|
use Hyperf\Framework\Bootstrap\ServerStartCallback;
|
||||||
|
use Hashids\Hashids;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义服务启动前回调事件
|
||||||
|
*
|
||||||
|
* Class ServerStart
|
||||||
|
* @package App\Bootstrap
|
||||||
|
*/
|
||||||
|
class ServerStart extends ServerStartCallback
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inject
|
||||||
|
* @var SocketFDService
|
||||||
|
*/
|
||||||
|
private $socketFDService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回调事件
|
||||||
|
*/
|
||||||
|
public function beforeStart()
|
||||||
|
{
|
||||||
|
$hashids = new Hashids('', 8, 'abcdefghijklmnopqrstuvwxyz');
|
||||||
|
|
||||||
|
// 服务运行ID
|
||||||
|
define('SERVER_RUN_ID', $hashids->encode(time() . rand(1000, 9999)));
|
||||||
|
|
||||||
|
$this->socketFDService->removeRedisCache();
|
||||||
|
|
||||||
|
|
||||||
|
stdout_log()->info(sprintf('服务运行ID : %s', SERVER_RUN_ID));
|
||||||
|
stdout_log()->info('服务启动前回调事件 : beforeStart ...');
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,6 @@ class ResponseCode extends AbstractConstants
|
||||||
*/
|
*/
|
||||||
const SERVER_ERROR = 500;
|
const SERVER_ERROR = 500;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Message("请求数据验证失败!")
|
* @Message("请求数据验证失败!")
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace App\Controller\Api\V1;
|
namespace App\Controller\Api\V1;
|
||||||
|
|
||||||
use App\Controller\AbstractController;
|
use App\Controller\AbstractController;
|
||||||
use App\Support\Http\Response;
|
use App\Support\Response;
|
||||||
use Hyperf\Di\Annotation\Inject;
|
use Hyperf\Di\Annotation\Inject;
|
||||||
use Phper666\JWTAuth\JWT;
|
use Phper666\JWTAuth\JWT;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,217 @@
|
||||||
|
|
||||||
namespace App\Controller\Api\V1;
|
namespace App\Controller\Api\V1;
|
||||||
|
|
||||||
|
use App\Constants\ResponseCode;
|
||||||
|
use App\Model\Emoticon;
|
||||||
|
use App\Model\EmoticonDetail;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Hyperf\HttpServer\Annotation\Controller;
|
||||||
|
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||||
|
use Hyperf\HttpServer\Annotation\Middleware;
|
||||||
|
use Phper666\JWTAuth\Middleware\JWTAuthMiddleware;
|
||||||
|
use App\Service\EmoticonService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EmoticonController
|
||||||
|
*
|
||||||
|
* @Controller(path="/api/v1/emoticon")
|
||||||
|
* @Middleware(JWTAuthMiddleware::class)
|
||||||
|
*
|
||||||
|
* @package App\Controller\Api\V1
|
||||||
|
*/
|
||||||
class EmoticonController extends CController
|
class EmoticonController extends CController
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @Inject
|
||||||
|
* @var EmoticonService
|
||||||
|
*/
|
||||||
|
public $emoticonService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户表情包列表
|
||||||
|
*
|
||||||
|
* @RequestMapping(path="user-emoticon", methods="get")
|
||||||
|
*/
|
||||||
|
public function getUserEmoticon()
|
||||||
|
{
|
||||||
|
$emoticonList = [];
|
||||||
|
$user_id = $this->uid();
|
||||||
|
|
||||||
|
if ($ids = $this->emoticonService->getInstallIds($user_id)) {
|
||||||
|
$items = Emoticon::whereIn('id', $ids)->get(['id', 'name', 'url']);
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$emoticonList[] = [
|
||||||
|
'emoticon_id' => $item->id,
|
||||||
|
'url' => get_media_url($item->url),
|
||||||
|
'name' => $item->name,
|
||||||
|
'list' => $this->emoticonService->getDetailsAll([
|
||||||
|
['emoticon_id', '=', $item->id],
|
||||||
|
['user_id', '=', 0]
|
||||||
|
])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->success([
|
||||||
|
'sys_emoticon' => $emoticonList,
|
||||||
|
'collect_emoticon' => $this->emoticonService->getDetailsAll([
|
||||||
|
['emoticon_id', '=', 0],
|
||||||
|
['user_id', '=', $user_id]
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取系统表情包
|
||||||
|
*
|
||||||
|
* @RequestMapping(path="system-emoticon", methods="get")
|
||||||
|
*/
|
||||||
|
public function getSystemEmoticon()
|
||||||
|
{
|
||||||
|
$items = Emoticon::get(['id', 'name', 'url'])->toArray();
|
||||||
|
if ($items) {
|
||||||
|
$ids = $this->emoticonService->getInstallIds($this->uid());
|
||||||
|
array_walk($items, function (&$item) use ($ids) {
|
||||||
|
$item['status'] = in_array($item['id'], $ids) ? 1 : 0;
|
||||||
|
$item['url'] = get_media_url($item['url']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->success($items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安装或移除系统表情包
|
||||||
|
*
|
||||||
|
* @RequestMapping(path="set-user-emoticon", methods="post")
|
||||||
|
*/
|
||||||
|
public function setUserEmoticon()
|
||||||
|
{
|
||||||
|
$params = $this->request->all();
|
||||||
|
$this->validate($params, [
|
||||||
|
'emoticon_id' => 'required|integer',
|
||||||
|
'type' => 'required|in:1,2',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user_id = $this->uid();
|
||||||
|
if ($params['type'] == 2) {
|
||||||
|
// 移除表情包
|
||||||
|
$isTrue = $this->emoticonService->removeSysEmoticon($user_id, $params['emoticon_id']);
|
||||||
|
if (!$isTrue) {
|
||||||
|
return $this->response->fail('移除表情包失败...');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->success([], '移除表情包成功...');
|
||||||
|
} else {
|
||||||
|
// 添加表情包
|
||||||
|
$emoticonInfo = Emoticon::where('id', $params['emoticon_id'])->first(['id', 'name', 'url']);
|
||||||
|
if (!$emoticonInfo) {
|
||||||
|
return $this->response->fail('添加表情包失败...');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->emoticonService->installSysEmoticon($user_id, $params['emoticon_id'])) {
|
||||||
|
return $this->response->fail('添加表情包失败...');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'emoticon_id' => $emoticonInfo->id,
|
||||||
|
'url' => get_media_url($emoticonInfo->url),
|
||||||
|
'name' => $emoticonInfo->name,
|
||||||
|
'list' => $this->emoticonService->getDetailsAll([
|
||||||
|
['emoticon_id', '=', $emoticonInfo->id]
|
||||||
|
])
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->response->success($data, '添加表情包成功...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义上传表情包
|
||||||
|
*
|
||||||
|
* @RequestMapping(path="upload-emoticon", methods="post")
|
||||||
|
*/
|
||||||
|
public function uploadEmoticon()
|
||||||
|
{
|
||||||
|
$file = $this->request->file('emoticon');
|
||||||
|
if (!$file->isValid()) {
|
||||||
|
return $this->response->fail(
|
||||||
|
'图片上传失败,请稍后再试...',
|
||||||
|
ResponseCode::VALIDATION_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ext = $file->getExtension();
|
||||||
|
if (!in_array($ext, ['jpg', 'png', 'jpeg', 'gif', 'webp'])) {
|
||||||
|
return $this->response->fail(
|
||||||
|
'图片格式错误,目前仅支持jpg、png、jpeg、gif和webp',
|
||||||
|
ResponseCode::VALIDATION_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$save_path = '';
|
||||||
|
|
||||||
|
$user_id = $this->uid();
|
||||||
|
$imgInfo = getimagesize($file->getPath());
|
||||||
|
$filename = create_image_name($ext, $imgInfo[0], $imgInfo[1]);
|
||||||
|
|
||||||
|
$result = EmoticonDetail::create([
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'url' => $save_path,
|
||||||
|
'file_suffix' => $ext,
|
||||||
|
'file_size' => $file->getSize(),
|
||||||
|
'created_at' => time()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
return $this->response->fail('表情包上传失败...');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->success([
|
||||||
|
'media_id' => $result->id,
|
||||||
|
'src' => get_media_url($result->url)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收藏聊天图片的我的表情包
|
||||||
|
*
|
||||||
|
* @RequestMapping(path="collect-emoticon", methods="post")
|
||||||
|
*/
|
||||||
|
public function collectEmoticon()
|
||||||
|
{
|
||||||
|
$params = $this->request->all();
|
||||||
|
$this->validate($params, [
|
||||||
|
'record_id' => 'required|integer'
|
||||||
|
]);
|
||||||
|
|
||||||
|
[$isTrue, $data] = $this->emoticonService->collect($this->uid(), $params['record_id']);
|
||||||
|
|
||||||
|
if (!$isTrue) {
|
||||||
|
return $this->response->fail('添加表情失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->success([
|
||||||
|
'emoticon' => $data
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除收藏的表情包
|
||||||
|
*
|
||||||
|
* @RequestMapping(path="del-collect-emoticon", methods="post")
|
||||||
|
*/
|
||||||
|
public function delCollectEmoticon()
|
||||||
|
{
|
||||||
|
$params = $this->request->all();
|
||||||
|
$this->validate($params, [
|
||||||
|
'ids' => 'required'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$ids = explode(',', trim($params['ids']));
|
||||||
|
|
||||||
|
return $this->emoticonService->deleteCollect($this->uid(), $ids) ?
|
||||||
|
$this->response->success([], 'success') :
|
||||||
|
$this->response->fail('fail');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,177 @@
|
||||||
|
|
||||||
namespace App\Controller\Api\V1;
|
namespace App\Controller\Api\V1;
|
||||||
|
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Hyperf\HttpServer\Annotation\Controller;
|
||||||
|
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||||
|
use Hyperf\HttpServer\Annotation\Middleware;
|
||||||
|
use Phper666\JWTAuth\Middleware\JWTAuthMiddleware;
|
||||||
|
use App\Service\FriendService;
|
||||||
|
use App\Service\UserService;
|
||||||
|
|
||||||
class UsersController extends CController
|
class UsersController extends CController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Inject
|
||||||
|
* @var FriendService
|
||||||
|
*/
|
||||||
|
protected $friendService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Inject
|
||||||
|
* @var UserService
|
||||||
|
*/
|
||||||
|
protected $userService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="friends", methods="get")
|
||||||
|
*/
|
||||||
|
public function getUserFriends()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="remove-friend", methods="get")
|
||||||
|
*/
|
||||||
|
public function removeFriend()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="user-groups", methods="get")
|
||||||
|
*/
|
||||||
|
public function getUserGroups()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="detail", methods="get")
|
||||||
|
*/
|
||||||
|
public function getUserDetail()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="setting", methods="get")
|
||||||
|
*/
|
||||||
|
public function getUserSetting()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="edit-user-detail", methods="get")
|
||||||
|
*/
|
||||||
|
public function editUserDetail()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="edit-avatar", methods="get")
|
||||||
|
*/
|
||||||
|
public function editAvatar()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="search-user", methods="get")
|
||||||
|
*/
|
||||||
|
public function searchUserInfo()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="edit-friend-remark", methods="get")
|
||||||
|
*/
|
||||||
|
public function editFriendRemark()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="send-friend-apply", methods="get")
|
||||||
|
*/
|
||||||
|
public function sendFriendApply()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="handle-friend-apply", methods="get")
|
||||||
|
*/
|
||||||
|
public function handleFriendApply()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="delete-friend-apply", methods="get")
|
||||||
|
*/
|
||||||
|
public function deleteFriendApply()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="friend-apply-records", methods="get")
|
||||||
|
*/
|
||||||
|
public function getFriendApplyRecords()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="friend-apply-num", methods="get")
|
||||||
|
*/
|
||||||
|
public function getApplyUnreadNum()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="change-password", methods="get")
|
||||||
|
*/
|
||||||
|
public function editUserPassword()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="change-mobile", methods="get")
|
||||||
|
*/
|
||||||
|
public function editUserMobile()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="change-email", methods="get")
|
||||||
|
*/
|
||||||
|
public function editUserEmail()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="send-mobile-code", methods="get")
|
||||||
|
*/
|
||||||
|
public function sendMobileCode()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestMapping(path="send-change-email-code", methods="get")
|
||||||
|
*/
|
||||||
|
public function sendChangeEmailCode()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,9 +13,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use App\Amqp\Producer\ChatMessageProducer;
|
|
||||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||||
use Hyperf\Amqp\Producer;
|
|
||||||
|
|
||||||
class IndexController extends AbstractController
|
class IndexController extends AbstractController
|
||||||
{
|
{
|
||||||
|
@ -24,13 +22,6 @@ class IndexController extends AbstractController
|
||||||
$user = $this->request->input('user', 'Hyperf');
|
$user = $this->request->input('user', 'Hyperf');
|
||||||
$method = $this->request->getMethod();
|
$method = $this->request->getMethod();
|
||||||
|
|
||||||
$producer = container()->get(Producer::class);
|
|
||||||
|
|
||||||
$ip = config('ip_address');
|
|
||||||
|
|
||||||
$string = time();
|
|
||||||
$producer->produce(new ChatMessageProducer("我是来自[{$ip} 服务器的消息],{$string}"));
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'method' => $method,
|
'method' => $method,
|
||||||
'message' => "Hello {$user}.",
|
'message' => "Hello {$user}.",
|
||||||
|
|
|
@ -3,33 +3,84 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
use Hyperf\Contract\OnCloseInterface;
|
use Hyperf\Contract\OnCloseInterface;
|
||||||
use Hyperf\Contract\OnMessageInterface;
|
use Hyperf\Contract\OnMessageInterface;
|
||||||
use Hyperf\Contract\OnOpenInterface;
|
use Hyperf\Contract\OnOpenInterface;
|
||||||
|
use Hyperf\Utils\Codec\Json;
|
||||||
|
use Phper666\JWTAuth\JWT;
|
||||||
use Swoole\Http\Request;
|
use Swoole\Http\Request;
|
||||||
use Swoole\Websocket\Frame;
|
use Swoole\Websocket\Frame;
|
||||||
use Hyperf\Amqp\Producer;
|
use Hyperf\Amqp\Producer;
|
||||||
use App\Amqp\Producer\ChatMessageProducer;
|
use App\Amqp\Producer\ChatMessageProducer;
|
||||||
|
use Swoole\Http\Response;
|
||||||
|
use Swoole\WebSocket\Server;
|
||||||
|
use App\Traits\WebSocketTrait;
|
||||||
|
use App\Service\SocketFDService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WebSocketController
|
||||||
|
* @package App\Controller
|
||||||
|
*/
|
||||||
class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
|
class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
|
||||||
{
|
{
|
||||||
public function onMessage($server, Frame $frame): void
|
use WebSocketTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Inject
|
||||||
|
* @var JWT
|
||||||
|
*/
|
||||||
|
private $jwt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inject
|
||||||
|
* @var SocketFDService
|
||||||
|
*/
|
||||||
|
private $socketFDService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接创建成功回调事件
|
||||||
|
*
|
||||||
|
* @param Response|Server $server
|
||||||
|
* @param Request $request
|
||||||
|
*/
|
||||||
|
public function onOpen($server, Request $request): void
|
||||||
{
|
{
|
||||||
$producer = container()->get(Producer::class);
|
$token = $request->get['token'] ?? '';
|
||||||
|
$userInfo = $this->jwt->getParserData($token);
|
||||||
|
stdout_log()->info("用户连接信息 : user_id:{$userInfo['user_id']} | fd:{$request->fd} | data:" . Json::encode($userInfo));
|
||||||
|
|
||||||
|
// 绑定fd与用户关系
|
||||||
|
$this->socketFDService->bindRelation($request->fd, $userInfo['user_id']);
|
||||||
|
|
||||||
$ip = config('ip_address');
|
$ip = config('ip_address');
|
||||||
|
$server->push($request->fd, "成功连接[{$ip}],IM 服务器");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息接收回调事件
|
||||||
|
*
|
||||||
|
* @param Response|Server $server
|
||||||
|
* @param Frame $frame
|
||||||
|
*/
|
||||||
|
public function onMessage($server, Frame $frame): void
|
||||||
|
{
|
||||||
|
$ip = config('ip_address');
|
||||||
|
$producer = container()->get(Producer::class);
|
||||||
$producer->produce(new ChatMessageProducer("我是来自[{$ip} 服务器的消息],{$frame->data}"));
|
$producer->produce(new ChatMessageProducer("我是来自[{$ip} 服务器的消息],{$frame->data}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接创建成功回调事件
|
||||||
|
*
|
||||||
|
* @param Response|\Swoole\Server $server
|
||||||
|
* @param int $fd
|
||||||
|
* @param int $reactorId
|
||||||
|
*/
|
||||||
public function onClose($server, int $fd, int $reactorId): void
|
public function onClose($server, int $fd, int $reactorId): void
|
||||||
{
|
{
|
||||||
|
// 解除fd关系
|
||||||
|
$this->socketFDService->removeRelation($fd);
|
||||||
echo PHP_EOL . "FD : 【{$fd}】 已断开...";
|
echo PHP_EOL . "FD : 【{$fd}】 已断开...";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onOpen($server, Request $request): void
|
|
||||||
{
|
|
||||||
$ip = config('ip_address');
|
|
||||||
$server->push($request->fd, "成功连接[{$ip}],IM 服务器");
|
|
||||||
echo PHP_EOL."FD : 【{$request->fd}】 成功连接...";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Middleware;
|
||||||
|
|
||||||
|
use Phper666\JWTAuth\JWT;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
|
||||||
|
class WebSocketAuthMiddleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ContainerInterface
|
||||||
|
*/
|
||||||
|
protected $container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inject
|
||||||
|
* @var JWT
|
||||||
|
*/
|
||||||
|
private $jwt;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
|
{
|
||||||
|
// 授权验证拦截握手请求并实现权限检查
|
||||||
|
$token = $request->getQueryParams()['token'] ?? '';
|
||||||
|
try {
|
||||||
|
$this->jwt->checkToken($token);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->container->get(\Hyperf\HttpServer\Contract\ResponseInterface::class)->raw('Forbidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $handler->handle($request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,169 @@
|
||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Model\Chat\ChatRecord;
|
||||||
|
use App\Model\Chat\ChatRecordsFile;
|
||||||
|
use App\Model\EmoticonDetail;
|
||||||
|
use App\Model\Group\UsersGroup;
|
||||||
|
use App\Model\UsersEmoticon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表情服务层
|
||||||
|
*
|
||||||
|
* Class EmoticonService
|
||||||
|
* @package App\Services
|
||||||
|
*/
|
||||||
class EmoticonService extends BaseService
|
class EmoticonService extends BaseService
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* 安装系统表情包
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param int $emoticon_id 表情包ID
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function installSysEmoticon(int $user_id, int $emoticon_id)
|
||||||
|
{
|
||||||
|
$info = UsersEmoticon::select(['id', 'user_id', 'emoticon_ids'])->where('user_id', $user_id)->first();
|
||||||
|
if (!$info) {
|
||||||
|
return UsersEmoticon::create(['user_id' => $user_id, 'emoticon_ids' => $emoticon_id]) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$emoticon_ids = $info->emoticon_ids;
|
||||||
|
if (in_array($emoticon_id, $emoticon_ids)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$emoticon_ids[] = $emoticon_id;
|
||||||
|
return UsersEmoticon::where('user_id', $user_id)->update([
|
||||||
|
'emoticon_ids' => implode(',', $emoticon_ids)
|
||||||
|
]) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除已安装的系统表情包
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param int $emoticon_id 表情包ID
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function removeSysEmoticon(int $user_id, int $emoticon_id)
|
||||||
|
{
|
||||||
|
$info = UsersEmoticon::select(['id', 'user_id', 'emoticon_ids'])->where('user_id', $user_id)->first();
|
||||||
|
if (!$info || !in_array($emoticon_id, $info->emoticon_ids)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$emoticon_ids = $info->emoticon_ids;
|
||||||
|
foreach ($emoticon_ids as $k => $id) {
|
||||||
|
if ($id == $emoticon_id) {
|
||||||
|
unset($emoticon_ids[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($info->emoticon_ids) == count($emoticon_ids)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UsersEmoticon::where('user_id', $user_id)->update([
|
||||||
|
'emoticon_ids' => implode(',', $emoticon_ids)
|
||||||
|
]) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户安装的表情ID
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getInstallIds(int $user_id)
|
||||||
|
{
|
||||||
|
$result = UsersEmoticon::where('user_id', $user_id)->value('emoticon_ids');
|
||||||
|
return $result ? explode(',', $result) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收藏聊天图片
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param int $record_id 聊天消息ID
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function collect(int $user_id, int $record_id)
|
||||||
|
{
|
||||||
|
$result = ChatRecord::where([
|
||||||
|
['id', '=', $record_id],
|
||||||
|
['msg_type', '=', 2],
|
||||||
|
['is_revoke', '=', 0],
|
||||||
|
])->first(['id', 'source', 'msg_type', 'user_id', 'receive_id', 'is_revoke']);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
return [false, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result->source == 1) {
|
||||||
|
if ($result->user_id != $user_id && $result->receive_id != $user_id) {
|
||||||
|
return [false, []];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!UsersGroup::isMember($result->receive_id, $user_id)) {
|
||||||
|
return [false, []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileInfo = ChatRecordsFile::where('record_id', $result->id)->where('file_type', 1)->first([
|
||||||
|
'file_suffix',
|
||||||
|
'file_size',
|
||||||
|
'save_dir'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$fileInfo) {
|
||||||
|
return [false, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$result = EmoticonDetail::where('user_id', $user_id)->where('url', $fileInfo->save_dir)->first();
|
||||||
|
if ($result) {
|
||||||
|
return [false, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = EmoticonDetail::create([
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'url' => $fileInfo->save_dir,
|
||||||
|
'file_suffix' => $fileInfo->file_suffix,
|
||||||
|
'file_size' => $fileInfo->file_size,
|
||||||
|
'created_at' => time()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $res ? [true, ['media_id' => $res->id, 'src' => get_media_url($res->url)]] : [false, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除收藏的表情包
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param array $ids 表情包详情ID
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public function deleteCollect(int $user_id, array $ids)
|
||||||
|
{
|
||||||
|
return EmoticonDetail::whereIn('id', $ids)->where('user_id', $user_id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取表情包列表
|
||||||
|
*
|
||||||
|
* @param array $where
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getDetailsAll(array $where = [])
|
||||||
|
{
|
||||||
|
$list = EmoticonDetail::where($where)->get(['id as media_id', 'url as src'])->toArray();
|
||||||
|
|
||||||
|
foreach ($list as $k => $value) {
|
||||||
|
$list[$k]['src'] = get_media_url($value['src']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Hyperf\Redis\Redis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Socket客户端ID服务
|
||||||
|
*
|
||||||
|
* @package App\Service
|
||||||
|
*/
|
||||||
|
class SocketFDService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* fd与用户绑定(使用hash 做处理)
|
||||||
|
*/
|
||||||
|
const BIND_FD_TO_USER = 'socket:fd:user';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用集合做处理
|
||||||
|
*/
|
||||||
|
const BIND_USER_TO_FDS = 'socket:user:fds';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inject
|
||||||
|
* @var Redis
|
||||||
|
*/
|
||||||
|
private $redis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端fd与用户ID绑定关系
|
||||||
|
*
|
||||||
|
* @param int $fd 客户端fd
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param string $run_id 服务运行ID(默认当前服务ID)
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function bindRelation(int $fd, int $user_id, $run_id = SERVER_RUN_ID)
|
||||||
|
{
|
||||||
|
$this->redis->multi();
|
||||||
|
$this->redis->hSet(sprintf('%s:%s', self::BIND_FD_TO_USER, $run_id), (string)$fd, (string)$user_id);
|
||||||
|
$this->redis->sadd(sprintf('%s:%s:%s', self::BIND_USER_TO_FDS, $run_id, $user_id), $fd);
|
||||||
|
$this->redis->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解除指定的客户端fd与用户绑定关系
|
||||||
|
*
|
||||||
|
* @param int $fd 客户端ID
|
||||||
|
* @param string $run_id 服务运行ID(默认当前服务ID)
|
||||||
|
*/
|
||||||
|
public function removeRelation(int $fd, $run_id = SERVER_RUN_ID)
|
||||||
|
{
|
||||||
|
$user_id = $this->findFdUserId($fd) | 0;
|
||||||
|
|
||||||
|
$this->redis->hdel(sprintf('%s:%s', self::BIND_FD_TO_USER, $run_id), (string)$fd);
|
||||||
|
$this->redis->srem(sprintf('%s:%s:%s', self::BIND_USER_TO_FDS, $run_id, $user_id), $fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测用户当前是否在线
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param string $run_id 服务运行ID(默认当前服务ID)
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isOnline(int $user_id, $run_id = SERVER_RUN_ID): bool
|
||||||
|
{
|
||||||
|
return $this->redis->scard(sprintf('%s:%s:%s', self::BIND_USER_TO_FDS, $run_id, $user_id)) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询客户端fd对应的用户ID
|
||||||
|
*
|
||||||
|
* @param int $fd 客户端ID
|
||||||
|
* @param string $run_id 服务运行ID(默认当前服务ID)
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function findFdUserId(int $fd, $run_id = SERVER_RUN_ID)
|
||||||
|
{
|
||||||
|
return $this->redis->hget(sprintf('%s:%s', self::BIND_FD_TO_USER, $run_id), (string)$fd) ?: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户的客户端fd集合(用户可能存在多端登录)
|
||||||
|
*
|
||||||
|
* @param int $user_id 用户ID
|
||||||
|
* @param string $run_id 服务运行ID(默认当前服务ID)
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function findUserFds(int $user_id, $run_id = SERVER_RUN_ID)
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除绑定缓存的信息
|
||||||
|
*
|
||||||
|
* @param string $run_id 服务运行ID(默认当前服务ID)
|
||||||
|
*/
|
||||||
|
public function removeRedisCache($run_id = SERVER_RUN_ID)
|
||||||
|
{
|
||||||
|
$this->redis->del(self::BIND_FD_TO_USER);
|
||||||
|
$prefix = self::BIND_USER_TO_FDS;
|
||||||
|
$iterator = null;
|
||||||
|
while (true) {
|
||||||
|
$keys = $this->redis->scan($iterator, "{$prefix}*");
|
||||||
|
if ($keys === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!empty($keys)) {
|
||||||
|
$this->redis->del(...$keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,13 +31,13 @@ class RedisLock
|
||||||
*
|
*
|
||||||
* @param string $key 缓存KEY
|
* @param string $key 缓存KEY
|
||||||
* @param string $requestId 客户端请求唯一ID
|
* @param string $requestId 客户端请求唯一ID
|
||||||
* @param int $lockSecond 锁定时间 单位(秒)
|
* @param integer $lockSecond 锁定时间 单位(秒)
|
||||||
* @param int $timeout 取锁超时时间。单位(秒)。等于0,如果当前锁被占用,则立即返回失败。如果大于0,则反复尝试获取锁直到达到该超时时间。
|
* @param integer $timeout 取锁超时时间。单位(秒)。等于0,如果当前锁被占用,则立即返回失败。如果大于0,则反复尝试获取锁直到达到该超时时间。
|
||||||
* @param int $sleep 取锁间隔时间 单位(微秒)。当锁为占用状态时。每隔多久尝试去取锁。默认 0.1 秒一次取锁。
|
* @param integer|float $sleep 取锁间隔时间 单位(秒)。当锁为占用状态时。每隔多久尝试去取锁。默认 0.1 秒一次取锁。
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function lock(string $key, string $requestId, $lockSecond = 20, $timeout = 0, $sleep = 100000)
|
public static function lock(string $key, string $requestId, $lockSecond = 20, $timeout = 0, $sleep = 0.1)
|
||||||
{
|
{
|
||||||
if (empty($key)) {
|
if (empty($key)) {
|
||||||
throw new \Exception('获取锁的KEY值没有设置');
|
throw new \Exception('获取锁的KEY值没有设置');
|
||||||
|
@ -56,7 +56,7 @@ class RedisLock
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep($sleep);
|
\Swoole\Coroutine\System::sleep($sleep);
|
||||||
} while (!is_numeric($timeout) || (self::getMicroTime()) < ($start + ($timeout * 1000000)));
|
} while (!is_numeric($timeout) || (self::getMicroTime()) < ($start + ($timeout * 1000000)));
|
||||||
|
|
||||||
return $acquired ? true : false;
|
return $acquired ? true : false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Support\Http;
|
namespace App\Support;
|
||||||
|
|
||||||
use Hyperf\Di\Annotation\Inject;
|
use Hyperf\Di\Annotation\Inject;
|
||||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
use Hyperf\HttpServer\Contract\ResponseInterface;
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait WebSocketTrait
|
||||||
|
*
|
||||||
|
* @package App\Traits
|
||||||
|
*/
|
||||||
|
trait WebSocketTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 聊天记录回调事件
|
||||||
|
*/
|
||||||
|
public function onTalk()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 键盘输入回调事件
|
||||||
|
*/
|
||||||
|
public function onInput()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
use Hyperf\Contract\StdoutLoggerInterface;
|
use Hyperf\Contract\StdoutLoggerInterface;
|
||||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||||
use Hyperf\Logger\LoggerFactory;
|
use Hyperf\Logger\LoggerFactory;
|
||||||
|
@ -9,108 +8,89 @@ use Hyperf\Utils\ApplicationContext;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Swoole\Websocket\Frame;
|
use Swoole\Websocket\Frame;
|
||||||
use Swoole\WebSocket\Server as WebSocketServer;
|
use Swoole\WebSocket\Server as WebSocketServer;
|
||||||
|
use Hyperf\Utils\Str;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 容器实例
|
* 容器实例
|
||||||
*/
|
*/
|
||||||
if (!function_exists('container')) {
|
|
||||||
function container()
|
function container()
|
||||||
{
|
{
|
||||||
return ApplicationContext::getContainer();
|
return ApplicationContext::getContainer();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redis 客户端实例
|
* Redis 客户端实例
|
||||||
*/
|
*/
|
||||||
if (!function_exists('redis')) {
|
|
||||||
function redis()
|
function redis()
|
||||||
{
|
{
|
||||||
return container()->get(Redis::class);
|
return container()->get(Redis::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* server 实例 基于 swoole server
|
* server 实例 基于 swoole server
|
||||||
*/
|
*/
|
||||||
if (!function_exists('server')) {
|
|
||||||
function server()
|
function server()
|
||||||
{
|
{
|
||||||
return container()->get(ServerFactory::class)->getServer()->getServer();
|
return container()->get(ServerFactory::class)->getServer()->getServer();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* websocket frame 实例
|
* websocket frame 实例
|
||||||
*/
|
*/
|
||||||
if (!function_exists('frame')) {
|
|
||||||
function frame()
|
function frame()
|
||||||
{
|
{
|
||||||
return container()->get(Frame::class);
|
return container()->get(Frame::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* websocket 实例
|
* websocket 实例
|
||||||
*/
|
*/
|
||||||
if (!function_exists('websocket')) {
|
|
||||||
function websocket()
|
function websocket()
|
||||||
{
|
{
|
||||||
return container()->get(WebSocketServer::class);
|
return container()->get(WebSocketServer::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存实例 简单的缓存
|
* 缓存实例 简单的缓存
|
||||||
*/
|
*/
|
||||||
if (!function_exists('cache')) {
|
|
||||||
function cache()
|
function cache()
|
||||||
{
|
{
|
||||||
return container()->get(Psr\SimpleCache\CacheInterface::class);
|
return container()->get(Psr\SimpleCache\CacheInterface::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制台日志
|
* 控制台日志
|
||||||
*/
|
*/
|
||||||
if (!function_exists('stdLog')) {
|
function stdout_log()
|
||||||
function stdLog()
|
|
||||||
{
|
{
|
||||||
return container()->get(StdoutLoggerInterface::class);
|
return container()->get(StdoutLoggerInterface::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件日志
|
* 文件日志
|
||||||
*/
|
*/
|
||||||
if (!function_exists('logger')) {
|
|
||||||
function logger(string $name = 'APP')
|
function logger(string $name = 'APP')
|
||||||
{
|
{
|
||||||
return container()->get(LoggerFactory::class)->get($name);
|
return container()->get(LoggerFactory::class)->get($name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* http 请求实例
|
* http 请求实例
|
||||||
*/
|
*/
|
||||||
if (!function_exists('request')) {
|
|
||||||
function request()
|
function request()
|
||||||
{
|
{
|
||||||
return container()->get(ServerRequestInterface::class);
|
return container()->get(ServerRequestInterface::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求响应
|
* 请求响应
|
||||||
*/
|
*/
|
||||||
if (!function_exists('response')) {
|
|
||||||
function response()
|
function response()
|
||||||
{
|
{
|
||||||
return container()->get(ResponseInterface::class);
|
return container()->get(ResponseInterface::class);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取加密后的密码字符
|
* 获取加密后的密码字符
|
||||||
|
@ -118,7 +98,8 @@ if (!function_exists('response')) {
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @return bool|false|null|string
|
* @return bool|false|null|string
|
||||||
*/
|
*/
|
||||||
function create_password(string $password){
|
function create_password(string $password)
|
||||||
|
{
|
||||||
return password_hash($password, PASSWORD_DEFAULT);
|
return password_hash($password, PASSWORD_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,3 +141,28 @@ function diff_date($day1, $day2)
|
||||||
|
|
||||||
return ceil(($second1 - $second2) / 86400);
|
return ceil(($second1 - $second2) / 86400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取媒体文件url
|
||||||
|
*
|
||||||
|
* @param string $path 文件相对路径
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function get_media_url(string $path)
|
||||||
|
{
|
||||||
|
return '/' . $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机生成图片名
|
||||||
|
*
|
||||||
|
* @param string $ext 图片后缀名
|
||||||
|
* @param int $width 图片宽度
|
||||||
|
* @param int $height 图片高度
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function create_image_name(string $ext, int $width, int $height)
|
||||||
|
{
|
||||||
|
return uniqid() . Str::random(18) . uniqid() . '_' . $width . 'x' . $height . '.' . $ext;
|
||||||
|
}
|
|
@ -12,8 +12,6 @@ date_default_timezone_set('Asia/Shanghai');
|
||||||
|
|
||||||
require BASE_PATH . '/vendor/autoload.php';
|
require BASE_PATH . '/vendor/autoload.php';
|
||||||
|
|
||||||
echo gethostbyname(null);
|
|
||||||
|
|
||||||
// Self-called anonymous function that creates its own scope and keep the global namespace clean.
|
// Self-called anonymous function that creates its own scope and keep the global namespace clean.
|
||||||
(function () {
|
(function () {
|
||||||
Hyperf\Di\ClassLoader::init();
|
Hyperf\Di\ClassLoader::init();
|
||||||
|
|
|
@ -31,7 +31,10 @@
|
||||||
"hyperf/websocket-server": "^2.0",
|
"hyperf/websocket-server": "^2.0",
|
||||||
"hyperf/constants": "^2.0",
|
"hyperf/constants": "^2.0",
|
||||||
"hyperf/validation": "^2.0",
|
"hyperf/validation": "^2.0",
|
||||||
"phper666/jwt-auth": "^3.0"
|
"phper666/jwt-auth": "^3.0",
|
||||||
|
"hyperf/filesystem": "^2.0",
|
||||||
|
"hyperf/socketio-server": "^2.0",
|
||||||
|
"hashids/hashids": "^4.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"swoole/ide-helper": "^4.5",
|
"swoole/ide-helper": "^4.5",
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?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' => 'local',
|
||||||
|
'storage' => [
|
||||||
|
'local' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\LocalAdapterFactory::class,
|
||||||
|
'root' => __DIR__ . '/../../runtime',
|
||||||
|
],
|
||||||
|
'ftp' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\FtpAdapterFactory::class,
|
||||||
|
'host' => 'ftp.example.com',
|
||||||
|
'username' => 'username',
|
||||||
|
'password' => 'password',
|
||||||
|
// 'port' => 21,
|
||||||
|
// 'root' => '/path/to/root',
|
||||||
|
// 'passive' => true,
|
||||||
|
// 'ssl' => true,
|
||||||
|
// 'timeout' => 30,
|
||||||
|
// 'ignorePassiveAddress' => false,
|
||||||
|
],
|
||||||
|
'memory' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\MemoryAdapterFactory::class,
|
||||||
|
],
|
||||||
|
's3' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
|
||||||
|
'credentials' => [
|
||||||
|
'key' => env('S3_KEY'),
|
||||||
|
'secret' => env('S3_SECRET'),
|
||||||
|
],
|
||||||
|
'region' => env('S3_REGION'),
|
||||||
|
'version' => 'latest',
|
||||||
|
'bucket_endpoint' => false,
|
||||||
|
'use_path_style_endpoint' => false,
|
||||||
|
'endpoint' => env('S3_ENDPOINT'),
|
||||||
|
'bucket_name' => env('S3_BUCKET'),
|
||||||
|
],
|
||||||
|
'minio' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
|
||||||
|
'credentials' => [
|
||||||
|
'key' => env('S3_KEY'),
|
||||||
|
'secret' => env('S3_SECRET'),
|
||||||
|
],
|
||||||
|
'region' => env('S3_REGION'),
|
||||||
|
'version' => 'latest',
|
||||||
|
'bucket_endpoint' => false,
|
||||||
|
'use_path_style_endpoint' => true,
|
||||||
|
'endpoint' => env('S3_ENDPOINT'),
|
||||||
|
'bucket_name' => env('S3_BUCKET'),
|
||||||
|
],
|
||||||
|
'oss' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\AliyunOssAdapterFactory::class,
|
||||||
|
'accessId' => env('OSS_ACCESS_ID'),
|
||||||
|
'accessSecret' => env('OSS_ACCESS_SECRET'),
|
||||||
|
'bucket' => env('OSS_BUCKET'),
|
||||||
|
'endpoint' => env('OSS_ENDPOINT'),
|
||||||
|
// 'timeout' => 3600,
|
||||||
|
// 'connectTimeout' => 10,
|
||||||
|
// 'isCName' => false,
|
||||||
|
// 'token' => '',
|
||||||
|
],
|
||||||
|
'qiniu' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\QiniuAdapterFactory::class,
|
||||||
|
'accessKey' => env('QINIU_ACCESS_KEY'),
|
||||||
|
'secretKey' => env('QINIU_SECRET_KEY'),
|
||||||
|
'bucket' => env('QINIU_BUCKET'),
|
||||||
|
'domain' => env('QINBIU_DOMAIN'),
|
||||||
|
],
|
||||||
|
'cos' => [
|
||||||
|
'driver' => \Hyperf\Filesystem\Adapter\CosAdapterFactory::class,
|
||||||
|
'region' => env('COS_REGION'),
|
||||||
|
'credentials' => [
|
||||||
|
'appId' => env('COS_APPID'),
|
||||||
|
'secretId' => env('COS_SECRET_ID'),
|
||||||
|
'secretKey' => env('COS_SECRET_KEY'),
|
||||||
|
],
|
||||||
|
'bucket' => env('COS_BUCKET'),
|
||||||
|
'read_from_cdn' => false,
|
||||||
|
// 'timeout' => 60,
|
||||||
|
// 'connect_timeout' => 60,
|
||||||
|
// 'cdn' => '',
|
||||||
|
// 'scheme' => 'https',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of Hyperf.
|
* This file is part of Hyperf.
|
||||||
*
|
*
|
||||||
|
@ -9,8 +10,15 @@ declare(strict_types=1);
|
||||||
* @contact group@hyperf.io
|
* @contact group@hyperf.io
|
||||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use App\Middleware\CorsMiddleware;
|
||||||
|
use App\Middleware\WebSocketAuthMiddleware;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'http' => [
|
'http' => [
|
||||||
|
CorsMiddleware::class
|
||||||
],
|
],
|
||||||
|
'ws' => [
|
||||||
|
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
|
@ -32,6 +32,7 @@ return [
|
||||||
'port' => 9504,
|
'port' => 9504,
|
||||||
'sock_type' => SWOOLE_SOCK_TCP,
|
'sock_type' => SWOOLE_SOCK_TCP,
|
||||||
'callbacks' => [
|
'callbacks' => [
|
||||||
|
// 自定义握手处理
|
||||||
SwooleEvent::ON_HAND_SHAKE => [Hyperf\WebSocketServer\Server::class, 'onHandShake'],
|
SwooleEvent::ON_HAND_SHAKE => [Hyperf\WebSocketServer\Server::class, 'onHandShake'],
|
||||||
SwooleEvent::ON_MESSAGE => [Hyperf\WebSocketServer\Server::class, 'onMessage'],
|
SwooleEvent::ON_MESSAGE => [Hyperf\WebSocketServer\Server::class, 'onMessage'],
|
||||||
SwooleEvent::ON_CLOSE => [Hyperf\WebSocketServer\Server::class, 'onClose'],
|
SwooleEvent::ON_CLOSE => [Hyperf\WebSocketServer\Server::class, 'onClose'],
|
||||||
|
@ -52,7 +53,7 @@ return [
|
||||||
],
|
],
|
||||||
'callbacks' => [
|
'callbacks' => [
|
||||||
//自定义启动前事件
|
//自定义启动前事件
|
||||||
//SwooleEvent::ON_BEFORE_START => [Hyperf\Framework\Bootstrap\ServerStartCallback::class, 'beforeStart'],
|
SwooleEvent::ON_BEFORE_START => [App\Bootstrap\ServerStart::class, 'beforeStart'],
|
||||||
|
|
||||||
SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
|
SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
|
||||||
SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
|
SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
|
||||||
|
|
|
@ -10,23 +10,19 @@ declare(strict_types=1);
|
||||||
* @contact group@hyperf.io
|
* @contact group@hyperf.io
|
||||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Hyperf\HttpServer\Router\Router;
|
use Hyperf\HttpServer\Router\Router;
|
||||||
use App\Middleware\CorsMiddleware;
|
|
||||||
|
|
||||||
|
|
||||||
Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
|
|
||||||
|
|
||||||
Router::post('/upload', 'App\Controller\IndexController@upload',['middleware' => [CorsMiddleware::class]]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Router::get('/favicon.ico', function () {
|
Router::get('/favicon.ico', function () {
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
|
|
||||||
Router::addServer('ws', function () {
|
// 加载 Http 路由
|
||||||
Router::get('/', 'App\Controller\WebSocketController');
|
Router::addServer('http', function () {
|
||||||
|
require __DIR__ . '/routes/http.php';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载 Websocket 路由
|
||||||
|
Router::addServer('ws', function () {
|
||||||
|
require __DIR__ . '/routes/websocket.php';
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?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
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Hyperf\HttpServer\Router\Router;
|
||||||
|
|
||||||
|
|
||||||
|
Router::get('/', 'App\Controller\IndexController@index');
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?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
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Hyperf\HttpServer\Router\Router;
|
||||||
|
|
||||||
|
|
||||||
|
// 添加 ws 服务对应的路由
|
||||||
|
Router::get('/socket.io', 'App\Controller\WebSocketController', [
|
||||||
|
'middleware' => [\App\Middleware\WebSocketAuthMiddleware::class]
|
||||||
|
]);
|
Loading…
Reference in New Issue