/dev/trunk

To get this branch, use:
bzr branch http://darksoft.org/webbzr/dev/trunk

« back to all changes in this revision

Viewing changes to classes/readers/couchreader.php

  • Committer: Suren A. Chilingaryan
  • Date: 2014-05-19 08:31:53 UTC
  • mfrom: (354.2.7 adei-couchreader)
  • Revision ID: csa@suren.me-20140519083153-lzmyk80wv78bopz9
Merge COUCHeReader

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/**
 
4
* CouchDB data class
 
5
*
 
6
* returns current dataset and will be iterated till end of timestamp
 
7
*
 
8
* Iterations stages:
 
9
* rewind -> valid -> key -> current -> valid -> (output) ->
 
10
* next   -> valid -> key -> current -> valid -> (output) ->
 
11
* next   -> valid -> key -> current -> valid -> (output) ->
 
12
* ...
 
13
* next   -> valid -> valid
 
14
*
 
15
*/
 
16
class COUCHData implements Iterator {
 
17
    
 
18
    /**
 
19
     * class constructor
 
20
     *
 
21
     */
 
22
    function __construct($view_url, $alldata_view, $opts, $items, $ivl) {
 
23
       
 
24
        # indicate wheter timeStamp is available
 
25
        $this->timeStamp = false;
 
26
        $this->hasNextData = false;
 
27
        $this->hasNextPacket = false;
 
28
        # these start and end keys will change dynamically
 
29
        $this->startKey;
 
30
        $this->endKey;
 
31
 
 
32
        # $this->defaultStart = 1313023285;
 
33
        # $this->defaultEnd = 1313023446;
 
34
        $this->defaultStart = $ivl->GetWindowStart();
 
35
        $this->defaultEnd = $ivl->GetWindowEnd();
 
36
 
 
37
        # items list
 
38
        $this->items = $items;
 
39
        $this->alldata_view = $alldata_view;
 
40
        $this->view_url = $view_url;
 
41
 
 
42
        $this->counter = 0;
 
43
 
 
44
        $this->buffer = array();
 
45
        $this->pointer = 10000;
 
46
        $this->packetSize = 10000;
 
47
 
 
48
        # create and reuse
 
49
        $this->ch = curl_init();
 
50
 
 
51
        curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, 'GET');
 
52
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
 
53
        curl_setopt($this->ch, CURLOPT_HTTPHEADER, array(
 
54
            'Content-type: application/json',
 
55
            'Accept: */*'
 
56
        ));
 
57
 
 
58
        $this->descending = "false";
 
59
        $this->itemLimit = false;
 
60
        $this->db_mask = $opts->props['db_mask'];
 
61
        $this->resample = $opts->props['resample'];
 
62
 
 
63
        if ( $ivl->item_limit ) {
 
64
            if ( $ivl->item_limit < 0 ) {
 
65
                $this->pointer = abs($ivl->item_limit);
 
66
                $this->packetSize = abs($ivl->item_limit);
 
67
                $this->descending = "true";
 
68
                $this->defaultStart = $ivl->GetWindowEnd();
 
69
                $this->defaultEnd = $ivl->GetWindowStart();
 
70
                $this->itemLimit = true;
 
71
            }
 
72
        }
 
73
    }
 
74
 
 
75
    /*
 
76
    * helper method to rewind the timestamp to default start
 
77
    *
 
78
    * default start is the first timestamp in the database
 
79
    */ 
 
80
    function rewind() {
 
81
        $this->timeStamp = $this->defaultStart;
 
82
    }
 
83
 
 
84
    /*
 
85
    * helper method to show the current data set
 
86
    *
 
87
    * @return array 
 
88
    * Array([0] => -0.89309238625218
 
89
    *       [1] => -0.44987330396278)
 
90
    */
 
