Completed
Push — develop ( 9773af...b9ad6f )
by Kirill
32:11 queued 50s
created

GitterRoomListenCommand::handle()   B

Complexity

Conditions 2
Paths 1

Size

Total Lines 24
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 1
Metric Value
c 6
b 0
f 1
dl 0
loc 24
rs 8.9713
cc 2
eloc 11
nc 1
nop 2
1
<?php
2
namespace App\Console\Commands;
3
4
5
use App\Gitter\Extensions\ExtensionInterface;
6
use App\Gitter\Extensions\Middleware\MiddlewaresExtension;
7
use App\Gitter\Middlewares\GoogleSearchMiddleware;
8
use App\Message;
9
use App\Room;
10
use App\User;
11
use Gitter\Models\User as GitterUser;
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 Illuminate\Contracts\Config\Repository;
18
use Illuminate\Contracts\Container\Container;
19
use React\EventLoop\LoopInterface;
20
21
22
/**
23
 * Class GitterRoomListenCommand
24
 * @package App\Console\Commands
25
 *
26
 * Прослушивание сообщений требуемой комнаты
27
 */
28
class GitterRoomListenCommand extends AbstractCommand
29
{
30
    /**
31
     * @var string
32
     */
33
    protected $signature = 'gitter:listen {room}';
34
35
    /**
36
     * @var string
37
     */
38
    protected $description = 'Listen gitter room';
39
40
    /**
41
     * @var array|ExtensionInterface[]
42
     */
43
    protected $extensions = [];
44
45
    /**
46
     * Execute the console command.
47
     *
48
     * @param Repository $config
49
     * @param Container $container
50
     *
51
     * @return mixed
52
     */
53
    public function handle(Repository $config, Container $container)
54
    {
55
        /** @var Client $client */
56
        $client = $this->createClient($container, $config->get('gitter.token'));
57
58
        $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...
59
60
            $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...
61
                try {
62
                    $this->getExtensions($room);
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 $gitter
95
     * @param bool $startup
96
     * @return $this
97
     */
98
    protected function listen(GitterRoom $gitter, $startup = false)
99
    {
100
        /** @var Room $room */
101
        $room = Room::make($gitter, function (Room $room) {
102
            $this->call('gitter:sync', [
103
                'room'       => $room->gitter_id,
104
                '--users'    => true,
105
                '--messages' => true,
106
            ]);
107
        });
108
109
110
        /** @var LoopInterface $loop */
111
        $loop = app(LoopInterface::class);
112
113
        if ($startup) {
114
            $this->info('Fetching last messages...');
115
            $this->onMessageFallback($loop, $gitter, 1);
116
117
            return $this;
118
        }
119
120
        $this->info(sprintf(
121
            'Startup gitter listener for %s at [%s]',
122
            $room->url,
123
            Carbon::now()->toDateTimeString()
124
        ));
125
126
        $gitter->onMessage(function (GitterMessage $msg) {
127
            $this->onMessage($msg);
128
129
        }, function (\Throwable $e) use ($loop, $gitter) {
130
            $this->error($e->getMessage());
131
            $this->error($e->getFile() . ':' . $e->getLine());
132
            $this->warn('Stream not available. Use message fallback fetch mode.');
133
            $this->onMessageFallback($loop, $gitter);
134
        });
135
136
        return $this;
137
    }
138
139
    /**
140
     * @param GitterRoom $room
141
     * @return array
142
     */
143
    protected function getExtensions(GitterRoom $room)
144
    {
145
        if ($this->extensions === []) {
146
            /**
147
             * Register Middlewares extension
148
             */
149
            $this->extensions[] =
150
                app(MiddlewaresExtension::class, ['room' => $room])
151
                    ->register(GoogleSearchMiddleware::class);
152
        }
153
154
        return $this->extensions;
155
    }
156
157
    /**
158
     * @param LoopInterface $loop
159
     * @param GitterRoom $gitter
160
     * @param int $timeout
161
     */
162
    protected function onMessageFallback(LoopInterface $loop, GitterRoom $gitter, $timeout = 10)
163
    {
164
        /** @var Message $lastMessage */
165
        $lastMessage = Message::where('room_id', $gitter->id)
166
            ->latest('created_at')
167
            ->first();
168
169 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...
170
            $gitter->getMessages($lastMessage->gitter_id, GitterRoom::MESSAGE_FETCH_ASC)
171
                ->fetch(function (GitterMessage $message, Controls $controls) {
172
                    $this->onMessage($message);
173
                    $controls->next();
174
                })
175
                ->then(function () use ($gitter) {
176
                    $this->warn('Connection...');
177
                    $this->listen($gitter);
178
                });
179
        });
180
    }
181
182
    /**
183
     * @param GitterMessage $gitter
184
     */
185
    protected function onMessage(GitterMessage $gitter)
186
    {
187
        $message = Message::make($gitter);
188
189
        /** @var ExtensionInterface $extension */
190
        foreach ($this->extensions as $extension) {
191
            $extension->fire($message);
192
        }
193
    }
194
}
195
196
197
198
199
200