Completed
Push — develop ( b9ad6f...544074 )
by Kirill
15:05 queued 11s
created

GitterRoomListenCommand::handle()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 0 Features 1
Metric Value
dl 0
loc 23
rs 9.0856
c 7
b 0
f 1
cc 2
eloc 10
nc 1
nop 2
1
<?php
2
namespace App\Console\Commands;
3
4
5
use App\Gitter\ExtensionInterface;
6
use App\Gitter\Middlewares\EloquentQueryBuilderMiddleware;
7
use App\Gitter\Middlewares\GoogleSearchMiddleware;
8
use App\Gitter\MiddlewaresExtension;
9
use App\Message;
10
use App\Room;
11
use App\User;
12
use Carbon\Carbon;
13
use Gitter\Client;
14
use Gitter\Iterators\PromiseIterator\Controls;
15
use Gitter\Models\Message as GitterMessage;
16
use Gitter\Models\Room as GitterRoom;
17
use Gitter\Models\User as GitterUser;
18
use Illuminate\Contracts\Config\Repository;
19
use Illuminate\Contracts\Container\Container;
20
use React\EventLoop\LoopInterface;
21
22
23
/**
24
 * Class GitterRoomListenCommand
25
 * @package App\Console\Commands
26
 *
27
 * Прослушивание сообщений требуемой комнаты
28
 */
29
class GitterRoomListenCommand extends AbstractCommand
30
{
31
    /**
32
     * @var string
33
     */
34
    protected $signature = 'gitter:listen {room}';
35
36
    /**
37
     * @var string
38
     */
39
    protected $description = 'Listen gitter room';
40
41
    /**
42
     * @var array|ExtensionInterface[]
43
     */
44
    protected $extensions = [];
45
46
    /**
47
     * Execute the console command.
48
     *
49
     * @param Repository $config
50
     * @param Container $container
51
     *
52
     * @return mixed
53
     */
54
    public function handle(Repository $config, Container $container)
55
    {
56
        /** @var Client $client */
57
        $client = $this->createClient($container, $config->get('gitter.token'));
58
59
        $this->auth($client, function (User $user) use ($client) {
0 ignored issues
show
Unused Code introduced by
The parameter $user is not used and could be removed.

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

Loading history...
60
61
            $this->findRoom($client, $this->argument('room'), function (GitterRoom $room) {
0 ignored issues
show
Bug introduced by
It seems like $this->argument('room') targeting Illuminate\Console\Command::argument() can also be of type array; however, App\Console\Commands\AbstractCommand::findRoom() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
62
                try {
63
                    $this->listen($room, true);
64
65
                } catch (\Throwable $e) {
66
67
                    $this->error($e->getMessage());
68
                }
69
            });
70
71
        });
72
73
        /** @var LoopInterface $loop */
74
        $loop = $container->make(LoopInterface::class);
75
        $loop->run();
76
    }
77
78
    /**
79
     * @param Client $client
80
     * @param \Closure $callback
81
     */
82
    protected function auth(Client $client, \Closure $callback)
83
    {
84
        GitterUser::current($client)
85
            ->then(function (GitterUser $gitterUser) use ($callback) {
86
                $user = User::make($gitterUser);
87
                \Auth::setUser($user);
88
89
                $callback($user);
90
            });
91
    }
92
93
    /**
94
     * @param GitterRoom $room
95
     * @return array
96
     */
97
    protected function getExtensions(GitterRoom $room)
98
    {
99
        if ($this->extensions === []) {
100
            /**
101
             * Register Middlewares extension
102
             * @var MiddlewaresExtension $middlewares
103
             */
104
            $middlewares = app(MiddlewaresExtension::class, ['room' => $room]);
105
            $middlewares
106
                    ->register(GoogleSearchMiddleware::class)
107
                    ->register(EloquentQueryBuilderMiddleware::class);
108
109
110
            $this->extensions[] = $middlewares;
111
        }
112
113
        return $this->extensions;
114
    }
115
116
    /**
117
     * @param GitterRoom $gitter
118
     * @param bool $startup
119
     * @return $this
120
     */
121
    protected function listen(GitterRoom $gitter, $startup = false)
122
    {
123
        /** @var Room $room */
124
        $room = Room::make($gitter, function (Room $room) {
125
            $this->call('gitter:sync', [
126
                'room'       => $room->gitter_id,
127
                '--users'    => true,
128
                '--messages' => true,
129
            ]);
130
        });
131
132
        $this->getExtensions($gitter);
133
134
        /** @var LoopInterface $loop */
135
        $loop = app(LoopInterface::class);
136
137
        if ($startup) {
138
            $this->info('Fetching last messages...');
139
            $this->onMessageFallback($loop, $gitter, 1);
140
141
            return $this;
142
        }
143
144
        $this->info(sprintf(
145
            'Startup gitter listener for %s at [%s]',
146
            $room->url,
147
            Carbon::now()->toDateTimeString()
148
        ));
149
150
        $gitter->onMessage(function (GitterMessage $msg) {
151
            app(Client::class)->setFallbackMode(false);
152
            $this->onMessage($msg);
153
154
        }, function (\Throwable $e) use ($loop, $gitter) {
155
            $this->error($e->getMessage());
156
            $this->error($e->getFile() . ':' . $e->getLine());
157
            $this->warn('Stream not available. Use message fallback fetch mode.');
158
159
            app(Client::class)->setFallbackMode(true);
160
            $this->onMessageFallback($loop, $gitter);
161
        });
162
163
        return $this;
164
    }
165
166
    /**
167
     * @param LoopInterface $loop
168
     * @param GitterRoom $gitter
169
     * @param int $timeout
170
     */
171
    protected function onMessageFallback(LoopInterface $loop, GitterRoom $gitter, $timeout = 10)
172
    {
173
        /** @var Message $lastMessage */
174
        $lastMessage = Message::where('room_id', $gitter->id)
175
            ->latest('created_at')
176
            ->first();
177
178
        if ($lastMessage) {
179 View Code Duplication
            $loop->addTimer($timeout, function () use ($gitter, $lastMessage) {
0 ignored issues
show
Documentation introduced by
$timeout is of type integer, but the function expects a object<React\EventLoop\numeric>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
                $gitter->getMessages($lastMessage->gitter_id, GitterRoom::MESSAGE_FETCH_ASC)
181
                    ->fetch(function (GitterMessage $message, Controls $controls) {
182
                        $this->onMessage($message);
183
                        $controls->next();
184
                    })
185
                    ->then(function () use ($gitter) {
186
                        $this->warn('Connection...');
187
                        $this->listen($gitter);
188
                    });
189
            });
190
        } else {
191
            $this->listen($gitter);
192
        }
193
    }
194
195
    /**
196
     * @param GitterMessage $gitter
197
     */
198
    protected function onMessage(GitterMessage $gitter)
199
    {
200
        $message = Message::make($gitter);
201
202
        /** @var ExtensionInterface $extension */
203
        foreach ($this->extensions as $extension) {
204
            $extension->fire($message);
205
        }
206
    }
207
}
208
209
210
211
212
213