91
    function current() {
 
92
        try {
 
93
            if ( $this->pointer >= ($this->packetSize - 1) ) {
 
94
                if ( $this->resample ) {
 
95
                    $this->buffer = array();
 
96
                    for ($i = 0; $i <= $this->packetSize; $i++) {
 
97
                        if ( $this->itemLimit ) {
 
98
                            if ($this->timeStamp < $this->defaultEnd ) break;
 
99
                        } else {
 
100
                            if ($this->timeStamp > $this->defaultEnd ) break;
 
101
                        }
 
102
                        $queryString = implode("&", array("startkey=".floor($this->timeStamp),
 
103
                                                         "endkey=".$this->defaultEnd,
 
104
                                                         "limit=1",
 
105
                                                         "descending=".$this->descending));
 
106
                        curl_setopt($this->ch, CURLOPT_URL, $this->view_url.$this->alldata_view.'?'.$queryString);
 
107
 
 
108
                        $response = curl_exec($this->ch);
 
109
                        $data = json_decode($response);
 
110
                        array_push($this->buffer, $data->rows[0]);
 
111
 
 
112
                        if ( $this->itemLimit ) {
 
113
                            $this->timeStamp -= $this->resample;
 
114
                       } else {
 
115
                            $this->timeStamp += $this->resample;
 
116
                        }
 
117
                    }
 
118
                } else {
 
119
                    $queryString = implode("&", array("startkey=".floor($this->timeStamp),
 
120
                                                     "endkey=".$this->defaultEnd,
 
121
                                                     "limit=".($this->packetSize + 1),
 
122
                                                     "descending=".$this->descending));
 
123
                    curl_setopt($this->ch, CURLOPT_URL, $this->view_url.$this->alldata_view.'?'.$queryString);
 
124
 
 
125
                    $response = curl_exec($this->ch);
 
126
                    $data = json_decode($response);
 
127
 
 
128
                    $this->buffer = $data->rows;
 
129
                }
 
130
                $this->pointer = 0;
 
131
                if ( count($this->buffer) <= (($this->packetSize))) {
 
132
                    $this->hasNextPacket = false;
 
133
                } else { 
 
134
                    $this->hasNextPacket = true;
 
135
                }
 
136
            } else {
 
137
                $this->pointer++;
 
138
            }
 
139
             
 
140
            $curData = $this->buffer[$this->pointer];
 
141
            $this->nextData = $this->buffer[$this->pointer+1];
 
142
 
 
143
            # output all value
 
144
            $output = $curData->value;
 
145
        } catch ( Exception $e) {
 
146
            # uncomment below to show amount of document shown (debug)
 
147
            # echo "\r\n"; print_r($this->counter); echo "\r\n";
 
148
            curl_close($this->ch);
 
149
            throw new ADEIException(translate("CouchDB error Current") . ": " . $e->getMessage());
 
150
        }
 
151
        $cleanOutput = array();
 
152
        if (is_array($output)){
 
153
            foreach ($output as $element) {
 
154
                if (!is_numeric($element)) {
 
155
                    $element = NULL;
 
156
                }
 
157
                array_push($cleanOutput, $element);
 
158
            }
 
159
        }
 
160
        return $cleanOutput;
 
161
    }
 
162
 
 
163
    /*
 
164
    * helper method to show current timestamp
 
165
    *
 
166
    * @return integer $this->timeStamp
 
167
    */
 
168
    function key() {
 
169
        return $this->timeStamp;
 
170
    }
 
171
 
 
172
    /*
 
173
    * helper method to update the current timestamp to the next
 
174
    * available timestamp
 
175
    *
 
176
    * @param boolean $this->nextData this shows next data 
 
177
    *                                availability status
 
178
    */
 
179
    function next() {
 
180
 
 
181
        if($this->hasNextPacket) {
 
182
            if ( $this->itemLimit && ($this->pointer == ($this->packetSize - 1)) ) {
 
183
                curl_close($this->ch);
 
184
                $this->timeStamp = false;
 
185
            } else {
 
186
                if ($this->pointer < (count($this->buffer)-1)) {
 
187
                    $this->timeStamp = $this->nextData->key;
 
188
                }
 
189
           }
 
190
        } else {
 
191
            if ($this->pointer < (count($this->buffer))) {
 
192
                $this->timeStamp = $this->nextData->key;
 
193
            } else {
 
194
                curl_close($this->ch);
 
195
                $this->timeStamp = false;
 
196
            }
 
197
        }
 
198
    }
 
