Completed
Push — master ( 512542...4d85fd )
by Jan-Petter
02:22
created

DelayHandlerClient::getTimeSleepUntil()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 14

Duplication

Lines 21
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 21
loc 21
rs 9.3142
cc 3
eloc 14
nc 3
nop 0
1
<?php
2
namespace vipnytt\RobotsTxtParser\Client\Delay;
3
4
use PDO;
5
use vipnytt\RobotsTxtParser\SQL\SQLInterface;
6
use vipnytt\RobotsTxtParser\SQL\SQLTrait;
7
8
/**
9
 * Class DelayClient
10
 *
11
 * @package vipnytt\RobotsTxtParser\Client\Delay
12
 */
13
class DelayHandlerClient implements SQLInterface
14
{
15
    use SQLTrait;
16
17
    /**
18
     * Database connection
19
     * @var PDO
20
     */
21
    private $pdo;
22
23
    /**
24
     * PDO driver
25
     * @var string
26
     */
27
    private $driver;
28
29
    /**
30
     * Base UriClient
31
     * @var string
32
     */
33
    private $base;
34
35
    /**
36
     * User-agent
37
     * @var string
38
     */
39
    private $userAgent;
40
41
    /**
42
     * Delay
43
     * @var float|int
44
     */
45
    private $delay;
46
47
    /**
48
     * DelayClient constructor.
49
     *
50
     * @param PDO $pdo
51
     * @param string $baseUri
52
     * @param string $userAgent
53
     * @param float|int $delay
54
     */
55
    public function __construct(PDO $pdo, $baseUri, $userAgent, $delay)
56
    {
57
        $this->pdo = $this->pdoInitialize($pdo);
58
        $this->driver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
59
        if ($this->driver != 'mysql') {
60
            trigger_error('Unsupported database. Currently only MySQL 5.6+ are officially supported. ' . self::README_SQL_DELAY, E_USER_WARNING);
61
        }
62
        $this->base = $baseUri;
63
        $this->userAgent = $userAgent;
64
        $this->delay = round($delay, 6, PHP_ROUND_HALF_UP);
65
    }
66
67
    /**
68
     * Queue
69
     *
70
     * @return float|int
71
     */
72 View Code Duplication
    public function getQueue()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
73
    {
74
        if ($this->delay == 0) {
75
            return 0;
76
        }
77
        $query = $this->pdo->prepare(<<<SQL
78
SELECT (microTime / 1000000) - UNIX_TIMESTAMP(CURTIME(6)) AS sec
79
FROM robotstxt__delay0
80
WHERE base = :base AND userAgent = :userAgent;
81
SQL
82
        );
83
        $query->bindParam(':base', $this->base, PDO::PARAM_STR);
84
        $query->bindParam(':userAgent', $this->userAgent, PDO::PARAM_STR);
85
        $query->execute();
86
        if ($query->rowCount() > 0) {
87
            $row = $query->fetch(PDO::FETCH_ASSOC);
88
            return max($row['sec'], 0);
89
        }
90
        return 0;
91
    }
92
93
    /**
94
     * Sleep
95
     *
96
     * @return float|int
97
     */
98
    public function sleep()
99
    {
100
        $start = microtime(true);
101
        $until = $this->getTimeSleepUntil();
102
        if (microtime(true) > $until) {
103
            return 0;
104
        }
105
        try {
106
            time_sleep_until($until);
107
        } catch (\Exception $warning) {
108
            // Timestamp already in the past
109
        }
110
        return microtime(true) - $start;
111
    }
112
113
    /**
114
     * Timestamp with milliseconds
115
     *
116
     * @return float|int
117
     */
118 View Code Duplication
    public function getTimeSleepUntil()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
119
    {
120
        if ($this->delay == 0) {
121
            return 0;
122
        }
123
        $query = $this->pdo->prepare(<<<SQL
124
SELECT microTime
125
FROM robotstxt__delay0
126
WHERE base = :base AND userAgent = :userAgent;
127
SQL
128
        );
129
        $query->bindParam(':base', $this->base, PDO::PARAM_STR);
130
        $query->bindParam(':userAgent', $this->userAgent, PDO::PARAM_STR);
131
        $query->execute();
132
        $this->increment();
133
        if ($query->rowCount() > 0) {
134
            $row = $query->fetch(PDO::FETCH_ASSOC);
135
            return $row['microTime'] / 1000000;
136
        }
137
        return 0;
138
    }
139
140
    /**
141
     * Set new delayUntil timestamp
142
     *
143
     * @return bool
144
     */
145
    private function increment()
146
    {
147
        $query = $this->pdo->prepare(<<<SQL
148
INSERT INTO robotstxt__delay0 (base, userAgent, microTime, lastDelay)
149
VALUES (:base, :userAgent, (UNIX_TIMESTAMP(CURTIME(6)) + :delay) * 1000000, ROUND(:delay))
150
ON DUPLICATE KEY UPDATE
151
  microTime = GREATEST((UNIX_TIMESTAMP(CURTIME(6)) + :delay) * 1000000, microTime + (:delay * 1000000)),
152
  lastDelay = ROUND(:delay);
153
SQL
154
        );
155
        $query->bindParam(':base', $this->base, PDO::PARAM_STR);
156
        $query->bindParam(':userAgent', $this->userAgent, PDO::PARAM_STR);
157
        $query->bindParam(':delay', $this->delay, is_int($this->delay) ? PDO::PARAM_INT : PDO::PARAM_STR);
158
        return $query->execute();
159
    }
160
}
161