-
Notifications
You must be signed in to change notification settings - Fork 0
/
Guild.php
176 lines (144 loc) · 4.8 KB
/
Guild.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<?php
namespace App\Libs\Guild;
use App\Jobs\GuildMessage;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Redis;
use WebSocket\Client;
use WebSocket\Connection;
use WebSocket\Message\Message;
use WebSocket\Middleware\PingResponder;
class Guild
{
private $qqGuildUrl = '';
private $token = '';
private $guzzleOptions = [];
private $s = '';
private $session_id = '';
private $time0 = 0;
private $seconds = 0;
public function __construct(String $qqGuildUrl, String $token, Array $guzzleOptions)
{
set_time_limit(0);
ini_set('memory_limit','-1');
$this->qqGuildUrl = $qqGuildUrl;
$this->token = $token;
$this->guzzleOptions = $guzzleOptions;
}
/**
* @param $token
* @return mixed
* 获取Gateway
*/
private function getGateway(String $token): string
{
$response = $this->constructHttp($token)->get($this->constructUrl('/gateway'));
return $response['url'];
}
/**
* @param String $uri
* @return string
* 构造请求URL
*/
private function constructUrl(String $uri): string
{
return $this->qqGuildUrl.$uri;
}
/**
* @param String $token
* @return \Illuminate\Http\Client\PendingRequest
* 构造HTTP请求
*/
private function constructHttp(String $token): \Illuminate\Http\Client\PendingRequest
{
return Http::withOptions($this->guzzleOptions)->withHeaders(['Authorization'=>$token]);
}
/**
* @param String $token
* @param Client $client
* @return String
* WS身份验证,返回SessionID
*/
private function identify(String $token, Client $client): string
{
$data = [
'op' => 2,
'd' => [
'token' => $token,
'intents' => 2081166851,
// 'shard' => [0, 1],
'properties' => []
]
];
$client->text(json_encode($data));
$receive = $client->receive()->getContent();
//var_dump($receive);
return json_decode($receive,1)['d']['session_id'];
}
/**
* 建立WS连接
*/
public function connect()
{
//获取WS连接路径
$gateway = $this->getGateway($this->token);
//创建连接
$this->s = '';
$client = new Client($gateway);
//获取心跳间隔
$this->seconds = intval($this->getHeartBeat($client));
//身份鉴权
$this->session_id = $this->identify($this->token, $client);
//首次心跳
$this->time0 = time();
$client->text(json_encode(['op'=>1, 'd'=>null]));
//消息监听
$client
->setTimeout($this->seconds)
// Add standard middlewares
->addMiddleware(new PingResponder())
// Listen to incoming Text messages
->onText(function (Client $client, Connection $connection, Message $message) {
//接收消息
$receive = $message->getContent();
//将消息转换为数组
$receiveArr =json_decode($receive, 1);
//如果op存在
if (isset($receiveArr['op'])){
//排除心跳pong
//if($receiveArr['op']!=11){}
//如果是服务端推送,将消息派发到队列处理
if($receiveArr['op']==0){
GuildMessage::dispatch($this->qqGuildUrl, $this->token, $this->guzzleOptions, $receiveArr);
}
//如果服务端通知重连
if($receiveArr['op'] == 7){
$client->text(json_encode(['op'=>6, 'd'=>['token'=>$this->token, 'session_id'=>$this->session_id, 's'=>Redis::get('s')]]));
}
}
})
->onTick(function (Client $client){
//检测是否到心跳时间
$time1 = time();
if($time1 - $this->time0 > $this->seconds - 20){
$client->text(json_encode(['op'=>1, 'd'=>Redis::get('s')]));
$this->time0 = $time1;
//Storage::append('heart.log',$time1);
}
})
->onError(function (Client $client){
//重新连接
$client->text(json_encode(['op'=>6, 'd'=>['token'=>$this->token, 'session_id'=>$this->session_id, 's'=>$this->s]]));
})
->start();
}
/**
* @param $client
* @return float
* 获得心跳时间
*/
public function getHeartBeat($client){
$receive = $client->receive()->getContent();
$initReceive = json_decode($receive,1);
return floor($initReceive['d']['heartbeat_interval']/1000);
}
}