199
 
 
200
    /*
 
201
    * helper method to tell whether there's any current
 
202
    * timestamp
 
203
    *
 
204
    * @return boolean $this->timeStamp
 
205
    */
 
206
    function valid() {
 
207
        return $this->timeStamp?true:false;
 
208
    }
 
209
}
 
210
 
 
211
 
 
212
/**
 
213
* Adei Reader for CouchDB class
 
214
*
 
215
* This class implements the necessary methods to get data
 
216
* from CouchDB and show it on Adei
 
217
*
 
218
*/
 
219
class COUCHReader extends READER {
 
220
 
 
221
    /**
 
222
     * class constructor
 
223
     *
 
224
     */
 
225
    function __construct(&$props) {
 
226
        parent::__construct($props);
 
227
 
 
228
        # server parameter
 
229
        $server = $this->req->srv;
 
230
        $database = $server['database'][0];
 
231
        $http_method = $server['http_method'];
 
232
        $host = $server['host'];
 
233
        $port = $server['port'];
 
234
        $username = $server['user'];
 
235
        $password = $server['password'];
 
236
 
 
237
        # options parameter
 
238
        $options = $this->opts;
 
239
 
 
240
        # credentials
 
241
        $credential = "";
 
242
        if ($username && $password ) {
 
243
            $credential = implode(":", array($username,
 
244
                                             $password));
 
245
            $credential = $credential."@";
 
246
        }
 
247
 
 
248
        # build URL for queries
 
249
        $this->base_view_url = implode("", array($http_method."://",
 
250
                                            $credential,
 
251
                                            $host.":",
 
252
                                            $port."/",
 
253
                                            $database."/",
 
254
                                            "_design/",
 
255
                                            "%design_view%/",
 
256
                                            "_view/"));
 
257
 
 
258
        $this->base_url = implode("", array($http_method."://",
 
259
                                            $credential,
 
260
                                            $host.":",
 
261
                                            $port."/",
 
262
                                            $database."/"));
 
263
 
 
264
        $this->resample = $options->props['resample'];
 
265
    }
 
266
 
 
267
    /*
 
268
    * helper method to get group information
 
269
    * 
 
270
    * @parameter integer $first first timestamp in the database (UTC)
 
271
    * @parameter integer $last last timestamp in the database (UTC)
 
272
    * @parameter integer $gid group id
 
273
    *
 
274
    * @return array
 
275
    * Array([default] => Array(
 
276
    *                  [gid] => default
 
277
    *                  [name] => Default Group
 
278
    *                  [first] => -2208988800
 
279
    *                  [last] => 1394534718))                   
 
280
    *
 
281
    */
 
282
    function GetGroupInfo(LOGGROUP $grp = NULL, $flags = 0) {
 
283
        $groups = array();
 
284
        $options = $this->opts;
 
285
        # Get Groups
 
286
        $groups = $options->Get('groups', false);
 
287
 
 
288
        foreach ($groups as $gid => &$group) {
 
289
            
 
290
            if (($grp)&&(strcmp($grp->gid, $gid))) continue;
 
291
 
 
292
            $stats_view = $groups[$gid]['stats_view'];
 
293
            $itemlist_id = $groups[$gid]['itemlist_id'];
 
294
            $design_view = $groups[$gid]['design_view'];
 
295
 
 
296
            $this->view_url = str_replace("%design_view%", $design_view, $this->base_view_url);
 
297
 
 
298
            $this->alldata_view = $groups[$gid]['alldata_view'];
 
299
 
 
300
            $ch = curl_init();
 
301
            curl_setopt($ch, CURLOPT_URL, $this->view_url.$stats_view);
 
302
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
 
303
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
304
            curl_setopt($ch, CURLOPT_HTTPHEADER, array(
 
305
                'Content-type: application/json',
 
306
                'Accept: */*'
 
307
            ));
 
308
            $response = curl_exec($ch);
 
309
            curl_close($ch);
 
310
            
 
311
            $minmax = json_decode($response);
 
312
            foreach ( $minmax as $unit ) {
 
313
                foreach ( $unit as $i ) {
 
314
                    $result = $i->value;
 
315
                }
 
316
            }
 
317
            $this->min = floor($result->min);
 
318
            $this->max = ceil($result->max);
 
319
            $this->count = $result->count;
 
320
 
 
321
            
 
322
            
 
323
            if ($group['name']) $name = $group['name'];
 
324
            else $name = false;
 
325
        
 
326
            # put name if there's no name specified
 
327
            if ((!$name)||($flags&REQUEST::NEED_INFO)) {
 
328
                if ($grp) {
 
329
                    $grtest = $grp;
 
330
                    $opts = $this->opts;
 
331
                } else {
 
332
                    $ginfo = array("db_group" => $gid);
 
333
                    $grtest = $this->CreateGroup($ginfo);
 
334
                    $opts = $this->req->GetGroupOptions($grtest);
 
335
                }
 
336
            
 
337
                if (!$name) {
 
338
                    $name = $opts->Get('name', $gid);
 
339
                }
 
340
            }
 
341
            
 
342
            # insert into groups
 
343
            $groups[$gid] = array(
 
344
                'gid' => $gid,
 
345
                'name' => $name
 
346
            );
 
347
 
 
348
            if ($flags&REQUEST::NEED_INFO) {
 
349
                $groups[$gid]['first'] = $this->min; 
 
350
                $groups[$gid]['last'] = $this->max; 
 
351
 
 
352
                if ($flags&REQUEST::NEED_COUNT) {
 
353
                    $groups[$gid]['records'] = $this->count;
 
354
                }
 
355
 
 
356
                # not yet implemented for couch
 
357
                # this might be the sensor list
 
358
                if ($flags&REQUEST::NEED_ITEMINFO) {
 
359
                    $groups[$gid]['items'] = $this->GetItemList($grtest);
 
360
                }
 
361
            }
 
362
        }
 
363
 
 
364
        if (($grp)&&(!$groups)) {
 
365
            throw new ADEIException(translate("Invalid group (%s) is specified", $grp->gid));
 
366
        }
 
367
        return $grp?$groups[$grp->gid]:$groups;
 
368
    }
 
369
 
 
370
    /*
 
371
    * helper method to return item list from sensors
 
372
    *
 
373
    * @param LOGGROUP $grp user group
 
374
    * @param MASK $mask filter mask to determine which sensor data to show
 
375
    * @param integer $flags flag to detemine type of operation
 
376
    *
 
377
    * @return array
 
378
    * Array( [0] => Array ( [id] => default 
 
379
    *                       [name] => Default Group))                   
 
380
    *
 
381
    */
 
382
    function GetItemList(LOGGROUP $grp = NULL, MASK $mask = NULL, $flags = 0) {
 
383
        if ($flags&REQUEST::ONLY_AXISINFO) {
 
384
            if (!$this->req->GetGroupOptions($grp, "axis")) return array();
 
385
        }
 
386
        #print_r($this->req->GetGroupOptions($grp, "axis"));
 
387
 
 
388
        $grp = $this->CheckGroup($grp, $flags);
 
389
 
 
390
        if (!$mask) {
 
391
            $mask = $this->CreateMask($grp, $info=NULL, $flags);
 
392
        }
 
393
        $i = 0;
 
394
        $items = array();
 
395
        
 
396
        $groups = array();
 
397
        $options = $this->opts;
 
398
        # Get Groups
 
399
        $groups = $options->Get('groups', false);
 
400
 
 
401
        $itemlist_id = $groups[$grp->gid]['itemlist_id'];
 
402
        $ch = curl_init();
 
403
        curl_setopt($ch, CURLOPT_URL, $this->base_url.$itemlist_id);
 
404
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
 
405
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
406
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
 
407
            'Content-type: application/json',
 
408
            'Accept: */*'
 
409
        ));
 
