Completed
Pull Request — develop (#184)
by Tony
23:35
created

BaseGraph::getDevice()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * BaseGraph.php
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 *
18
 * @package    LibreNMS
19
 * @link       http://librenms.org
20
 * @copyright  2016 Neil Lathwood
21
 * @author     Neil Lathwood <[email protected]>
22
 */
23
24
namespace App\Graphs;
25
26
use App\Exceptions\UnknownDataSourceException;
27
use App\Models\Device;
28
use Carbon\Carbon;
29
use Illuminate\Http\Request;
30
use stdClass;
31
use Symfony\Component\Process\Exception\ProcessFailedException;
32
use Symfony\Component\Process\Process;
33
34
abstract class BaseGraph
35
{
36
37
    protected $device;
38
    protected $type;
39
    protected $request;
40
    protected $input;
41
42
    /**
43
     * BaseGraph constructor.
44
     *
45
     * @param Device $device
46
     * @param string $type
47
     * @param Request $request
48
     * @param stdClass $input
49
     */
50
    public function __construct(Device $device, $type, Request $request, $input = null)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
51
    {
52
        $this->type = $type;
53
        $this->device = $device;
54
        $this->request = $request;
55
        if (is_null($input)) {
56
            $this->input = json_decode($request->{'input'});
57
        } else {
58
            $this->input = $input;
59
        }
60
    }
61
62
    /**
63
     * @param $input
64
     * @return $this
65
     */
66
    public function setInput($input)
67
    {
68
        $this->input = $input;
69
        return $this;
70
    }
71
72
    /**
73
     * @return Device
74
     */
75
    public function getDevice()
76
    {
77
        return $this->device;
78
    }
79
80
    /**
81
     * Get json output.
82
     *
83
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
84
     * @throws UnknownDataSourceException
85
     */
86
    public function json()
87
    {
88
        $source = $this->request->{'source'};
89
        if ($source === 'rrd')
90
        {
91
            $build = $this->buildRRDJson();
92
            $response = $this->runRRDXport($build['cmd']);
93
            return $this->parseRRDJson($response);
94
        }
95
        throw new UnknownDataSourceException("Source type $source is not supported");
96
    }
97
98
    /**
99
     * Get csv output.
100
     *
101
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
102
     * @throws UnknownDataSourceException
103
     */
104
    public function csv()
105
    {
106
        $source = $this->request->{'source'};
107
        if ($source === 'rrd') {
108
            $build = $this->buildRRDJson();
109
            $response = $this->runRRDXport($build['cmd']);
110
            return $this->parseRRDCsv($response, $build['headers']);
111
        }
112
        throw new UnknownDataSourceException("Source type $source is not supported");
113
    }
114
115
    /**
116
     * Get png output.
117
     *
118
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
119
     * @throws UnknownDataSourceException
120
     */
121
    public function png()
122
    {
123
        $source = $this->request->{'source'};
124
        if ($source === 'rrd') {
125
            $build = $this->buildRRDGraph();
126
            $response = $this->runRRDGraph($build['cmd']);
127
            return base64_encode($response);
128
        }
129
        throw new UnknownDataSourceException("Source type $source is not supported");
130
    }
131
132
    /**
133
     * Build the RRD Xport query
134
     *
135
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
136
     */
137
    protected function buildRRDJson()
138
    {
139
        $setup = $this->buildRRDXport();
140
        $rrd_defs = $setup['defs'];
141
        $headers  = $setup['headers'];
142
        $cmd = build_rrdtool(' xport --json -s '.$this->input->{'start'}.' -e '.$this->input->{'end'}.' '.$rrd_defs);
143
144
        return [
145
            'headers' => $headers,
146
            'cmd'     => $cmd,
147
        ];
148
    }
149
150
    /**
151
     * Build the RRD Graph command
152
     *
153
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array<string,array|string>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
154
     */
155
    protected function buildRRDGraph()
156
    {
157
        $setup = $this->buildRRDGraphParams();
158
        $rrd_defs = $setup['defs'];
159
        $headers = [];
160
        $cmd = build_rrdtool(' graph - -s '.$this->input->{'start'}.' -e '.$this->input->{'end'}.' '.
161
            " --width ".$this->input->{'width'}." --height ".$this->input->{'height'}." --alt-autoscale-max --rigid -E -c BACK#EEEEEE00 -c SHADEA#EEEEEE00 -c SHADEB#EEEEEE00 -c \
162
                FONT#000000 -c CANVAS#FFFFFF00 -c GRID#a5a5a5 -c MGRID#FF9999 -c FRAME#5e5e5e -c ARROW#5e5e5e \
163
                -R normal --font LEGEND:8:DejaVuSansMono --font AXIS:7:DejaVuSansMono --font-render-mode normal " .
164
            $rrd_defs);
165
        return [
166
            'headers' => $headers,
167
            'cmd'     => $cmd,
168
        ];
169
    }
170
171
    /**
172
     * @param $cmd
173
     * @return mixed|string
174
     */
175
    protected function runRRDGraph($cmd)
176
    {
177
        $process = new Process($cmd);
178
        $process->run();
179
        if (!$process->isSuccessful()) {
180
            throw new ProcessFailedException($process);
181
        }
182
        $output = $process->getOutput();
183
        return $output;
184
    }
185
186
    /**
187
     * Run the RRD Xport query
188
     *
189
     * @param $query
190
     * @return string
191
     */
192
    protected function runRRDXport($query)
193
    {
194
        $process = new Process($query);
195
        $process->run();
196
        if (!$process->isSuccessful()) {
197
            throw new ProcessFailedException($process);
198
        }
199
        $output = $process->getOutput();
200
        $output = preg_replace('/\'/', '"', $output);
201
        $output = preg_replace('/about\:/', '"meta":', $output);
202
        $output = preg_replace('/meta\:/', '"meta":', $output);
203
        $output = json_decode($output);
204
        return $output;
205
    }
206
207
    /**
208
     * Run the RRD Xport query
209
     *
210
     * @param $response
211
     * @return string
212
     */
213
    protected function parseRRDJson($response)
214
    {
215
        $step = $response->{'meta'}->{'step'};
216
        $start = $response->{'meta'}->{'start'};
217
        $end = $response->{'meta'}->{'end'};
0 ignored issues
show
Unused Code introduced by
$end is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
218
        $cur_time = $start;
219
        $z = 0;
220
        $tmp_data = [];
221
222
        foreach ($response->{'data'} as $data)
223
        {
224
            $tmp_data['data'][$z][] = $cur_time + $step;
225
            foreach ($data as $key => $value)
226
            {
227
                $tmp_data['data'][$z][] = (is_null($value)) ? 0 : (int) $value;
228
            }
229
            //$tmp_data[] = $data;
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
230
            $z++;
231
        }
232
        $tmp_data['labels'] = ['x', 'A', 'B', 'C', 'D'];
233
        return json_encode($tmp_data);
234
    }
235
236
    /**
237
     * Parse RRD output to csv
238
     *
239
     * @param $response
240
     * @param $headers
241
     * @return string
242
     */
243
    protected function parseRRDCsv($response, $headers)
244
    {
245
        $step = $response->{'meta'}->{'step'};
246
        $start = $response->{'meta'}->{'start'};
247
        $end = $response->{'meta'}->{'end'};
0 ignored issues
show
Unused Code introduced by
$end is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
248
        $cur_time = $start;
249
        $output = 'Date, ' . implode(',', $headers) . PHP_EOL;
250
251
        foreach ($response->{'data'} as $data)
252
        {
253
            $output .=  Carbon::createFromTimestamp($cur_time) . ',';
254
            $tmp_data = [];
255
            foreach ($data as $key => $value)
256
            {
257
                $tmp_data[] = (is_null($value)) ? 0 : (int) $value;
258
            }
259
            $output .= implode(',', $tmp_data) . PHP_EOL;
260
            $cur_time = $cur_time + $step;
261
        }
262
        return $output;
263
    }
264
265
    abstract protected function buildRRDXport();
266
267
    abstract protected function buildRRDGraphParams();
268
269
}
270