Issues (66)

src/Bot.php (1 issue)

Severity
1
<?php
2
3
namespace PortlandLabs\Slackbot;
4
5
use Carbon\Carbon;
6
use DateTime;
7
use PortlandLabs\Slackbot\Command\Manager;
8
use PortlandLabs\Slackbot\Slack\Api\Client as ApiClient;
9
use PortlandLabs\Slackbot\Slack\ConnectionManager;
10
use PortlandLabs\Slackbot\Slack\Rtm\Client as RtmClient;
11
use PortlandLabs\Slackbot\Slack\Rtm\Event\Middleware\CommandMiddleware;
12
use Psr\Log\LoggerInterface;
13
use React\EventLoop\LoopInterface;
14
use React\EventLoop\TimerInterface;
15
use React\Promise\Deferred;
16
17
class Bot
18
{
19
20
    /** @var TimerInterface[] */
21
    protected $typing = [];
22
23
    /** @var ConnectionManager */
24
    protected $connectionManager;
25
26
    /** @var LoggerInterface */
27
    protected $logger;
28
29
    /** @var LoopInterface */
30
    protected $loop;
31
32
    /** @var Carbon */
33
    protected $connected;
34
35
    /** @var bool */
36
    protected $connecting;
37
38
    /** @var string */
39
    protected $id;
40
41
    /**
42
     * @var string[]
43
     */
44
    protected $eventMiddlewares = [
45
        CommandMiddleware::class
46
    ];
47
48
    protected $commands;
49
50
    public function __construct(
51
        ConnectionManager $connectionManager,
52
        LoggerInterface $logger,
53
        LoopInterface $loop,
54
        Manager $commands)
55
    {
56
        $this->connectionManager = $connectionManager;
57
        $this->logger = $logger;
58
        $this->loop = $loop;
59
        $this->commands = $commands;
60
        $this->id = bin2hex(random_bytes(4));
61
    }
62
63
    /**
64
     * Connect to slack
65
     *
66
     * @return \React\Promise\Promise
67
     * @throws \GuzzleHttp\Exception\GuzzleException
68
     */
69
    public function connect()
70
    {
71
        $promise = $this->connectionManager->connect($this->getLoop(), $this->eventMiddlewares);
72
73
        // Record when we connect
74
        $promise->done(function($result) {
0 ignored issues
show
The parameter $result is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

74
        $promise->done(function(/** @scrutinizer ignore-unused */ $result) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
75
            $this->connecting = false;
76
            $this->connected = Carbon::now();
77
        });
78
79
        return $promise;
80
    }
81
82
    /**
83
     * Run the bot
84
     *
85
     * This method must be called in order to start running the bot
86
     */
87
    public function run()
88
    {
89
        if (!$this->connected && !$this->connecting) {
90
            $this->connect();
91
        }
92
93
        $this->loop->run();
94
    }
95
96
    /**
97
     * Stop a running bot
98
     */
99
    public function stop()
100
    {
101
        $this->rtm()->disconnect();
102
        $this->loop->stop();
103
    }
104
105
    /**
106
     * Get the API client
107
     *
108
     * @return ApiClient
109
     */
110
    public function api(): ApiClient
111
    {
112
        return $this->connectionManager->getApiClient();
113
    }
114
115
    /**
116
     * Get the RTM client
117
     *
118
     * @return RtmClient
119
     */
120
    public function rtm(): RtmClient
121
    {
122
        return $this->connectionManager->getRtmClient();
123
    }
124
125
    /**
126
     * Get the command manager
127
     *
128
     * @return Manager
129
     */
130
    public function commands(): Manager
131
    {
132
        return $this->commands;
133
    }
134
135
    /**
136
     * Get our Logger
137
     *
138
     * @return LoggerInterface
139
     */
140
    public function logger(): LoggerInterface
141
    {
142
        return $this->logger;
143
    }
144
145
    /**
146
     * Get the event loop that is powering RTM
147
     *
148
     * @return LoopInterface
149
     */
150
    public function getLoop(): LoopInterface
151
    {
152
        return $this->loop;
153
    }
154
155
    /**
156
     * Get the datetime for when we connected
157
     *
158
     * @return DateTime
159
     */
160
    public function getConnectedTime(): Carbon
161
    {
162
        return $this->connected;
163
    }
164
165
    /**
166
     * Get the bot ID
167
     *
168
     * @return string
169
     */
170
    public function getId(): string
171
    {
172
        return $this->id;
173
    }
174
175
    /**
176
     * Pretend to type
177
     *
178
     * @param string $channel
179
     * @param string $message
180
     * @param float $duration
181
     *
182
     * @return \React\Promise\Promise|\React\Promise\Promise
183
     */
184
    public function feignTyping(string $channel, string $message = null, float $duration = .1)
185
    {
186
        $deferred = new Deferred();
187
        $duration = max(0, $duration);
188
189
        $this->logger->info('[<bold>BOT.TYP</bold>] Beginning to type');
190
191
        if ($duration) {
192
            $this->rtm()->typing($channel);
193
            $this->getLoop()->addTimer($duration, function () use ($channel, $message, $deferred) {
194
                if ($message) {
195
                    $this->rtm()
196
                        ->sendMessage($message, $channel)
197
                        ->done(function (array $result) use ($deferred) {
198
                            $this->logger->info('[<bold>BOT.TYP</bold>] Done Typing');
199
                            $deferred->resolve($result);
200
                        });
201
                } else {
202
                    $deferred->resolve();
203
                }
204
            });
205
        }
206
207
        return $deferred->promise();
208
    }
209
210
    /**
211
     * Get a string representing how long we've been up
212
     *
213
     * @param DateTime|null $now
214
     *
215
     * @return string
216
     */
217
    public function getUptime(DateTime $now = null): string
218
    {
219
        if (!$now) {
220
            $now = Carbon::now();
221
        }
222
223
        $diffString = $this->connected->diffForHumans($now, true, false, 6);
224
225
        // Return the time string with "and" between the last two segments
226
        return preg_replace('/(\d+ \D+?) (\d+ \D+?)$/', '$1 and $2', $diffString);
227
    }
228
}
229