410
        $response = curl_exec($ch);
 
411
        curl_close($ch);
 
412
        $this->itemList = json_decode($response);
 
413
 
 
414
        foreach ($this->itemList as $key => $value) {
 
415
            if (strcmp($grp->gid, $key)) continue;
 
416
            $itemList = $value;
 
417
        }
 
418
 
 
419
        if ($mask->isFull()) {
 
420
            foreach($itemList as $unit) {
 
421
                array_push($items, array('id' => $i,
 
422
                                         'name' => $unit->name,
 
423
                                         'axis' => $unit->axis,
 
424
                                         'desc' => $unit->description));
 
425
                $i++;
 
426
            }
 
427
        } else {
 
428
            foreach ($mask->ids as $bit) {
 
429
                array_push($items, array('id' => $i,
 
430
                                         'name' => $itemList[$bit]->name,
 
431
                                         'axis' => $itemList[$bit]->axis,
 
432
                                         'desc' => $itemList[$bit]->description));
 
433
                $i++;
 
434
            }
 
435
        }       
 
436
 
 
437
        if ($flags&REQUEST::NEED_AXISINFO) {
 
438
            $this->AddAxisInfo($grp, $items);
 
439
        }
 
440
 
 
441
        return $items;
 
442
    }
 
443
 
 
444
    /*
 
445
    * helper method to get raw data
 
446
    *
 
447
    * @param LOGGROUP $grp user group
 
448
    * @param integer $from start timestamp
 
449
    * @param integer $to end timestamp
 
450
    * @param DATAFilter $filter filtered data from the sensor
 
451
    *
 
452
    * @return COUCHData iterator
 
453
    *
 
454
    */
 
