6
* returns current dataset and will be iterated till end of timestamp
9
* rewind -> valid -> key -> current -> valid -> (output) ->
10
* next -> valid -> key -> current -> valid -> (output) ->
11
* next -> valid -> key -> current -> valid -> (output) ->
13
* next -> valid -> valid
16
class COUCHData implements Iterator {
22
function __construct($view_url, $alldata_view, $opts, $items, $ivl) {
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
32
# $this->defaultStart = 1313023285;
33
# $this->defaultEnd = 1313023446;
34
$this->defaultStart = $ivl->GetWindowStart();
35
$this->defaultEnd = $ivl->GetWindowEnd();
38
$this->items = $items;
39
$this->alldata_view = $alldata_view;
40
$this->view_url = $view_url;
44
$this->buffer = array();
45
$this->pointer = 10000;
46
$this->packetSize = 10000;
49
$this->ch = curl_init();
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',
58
$this->descending = "false";
59
$this->itemLimit = false;
60
$this->db_mask = $opts->props['db_mask'];
61
$this->resample = $opts->props['resample'];
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;
76
* helper method to rewind the timestamp to default start
78
* default start is the first timestamp in the database
81
$this->timeStamp = $this->defaultStart;
85
* helper method to show the current data set
88
* Array([0] => -0.89309238625218
89
* [1] => -0.44987330396278)
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;
100
if ($this->timeStamp > $this->defaultEnd ) break;
102
$queryString = implode("&", array("startkey=".floor($this->timeStamp),
103
"endkey=".$this->defaultEnd,
105
"descending=".$this->descending));
106
curl_setopt($this->ch, CURLOPT_URL, $this->view_url.$this->alldata_view.'?'.$queryString);
108
$response = curl_exec($this->ch);
109
$data = json_decode($response);
110
array_push($this->buffer, $data->rows[0]);
112
if ( $this->itemLimit ) {
113
$this->timeStamp -= $this->resample;
115
$this->timeStamp += $this->resample;
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);
125
$response = curl_exec($this->ch);
126
$data = json_decode($response);
128
$this->buffer = $data->rows;
131
if ( count($this->buffer) <= (($this->packetSize))) {
132
$this->hasNextPacket = false;
134
$this->hasNextPacket = true;
140
$curData = $this->buffer[$this->pointer];
141
$this->nextData = $this->buffer[$this->pointer+1];
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());
151
$cleanOutput = array();
152
if (is_array($output)){
153
foreach ($output as $element) {
154
if (!is_numeric($element)) {
157
array_push($cleanOutput, $element);
164
* helper method to show current timestamp
166
* @return integer $this->timeStamp
169
return $this->timeStamp;
173
* helper method to update the current timestamp to the next
174
* available timestamp
176
* @param boolean $this->nextData this shows next data
177
* availability status
181
if($this->hasNextPacket) {
182
if ( $this->itemLimit && ($this->pointer == ($this->packetSize - 1)) ) {
183
curl_close($this->ch);
184
$this->timeStamp = false;
186
if ($this->pointer < (count($this->buffer)-1)) {
187
$this->timeStamp = $this->nextData->key;
191
if ($this->pointer < (count($this->buffer))) {
192
$this->timeStamp = $this->nextData->key;
194
curl_close($this->ch);
195
$this->timeStamp = false;
201
* helper method to tell whether there's any current
204
* @return boolean $this->timeStamp
207
return $this->timeStamp?true:false;
213
* Adei Reader for CouchDB class
215
* This class implements the necessary methods to get data
216
* from CouchDB and show it on Adei
219
class COUCHReader extends READER {
225
function __construct(&$props) {
226
parent::__construct($props);
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'];
238
$options = $this->opts;
242
if ($username && $password ) {
243
$credential = implode(":", array($username,
245
$credential = $credential."@";
248
# build URL for queries
249
$this->base_view_url = implode("", array($http_method."://",
258
$this->base_url = implode("", array($http_method."://",
264
$this->resample = $options->props['resample'];
268
* helper method to get group information
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
275
* Array([default] => Array(
277
* [name] => Default Group
278
* [first] => -2208988800
279
* [last] => 1394534718))
282
function GetGroupInfo(LOGGROUP $grp = NULL, $flags = 0) {
284
$options = $this->opts;
286
$groups = $options->Get('groups', false);
288
foreach ($groups as $gid => &$group) {
290
if (($grp)&&(strcmp($grp->gid, $gid))) continue;
292
$stats_view = $groups[$gid]['stats_view'];
293
$itemlist_id = $groups[$gid]['itemlist_id'];
294
$design_view = $groups[$gid]['design_view'];
296
$this->view_url = str_replace("%design_view%", $design_view, $this->base_view_url);
298
$this->alldata_view = $groups[$gid]['alldata_view'];
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',
308
$response = curl_exec($ch);
311
$minmax = json_decode($response);
312
foreach ( $minmax as $unit ) {
313
foreach ( $unit as $i ) {
317
$this->min = floor($result->min);
318
$this->max = ceil($result->max);
319
$this->count = $result->count;
323
if ($group['name']) $name = $group['name'];
326
# put name if there's no name specified
327
if ((!$name)||($flags&REQUEST::NEED_INFO)) {
332
$ginfo = array("db_group" => $gid);
333
$grtest = $this->CreateGroup($ginfo);
334
$opts = $this->req->GetGroupOptions($grtest);
338
$name = $opts->Get('name', $gid);
343
$groups[$gid] = array(
348
if ($flags&REQUEST::NEED_INFO) {
349
$groups[$gid]['first'] = $this->min;
350
$groups[$gid]['last'] = $this->max;
352
if ($flags&REQUEST::NEED_COUNT) {
353
$groups[$gid]['records'] = $this->count;
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);
364
if (($grp)&&(!$groups)) {
365
throw new ADEIException(translate("Invalid group (%s) is specified", $grp->gid));
367
return $grp?$groups[$grp->gid]:$groups;
371
* helper method to return item list from sensors
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
378
* Array( [0] => Array ( [id] => default
379
* [name] => Default Group))
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();
386
#print_r($this->req->GetGroupOptions($grp, "axis"));
388
$grp = $this->CheckGroup($grp, $flags);
391
$mask = $this->CreateMask($grp, $info=NULL, $flags);
397
$options = $this->opts;
399
$groups = $options->Get('groups', false);
401
$itemlist_id = $groups[$grp->gid]['itemlist_id'];
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',
410
$response = curl_exec($ch);
412
$this->itemList = json_decode($response);
414
foreach ($this->itemList as $key => $value) {
415
if (strcmp($grp->gid, $key)) continue;
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));
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));
437
if ($flags&REQUEST::NEED_AXISINFO) {
438
$this->AddAxisInfo($grp, $items);
445
* helper method to get raw data
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
452
* @return COUCHData iterator
455
function GetRawData(LOGGROUP $grp = NULL, $from = false, $to = false, DATAFilter $filter = NULL, &$filter_data = NULL) {
457
$grp = $this->CheckGroup($grp);
458
$ivl = $this->CreateInterval($grp);
459
$ivl->Limit($from, $to);
463
$options = $this->opts;
465
$groups = $options->Get('groups', false);
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);
475
$mask = $filter->GetItemMask();
476
$resample = $filter->GetSamplingRate();
477
$limit = $filter->GetVectorsLimit();
478
if ($limit) $ivl->SetItemLimit($limit);
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;
491
foreach ($this->itemList as $key => $value) {
492
if (strcmp($grp->gid, $key)) continue;
498
if (($mask)&&(is_array($ids = $mask->GetIDs()))) {
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));
504
array_push($tmp, $itemList[$id]);
508
return new COUCHData($this->view_url, $this->alldata_view, $this->req->GetGroupOptions($grp), $items, $ivl);