1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Zanzara; |
6
|
|
|
|
7
|
|
|
use Clue\React\Buzz\Browser; |
8
|
|
|
use Clue\React\HttpProxy\ProxyConnector; |
9
|
|
|
use DI\Container; |
10
|
|
|
use Psr\Log\LoggerInterface; |
11
|
|
|
use React\Cache\ArrayCache; |
12
|
|
|
use React\Cache\CacheInterface; |
13
|
|
|
use React\EventLoop\Factory; |
14
|
|
|
use React\EventLoop\LoopInterface; |
15
|
|
|
use React\Filesystem\Filesystem; |
16
|
|
|
use React\Http\Server; |
17
|
|
|
use React\Promise\PromiseInterface; |
18
|
|
|
use React\Socket\Connector; |
19
|
|
|
use Zanzara\Listener\ListenerResolver; |
20
|
|
|
use Zanzara\Telegram\Telegram; |
21
|
|
|
use Zanzara\UpdateMode\ReactPHPWebhook; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* |
25
|
|
|
*/ |
26
|
|
|
class Zanzara extends ListenerResolver |
27
|
|
|
{ |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var Config |
31
|
|
|
*/ |
32
|
|
|
private $config; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var Telegram |
36
|
|
|
*/ |
37
|
|
|
private $telegram; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var LoopInterface |
41
|
|
|
*/ |
42
|
|
|
private $loop; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @param string $botToken |
46
|
|
|
* @param Config|null $config |
47
|
|
|
*/ |
48
|
|
|
public function __construct(string $botToken, ?Config $config = null) |
49
|
|
|
{ |
50
|
|
|
$this->config = $config ?? new Config(); |
51
|
|
|
$this->config->setBotToken($botToken); |
52
|
|
|
$this->container = $this->config->getContainer() ?? new Container(); |
53
|
|
|
$this->loop = $this->config->getLoop() ?? Factory::create(); |
54
|
|
|
$this->container->set(LoopInterface::class, $this->loop); // loop cannot be created by container |
55
|
|
|
$this->container->set(LoggerInterface::class, $this->config->getLogger()); |
56
|
|
|
$connector = $this->config->getConnector(); |
57
|
|
|
$connectorOptions = $this->config->getConnectorOptions(); |
58
|
|
|
$proxyUrl = $this->config->getProxyUrl(); |
59
|
|
|
$proxyHttpHeaders = $this->config->getProxyHttpHeaders(); |
60
|
|
|
if (!$connector && ($connectorOptions || $proxyUrl || $proxyHttpHeaders)) { |
|
|
|
|
61
|
|
|
if ($proxyUrl) { |
62
|
|
|
$proxy = new ProxyConnector($proxyUrl, new Connector($this->loop), $proxyHttpHeaders); |
63
|
|
|
$connectorOptions['tcp'] = $proxy; |
64
|
|
|
} |
65
|
|
|
$connector = new Connector($this->loop, $connectorOptions); |
66
|
|
|
$this->config->setConnector($connector); |
67
|
|
|
} |
68
|
|
|
$this->container->set(Browser::class, (new Browser($this->loop, $this->config->getConnector())) // browser cannot be created by container |
69
|
|
|
->withBase("{$this->config->getApiTelegramUrl()}/bot{$botToken}")); |
70
|
|
|
$this->telegram = $this->container->get(Telegram::class); |
71
|
|
|
$this->container->set(CacheInterface::class, $this->config->getCache() ?? new ArrayCache()); |
72
|
|
|
$this->container->set(Config::class, $this->config); |
73
|
|
|
if ($this->config->isReactFileSystem()) { |
74
|
|
|
$this->container->set(Filesystem::class, Filesystem::create($this->loop)); |
75
|
|
|
} |
76
|
|
|
$this->cache = $this->container->get(ZanzaraCache::class); |
77
|
|
|
$this->container->set(Zanzara::class, $this); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
public function run(): void |
81
|
|
|
{ |
82
|
|
|
$this->feedMiddlewareStack(); |
83
|
|
|
// we set "string|UpdateModeInterface" as return type just to have IDE suggestions, actually it is always a string |
84
|
|
|
$this->container->get(/** @scrutinizer ignore-type */ $this->config->getUpdateMode())->run(); |
85
|
|
|
$this->loop->run(); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* @return Telegram |
90
|
|
|
*/ |
91
|
|
|
public function getTelegram(): Telegram |
92
|
|
|
{ |
93
|
|
|
return $this->telegram; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* @return LoopInterface |
98
|
|
|
*/ |
99
|
|
|
public function getLoop(): LoopInterface |
100
|
|
|
{ |
101
|
|
|
return $this->loop; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @return Server |
106
|
|
|
*/ |
107
|
|
|
public function getServer(): Server |
108
|
|
|
{ |
109
|
|
|
return $this->container->get(ReactPHPWebhook::class)->getServer(); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @return Container |
114
|
|
|
*/ |
115
|
|
|
public function getContainer(): Container |
116
|
|
|
{ |
117
|
|
|
return $this->container; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Sets an item of the global data. |
122
|
|
|
* This cache is not related to any chat or user. |
123
|
|
|
* |
124
|
|
|
* Eg: |
125
|
|
|
* $ctx->setGlobalData('age', 21)->then(function($result) { |
126
|
|
|
* |
127
|
|
|
* }); |
128
|
|
|
* |
129
|
|
|
* @param $key |
130
|
|
|
* @param $data |
131
|
|
|
* @param $ttl |
132
|
|
|
* @return PromiseInterface |
133
|
|
|
*/ |
134
|
|
|
public function setGlobalData($key, $data, $ttl = false) |
135
|
|
|
{ |
136
|
|
|
return $this->cache->setGlobalCacheData($key, $data, $ttl); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Append data to an existing global cache item. The item value is always an array. |
141
|
|
|
* |
142
|
|
|
* Eg: |
143
|
|
|
* $ctx->appendGlobalData('users', ['Mike', 'John'])->then(function($result) { |
144
|
|
|
* |
145
|
|
|
* }); |
146
|
|
|
* |
147
|
|
|
* @param $key |
148
|
|
|
* @param $data |
149
|
|
|
* @param $ttl |
150
|
|
|
* @return PromiseInterface |
151
|
|
|
*/ |
152
|
|
|
public function appendGlobalData($key, $data, $ttl = false): PromiseInterface |
153
|
|
|
{ |
154
|
|
|
return $this->cache->appendGlobalCacheData($key, $data, $ttl); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Returns all the global data. |
159
|
|
|
* This cache is not related to any chat or user. |
160
|
|
|
* |
161
|
|
|
* Eg: |
162
|
|
|
* $ctx->getGlobalData()->then(function($data) { |
163
|
|
|
* $age = $data['age']; |
164
|
|
|
* }); |
165
|
|
|
* |
166
|
|
|
* @return PromiseInterface |
167
|
|
|
*/ |
168
|
|
|
public function getGlobalData() |
169
|
|
|
{ |
170
|
|
|
return $this->cache->getGlobalCacheData(); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Gets an item of the global data. |
175
|
|
|
* This cache is not related to any chat or user. |
176
|
|
|
* |
177
|
|
|
* Eg: |
178
|
|
|
* $ctx->getGlobalDataItem('age')->then(function($age) { |
179
|
|
|
* |
180
|
|
|
* }); |
181
|
|
|
* |
182
|
|
|
* @param $key |
183
|
|
|
* @return PromiseInterface |
184
|
|
|
*/ |
185
|
|
|
public function getGlobalDataItem($key) |
186
|
|
|
{ |
187
|
|
|
return $this->cache->getCacheGlobalDataItem($key); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Deletes an item from the global data. |
192
|
|
|
* This cache is not related to any chat or user. |
193
|
|
|
* |
194
|
|
|
* Eg: |
195
|
|
|
* $ctx->deleteGlobalDataItem('age')->then(function($result) { |
196
|
|
|
* |
197
|
|
|
* }); |
198
|
|
|
* |
199
|
|
|
* @param $key |
200
|
|
|
* @return PromiseInterface |
201
|
|
|
*/ |
202
|
|
|
public function deleteGlobalDataItem($key) |
203
|
|
|
{ |
204
|
|
|
return $this->cache->deleteCacheItemGlobalData($key); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Deletes all global data. |
209
|
|
|
* |
210
|
|
|
* Eg: |
211
|
|
|
* $ctx->deleteGlobalData()->then(function($result) { |
212
|
|
|
* |
213
|
|
|
* }); |
214
|
|
|
* |
215
|
|
|
* @return PromiseInterface |
216
|
|
|
*/ |
217
|
|
|
public function deleteGlobalData() |
218
|
|
|
{ |
219
|
|
|
return $this->cache->deleteCacheGlobalData(); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Wipe entire cache. |
224
|
|
|
* |
225
|
|
|
* @return PromiseInterface |
226
|
|
|
*/ |
227
|
|
|
public function wipeCache() |
228
|
|
|
{ |
229
|
|
|
return $this->cache->wipeCache(); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
} |
233
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.