455
    function GetRawData(LOGGROUP $grp = NULL, $from = false, $to = false, DATAFilter $filter = NULL, &$filter_data = NULL) {
 
456
 
 
457
        $grp = $this->CheckGroup($grp);
 
458
        $ivl = $this->CreateInterval($grp);
 
459
        $ivl->Limit($from, $to);
 
460
 
 
461
        if ($grp) {
 
462
            $groups = array();
 
463
            $options = $this->opts;
 
464
            # Get Groups
 
465
            $groups = $options->Get('groups', false);
 
466
 
 
467
            foreach ($groups as $gid => &$group) {
 
468
                if (($grp)&&(strcmp($grp->gid, $gid))) continue;
 
469
                $design_view = $groups[$gid]['design_view'];
 
470
                $this->view_url = str_replace("%design_view%", $design_view, $this->base_view_url);
 
471
            }
 
472
        }
 
473
 
 
474
        if ($filter) {
 
475
            $mask = $filter->GetItemMask();
 
476
            $resample = $filter->GetSamplingRate();
 
477
            $limit = $filter->GetVectorsLimit();
 
478
            if ($limit) $ivl->SetItemLimit($limit);
 
479
 
 
480
            if (isset($filter_data)) {
 
481
                #if ($mask) $filter_data['masked'] = true;
 
482
                if ($resample) $filter_data['resampled'] = true;
 
483
                if ($limit) $filter_data['limited'] = true;
 
484
            }
 
485
        } else {
 
486
            $mask = NULL;
 
487
            $resample = 0;
 
488
            $limit = 0;
 
489
        }
 
490
 
 
491
        foreach ($this->itemList as $key => $value) {
 
492
            if (strcmp($grp->gid, $key)) continue;
 
493
            $itemList = $value;
 
494
        }
 
495
 
 
496
        $items = array();  
 
497
         
 
498
        if (($mask)&&(is_array($ids = $mask->GetIDs()))) {
 
499
            $tmp = array();
 
500
            foreach ($ids as $id) {
 
501
                if ($id >= sizeof($itemList)) {
 
502
                    throw new ADEIException(translate("Invalid item mask is supplied. The ID:%d refers non-existing item.", $id));
 
503
                }
 
504
                array_push($tmp, $itemList[$id]);
 
505
            }
 
506
            $items = $tmp;
 
507
        }
 
508
        return new COUCHData($this->view_url, $this->alldata_view, $this->req->GetGroupOptions($grp), $items, $ivl);
 
509
    }
 
510
}
 
511
?>