Notifier   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 29
c 1
b 0
f 0
lcom 1
cbo 5
dl 0
loc 200
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A processScanRequest() 0 18 4
A processWebhookRequest() 0 14 4
A requestPokemonGoMapScan() 0 20 3
A requestPokemonGoMapData() 0 12 2
B sendSlackNotification() 0 26 4
B processPokemon() 0 25 6
B expireCachedItems() 0 18 6
1
<?php namespace Cornford\Pokenotifier;
2
3
use Cornford\Pokenotifier\Exceptions\NotifierException;
4
use Cornford\Pokenotifier\Models\Position;
5
use Cornford\Pokenotifier\Contracts\NotifyingInterface;
6
use Exception;
7
8
class Notifier extends NotifierBase implements NotifyingInterface {
9
10
    const TYPE_POKEMON = 'pokemon';
11
12
    /**
13
     * Process scan request.
14
     *
15
     * @param Position $position
16
     *
17
     * @throws NotifierException
18
     *
19
     * @return boolean
20
     */
21
    public function processScanRequest(Position $position)
22
    {
23
        $response = $this->requestPokemonGoMapScan($position);
24
25
        if (!$response) {
26
            throw new NotifierException('Unable to request a current location scan from PokemonGo-Map.');
27
        }
28
29
        $results = $this->requestPokemonGoMapData();
30
31
        if (!$results || !isset($results['pokemons'])) {
32
            throw new NotifierException('Unable to request pokemon from PokemonGo-Map.');
33
        }
34
35
        $this->expireCachedItems();
36
37
        return $this->processPokemon($results['pokemons'], $position);
38
    }
39
40
    /**
41
     * Process webhook request.
42
     *
43
     * @param array    $result
44
     * @param Position $position
45
     *
46
     * @throws NotifierException
47
     *
48
     * @return boolean
49
     */
50
    public function processWebhookRequest(array $result, Position $position)
51
    {
52
        if (empty($result) || !isset($result['type']) || $result['type'] != self::TYPE_POKEMON) {
53
            throw new NotifierException('Unable to process Pokemon results array.');
54
        }
55
56
        $this->expireCachedItems();
57
58
        $result = (array) $result['message'];
59
        $pokemonConfiguration = $this->getPokemonConfiguration();
60
        $result['pokemon_name'] = $pokemonConfiguration[$result['pokemon_id']]['name'];
61
62
        return $this->processPokemon([$result], $position);
63
    }
64
65
    /**
66
     * Request PokemonGo-Map scan.
67
     *
68
     * @param Position $position
69
     *
70
     * @return boolean
71
     */
72
    public function requestPokemonGoMapScan(Position $position)
73
    {
74
        try {
75
            $response = $this->getGuzzleClient()
76
                ->post(
77
                    sprintf('/next_loc?lat=%s&lon=%s', $position->getLatitude(), $position->getLongitude()),
78
                    [
79
                        'headers' => [
80
                            'accept' => 'application/hal+json',
81
                            'cache-control' => 'no-cache',
82
                        ]
83
                    ]
84
                )
85
                ->getBody();
86
        } catch (Exception $exception) {
87
            return false;
88
        }
89
90
        return ($response->__toString() === 'ok' ? true : false);
91
    }
92
93
    /**
94
     * Request PokemonGo-Map data array.
95
     *
96
     * @return array|boolean
97
     */
98
    public function requestPokemonGoMapData()
99
    {
100
        try {
101
            $response = $this->getGuzzleClient()
102
                ->get('/raw_data')
103
                ->json();
104
        } catch (Exception $exception) {
105
            return false;
106
        }
107
108
        return $response;
109
    }
110
111
    /**
112
     * Expire cache items.
113
     *
114
     * @param string $timeout
115
     *
116
     * @return boolean
117
     */
118
    public function expireCachedItems($timeout = '-1 hour')
119
    {
120
        try {
121
            foreach ($this->getDirectoryIterator() as $file) {
122
                if ($file->isDot() || $file->getFilename() == '.gitkeep') {
123
                    continue;
124
                }
125
126
                if ($file->getMTime() <= strtotime($timeout)) {
127
                    unlink($file->getPathname());
128
                }
129
            }
130
        } catch (Exception $exception) {
131
            return false;
132
        }
133
134
        return true;
135
    }
136
137
    /**
138
     * Send slack notification.
139
     *
140
     * @param array    $pokemon
141
     * @param Position $position
142
     *
143
     * @return boolean
144
     */
145
    public function sendSlackNotification(array $pokemon, Position $position)
146
    {
147
        try {
148
            $applicationConfiguration = $this->getApplicationConfiguration();
149
150
            if (count(array_diff(['pokemon_id', 'pokemon_name', 'latitude', 'longitude', 'disappear_time'], array_keys($pokemon))) > 0) {
151
                return false;
152
            }
153
154
            $now = (integer) (time() . round(microtime() * 1000));
155
            $pokemonName = '<http://pogobase.net/' . $pokemon['pokemon_id'] . '|' . $pokemon['pokemon_name'] . '>';
156
            $pokemonPosition = new Position($pokemon['latitude'], $pokemon['longitude']);
157
            $pokemonDistance = $position->calculateDistance($pokemonPosition) . 'm';
158
            $time = round(abs(($now - $pokemon['disappear_time']) / 1000 / 60), 0);
159
            $pokemonTime = (integer) ($time > 100 ? 'now' : 'in ' . $time . ' min');
160
            $pokemonMap = '<https://www.google.co.uk/maps/dir/' . $position->getLatitude() . ',' . $position->getLongitude() . '/' . $pokemonPosition->getLatitude() . ',' . $pokemonPosition->getLongitude() . '/?dirflg=w|location>! :world_map:';
161
162
            $this->getSlackClient()
163
                ->to($applicationConfiguration['slack-channel'])
164
                ->send($pokemonName . ' ' . $pokemonDistance . ' away. Expires ' . $pokemonTime . ' at ' . $pokemonMap);
165
        } catch (Exception $exception) {
166
            return false;
167
        }
168
169
        return true;
170
    }
171
172
    /**
173
     * Process an array of Pokemon.
174
     *
175
     * @param array    $array
176
     * @param Position $position
177
     * @param boolean  $notification
178
     *
179
     * @return boolean
180
     */
181
    public function processPokemon(array $array, Position $position, $notification = true)
182
    {
183
        try {
184
            $applicationConfiguration = $this->getApplicationConfiguration();
185
            $pokemonConfiguration = $this->getPokemonConfiguration();
186
187
            foreach ($array as $pokemon) {
188
                if ((integer) $pokemonConfiguration[$pokemon['pokemon_id']]['rarity'] >= $applicationConfiguration['pokemon-rarity']) {
189
                    $cache = $applicationConfiguration['cache-directory'] . md5($pokemon['pokemon_id'] . $pokemon['encounter_id'] . $pokemon['spawnpoint_id'] . $pokemon['disappear_time']) . '.md5';
190
191
                    if (!file_exists($cache)) {
192
                        if ($notification) {
193
                            $this->sendSlackNotification($pokemon, $position);
194
                        }
195
196
                        file_put_contents($cache, $pokemon['encounter_id']);
197
                    }
198
                }
199
            }
200
        } catch (Exception $exception) {
201
            return false;
202
        }
203
204
        return true;
205
    }
206
    
207
}