MIDAS
Loading...
Searching...
No Matches
mjsonrpc.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: mjsonrpc.cxx
4 Created by: Konstantin Olchanski
5
6 Contents: handler of MIDAS standard JSON-RPC requests
7
8\********************************************************************/
9
10#undef NDEBUG // midas required assert() to be always enabled
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <assert.h>
15#include <map>
16
17#include "mjson.h"
18#include "midas.h"
19#include "msystem.h"
20#include "mstrlcpy.h"
21
22#include "mjsonrpc.h"
23
24#include <mutex> // std::mutex
25
27//
28// Specifications for JSON-RPC
29//
30// https://tools.ietf.org/html/rfc4627 - JSON RFC
31// http://www.jsonrpc.org/specification - specification of JSON-RPC 2.0
32// http://www.simple-is-better.org/json-rpc/transport_http.html
33//
34// NB - MIDAS JSON (odb.c and mjson.cxx) encode IEEE754/854 numeric values
35// NaN and +/-Inf into JSON strings "NaN", "Infinity" and "-Infinity"
36// for reasons unknown, the JSON standard does not specify a standard
37// way for encoding these numeric values.
38//
39// NB - Batch requests are processed in order and the returned array of responses
40// has the resonses in exactly same order as the requests for simpler
41// matching of requests and responses - 1st response to 1st request,
42// 2nd response to 2nd request and so forth.
43//
45//
46// JSON-RPC error codes:
47//
48// -32700 Parse error Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
49// -32600 Invalid Request The JSON sent is not a valid Request object.
50// -32601 Method not found The method does not exist / is not available.
51// -32602 Invalid params Invalid method parameter(s).
52// -32603 Internal error Internal JSON-RPC error.
53// -32000 to -32099 Server error Reserved for implementation-defined server-errors.
54//
55// Typical JSON-RPC request:
56//
57// {
58// "jsonrpc": "2.0",
59// "method": "sum",
60// "params": { "b": 34, "c": 56, "a": 12 },
61// "id": 123
62// }
63//
64// Typical JSON-RPC reply:
65//
66// {
67// "jsonrpc": "2.0",
68// "result": 102,
69// "id": 5
70// }
71//
72// Typical error reply:
73//
74// {
75// "jsonrpc": "2.0",
76// "error": {
77// "code": -32600,
78// "message": "Invalid Request.",
79// "data": "'method' is missing"
80// },
81// "id": 6
82// }
83// }
84//
86//
87// JSON-RPC is documented via an automatically generated JSON Schema.
88//
89// For more information about JSON Schemas, see:
90//
91// https://tools.ietf.org/html/draft-zyp-json-schema-04
92// http://spacetelescope.github.io/understanding-json-schema/
93// http://json-schema.org/
94//
95// JSON Schema examples:
96// http://json-schema.org/examples.html
97// http://json-schema.org/example1.html
98//
99// JSON Schema visualization: (schema file has to have a .json extension)
100// https://github.com/lbovet/docson
101//
102// Non-standard proposed JSON-RPC schema is *NOT* used: (no visualization tools)
103// http://www.simple-is-better.org/json-rpc/jsonrpc20-schema-service-descriptor.html
104//
105// Variances of MIDAS JSON-RPC Schema from standard:
106//
107// - optional parameters end with "?" and have an "optional:true" attribute, i.e. "bUnique?"
108// - array parameters end with "[]", JSON Schema array schema is not generated yet
109//
111
112int mjsonrpc_debug = 0; // in mjsonrpc.h
113static int mjsonrpc_sleep = 0;
114static int mjsonrpc_time = 0;
115
116static double GetTimeSec()
117{
118 struct timeval tv;
119 gettimeofday(&tv, NULL);
120 return tv.tv_sec*1.0 + tv.tv_usec/1000000.0;
121}
122
123MJsonNode* mjsonrpc_make_error(int code, const char* message, const char* data)
124{
125 MJsonNode* errnode = MJsonNode::MakeObject();
126 errnode->AddToObject("code", MJsonNode::MakeInt(code));
127 errnode->AddToObject("message", MJsonNode::MakeString(message));
128 errnode->AddToObject("data", MJsonNode::MakeString(data));
129
130 MJsonNode* result = MJsonNode::MakeObject();
131 result->AddToObject("error", errnode);
132 return result;
133}
134
135MJsonNode* mjsonrpc_make_result(MJsonNode* node)
136{
137 MJsonNode* result = MJsonNode::MakeObject();
138 result->AddToObject("result", node);
139 return result;
140}
141
142MJsonNode* mjsonrpc_make_result(const char* name, MJsonNode* value, const char* name2, MJsonNode* value2, const char* name3, MJsonNode* value3)
143{
144 MJsonNode* node = MJsonNode::MakeObject();
145
146 if (name)
147 node->AddToObject(name, value);
148 if (name2)
149 node->AddToObject(name2, value2);
150 if (name3)
151 node->AddToObject(name3, value3);
152
153 MJsonNode* result = MJsonNode::MakeObject();
154 result->AddToObject("result", node);
155 return result;
156}
157
158MJsonNode* mjsonrpc_make_result(const char* name, MJsonNode* value, const char* name2, MJsonNode* value2, const char* name3, MJsonNode* value3, const char* name4, MJsonNode* value4)
159{
160 MJsonNode* node = MJsonNode::MakeObject();
161
162 if (name)
163 node->AddToObject(name, value);
164 if (name2)
165 node->AddToObject(name2, value2);
166 if (name3)
167 node->AddToObject(name3, value3);
168 if (name4)
169 node->AddToObject(name4, value4);
170
171 MJsonNode* result = MJsonNode::MakeObject();
172 result->AddToObject("result", node);
173 return result;
174}
175
176static MJsonNode* gNullNode = NULL;
177
178const MJsonNode* mjsonrpc_get_param(const MJsonNode* params, const char* name, MJsonNode** error)
179{
180 assert(gNullNode != NULL);
181
182 // NULL params is a request for documentation, return an empty object
183 if (!params) {
184 if (error)
185 *error = MJsonNode::MakeObject();
186 return gNullNode;
187 }
188
189 const MJsonNode* obj = params->FindObjectNode(name);
190 if (!obj) {
191 if (error)
192 *error = mjsonrpc_make_error(-32602, "Invalid params", (std::string("missing parameter: ") + name).c_str());
193 return gNullNode;
194 }
195
196 if (error)
197 *error = NULL;
198 return obj;
199}
200
201const MJsonNodeVector* mjsonrpc_get_param_array(const MJsonNode* params, const char* name, MJsonNode** error)
202{
203 // NULL params is a request for documentation, return NULL
204 if (!params) {
205 if (error)
206 *error = MJsonNode::MakeObject();
207 return NULL;
208 }
209
210 const MJsonNode* node = mjsonrpc_get_param(params, name, error);
211
212 // handle error return from mjsonrpc_get_param()
213 if (error && *error) {
214 return NULL;
215 }
216
217 const MJsonNodeVector* v = node->GetArray();
218
219 if (!v) {
220 if (error)
221 *error = mjsonrpc_make_error(-32602, "Invalid params", (std::string("parameter must be an array: ") + name).c_str());
222 return NULL;
223 }
224
225 if (error)
226 *error = NULL;
227 return v;
228}
229
230MJSO* MJSO::MakeObjectSchema(const char* description) // constructor for object schema
231{
232 MJSO* p = new MJSO();
233 if (description)
234 p->AddToObject("description", MJsonNode::MakeString(description));
235 p->AddToObject("type", MJsonNode::MakeString("object"));
236 p->properties = MJsonNode::MakeObject();
237 p->required = MJsonNode::MakeArray();
238 p->AddToObject("properties", p->properties);
239 p->AddToObject("required", p->required);
240 return p;
241}
242
243MJSO* MJSO::MakeArraySchema(const char* description) // constructor for array schema
244{
245 MJSO* p = new MJSO();
246 p->AddToObject("description", MJsonNode::MakeString(description));
247 p->AddToObject("type", MJsonNode::MakeString("array"));
248 p->items = MJsonNode::MakeArray();
249 p->AddToObject("items", p->items);
250 return p;
251}
252
253static std::string remove(const std::string s, char c)
254{
255 std::string::size_type pos = s.find(c);
256 if (pos == std::string::npos)
257 return s;
258 else
259 return s.substr(0, pos);
260}
261
262void MJSO::AddToSchema(MJsonNode* s, const char* xname)
263{
264 if (!xname)
265 xname = "";
266
267 bool optional = strchr(xname, '?');
268 bool array = strchr(xname, '[');
269
270 // remove the "?" and "[]" marker characters
271 std::string name = xname;
272 name = remove(name, '?');
273 name = remove(name, '[');
274 name = remove(name, ']');
275
276 if (optional)
277 s->AddToObject("optional", MJsonNode::MakeBool(true));
278
279 if (array) { // insert an array schema
280 MJSO* ss = MakeArraySchema(s->FindObjectNode("description")->GetString().c_str());
281 s->DeleteObjectNode("description");
282 ss->AddToSchema(s, "");
283 s = ss;
284 }
285
286 if (items)
287 items->AddToArray(s);
288 else {
289 assert(properties);
290 assert(required);
291 properties->AddToObject(name.c_str(), s);
292 if (!optional) {
293 required->AddToArray(MJsonNode::MakeString(name.c_str()));
294 }
295 }
296}
297
299{
300 return MakeObjectSchema(NULL);
301}
302
303void MJSO::D(const char* description)
304{
305 this->AddToObject("description", MJsonNode::MakeString(description));
306}
307
309{
310 if (!params) {
311 params = MakeObjectSchema(NULL);
312 this->AddToSchema(params, "params");
313 }
314 return params;
315}
316
318{
319 if (!result) {
320 result = MakeObjectSchema(NULL);
321 this->AddToSchema(result, "result");
322 }
323 return result;
324}
325
327{
329 this->AddToSchema(s, "params");
330 return s;
331}
332
334{
336 this->AddToSchema(s, "result");
337 return s;
338}
339
340void MJSO::P(const char* name, int mjson_type, const char* description)
341{
342 if (name == NULL)
343 this->Add("params", mjson_type, description);
344 else
345 Params()->Add(name, mjson_type, description);
346}
347
348void MJSO::R(const char* name, int mjson_type, const char* description)
349{
350 if (name == NULL)
351 this->Add("result", mjson_type, description);
352 else
353 Result()->Add(name, mjson_type, description);
354}
355
356void MJSO::Add(const char* name, int mjson_type, const char* description)
357{
358 MJsonNode* p = MJsonNode::MakeObject();
359 p->AddToObject("description", MJsonNode::MakeString(description));
360 if (mjson_type == MJSON_ARRAY)
361 p->AddToObject("type", MJsonNode::MakeString("array"));
362 else if (mjson_type == MJSON_OBJECT)
363 p->AddToObject("type", MJsonNode::MakeString("object"));
364 else if (mjson_type == MJSON_STRING)
365 p->AddToObject("type", MJsonNode::MakeString("string"));
366 else if (mjson_type == MJSON_INT)
367 p->AddToObject("type", MJsonNode::MakeString("integer"));
368 else if (mjson_type == MJSON_NUMBER)
369 p->AddToObject("type", MJsonNode::MakeString("number"));
370 else if (mjson_type == MJSON_BOOL)
371 p->AddToObject("type", MJsonNode::MakeString("bool"));
372 else if (mjson_type == MJSON_NULL)
373 p->AddToObject("type", MJsonNode::MakeString("null"));
374 else if (mjson_type == MJSON_ARRAYBUFFER)
375 p->AddToObject("type", MJsonNode::MakeString("arraybuffer"));
376 else if (mjson_type == MJSON_JSON)
377 p->AddToObject("type", MJsonNode::MakeString("json"));
378 else if (mjson_type == 0)
379 ;
380 else
381 assert(!"invalid value of mjson_type");
382 this->AddToSchema(p, name);
383}
384
385MJSO* MJSO::AddObject(const char* name, const char* description)
386{
388 s->AddToObject("description", MJsonNode::MakeString(description));
389 s->AddToObject("type", MJsonNode::MakeString("object"));
390 this->AddToSchema(s, name);
391 return s;
392}
393
394MJSO* MJSO::AddArray(const char* name, const char* description)
395{
397 s->AddToObject("description", MJsonNode::MakeString(description));
398 s->AddToObject("type", MJsonNode::MakeString("array"));
399 this->AddToSchema(s, name);
400 return s;
401}
402
403MJSO::MJSO() // ctor
404 : MJsonNode(MJSON_OBJECT)
405{
406 properties = NULL;
407 required = NULL;
408 items = NULL;
409 params = NULL;
410 result = NULL;
411}
412
413static MJsonNode* xnull(const MJsonNode* params)
414{
415 if (!params) {
416 MJSO* doc = MJSO::I();
417 doc->D("RPC method always returns null");
418 doc->P(NULL, 0, "method parameters are ignored");
419 doc->R(NULL, MJSON_NULL, "always returns null");
420 return doc;
421 }
422
423 return mjsonrpc_make_result(MJsonNode::MakeNull());
424}
425
427//
428// Programs start/stop code goes here
429//
431
432static MJsonNode* js_cm_exist(const MJsonNode* params)
433{
434 if (!params) {
435 MJSO* doc = MJSO::I();
436 doc->D("calls MIDAS cm_exist() to check if given MIDAS program is running");
437 doc->P("name", MJSON_STRING, "name of the program, corresponding to ODB /Programs/name");
438 doc->P("unique?", MJSON_BOOL, "bUnique argument to cm_exist()");
439 doc->R("status", MJSON_INT, "return status of cm_exist()");
440 return doc;
441 }
442
443 MJsonNode* error = NULL;
444
445 std::string name = mjsonrpc_get_param(params, "name", &error)->GetString();
446 if (error)
447 return error;
448
449 int unique = mjsonrpc_get_param(params, "unique", NULL)->GetBool();
450
451 int status = cm_exist(name.c_str(), unique);
452
453 if (mjsonrpc_debug)
454 printf("cm_exist(%s,%d) -> %d\n", name.c_str(), unique, status);
455
456 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
457}
458
459static MJsonNode* js_cm_shutdown(const MJsonNode* params)
460{
461 if (!params) {
462 MJSO *doc = MJSO::I();
463 doc->D("calls MIDAS cm_shutdown() to stop given MIDAS program");
464 doc->P("name", MJSON_STRING, "name of the program, corresponding to ODB /Programs/name");
465 doc->P("unique?", MJSON_BOOL, "bUnique argument to cm_shutdown()");
466 doc->R("status", MJSON_INT, "return status of cm_shutdown()");
467 return doc;
468 }
469
470 MJsonNode* error = NULL;
471
472 std::string name = mjsonrpc_get_param(params, "name", &error)->GetString();
473 if (error)
474 return error;
475
476 int unique = mjsonrpc_get_param(params, "unique", NULL)->GetBool();
477
478 int status = cm_shutdown(name.c_str(), unique);
479
480 if (mjsonrpc_debug)
481 printf("cm_shutdown(%s,%d) -> %d\n", name.c_str(), unique, status);
482
483 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
484}
485
486static MJsonNode* start_program(const MJsonNode* params)
487{
488 if (!params) {
489 MJSO* doc = MJSO::I();
490 doc->D("start MIDAS program defined in ODB /Programs/name");
491 doc->P("name", MJSON_STRING, "name of the program, corresponding to ODB /Programs/name");
492 doc->R("status", MJSON_INT, "return status of ss_system()");
493 return doc;
494 }
495
496 MJsonNode* error = NULL;
497
498 std::string name = mjsonrpc_get_param(params, "name", &error)->GetString(); if (error) return error;
499
500 std::string path = "";
501 path += "/Programs/";
502 path += name;
503 path += "/Start command";
504
505 HNDLE hDB;
507
508 char command[256];
509 int size = sizeof(command);
510 int status = db_get_value(hDB, 0, path.c_str(), command, &size, TID_STRING, FALSE);
511
512 if (status == DB_SUCCESS && command[0]) {
513 status = ss_system(command);
514 }
515
516 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
517}
518
519static MJsonNode* exec_script(const MJsonNode* params)
520{
521 if (!params) {
522 MJSO* doc = MJSO::I();
523 doc->D("execute custom script defined in ODB /Script (scripts show in the menu) or /CustomScript (scripts from custom pages)");
524 doc->P("script?", MJSON_STRING, "Execute ODB /Script/xxx");
525 doc->P("customscript?", MJSON_STRING, "Execute ODB /CustomScript/xxx");
526 doc->R("status", MJSON_INT, "return status of cm_exec_script()");
527 return doc;
528 }
529
530 std::string script = mjsonrpc_get_param(params, "script", NULL)->GetString();
531 std::string customscript = mjsonrpc_get_param(params, "customscript", NULL)->GetString();
532
533 std::string path;
534
535 if (script.length() > 0) {
536 path += "/Script";
537 path += "/";
538 path += script;
539 } else if (customscript.length() > 0) {
540 path += "/CustomScript";
541 path += "/";
542 path += customscript;
543 }
544
545 int status = 0;
546
547 if (path.length() > 0) {
548 status = cm_exec_script(path.c_str());
549 }
550
551 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
552}
553
555//
556// ODB code goes here
557//
559
560static int parse_array_index_list(const char* method, const char* path, std::vector<unsigned> *list)
561{
562 // parse array index in form of:
563 // odbpath[number]
564 // odbpath[number,number]
565 // odbpath[number-number]
566 // or any combination of them, i.e. odbpath[1,10-15,20,30-40]
567
568 const char*s = strchr(path, '[');
569
570 if (!s) {
571 cm_msg(MERROR, method, "expected an array index character \'[\' in \"%s\"", path);
572 return DB_OUT_OF_RANGE;
573 }
574
575 s++; // skip '[' itself
576
577 while (s && (*s != 0)) {
578
579 // check that we have a number
580 if (!isdigit(*s)) {
581 cm_msg(MERROR, method, "expected a number in array index in \"%s\" at \"%s\"", path, s);
582 return DB_OUT_OF_RANGE;
583 }
584
585 unsigned value1 = strtoul(s, (char**)&s, 10);
586
587 // array range,
588 if (*s == '-') {
589 s++; // skip the minus char
590
591 if (!isdigit(*s)) {
592 cm_msg(MERROR, method, "expected a number in array index in \"%s\" at \"%s\"", path, s);
593 return DB_OUT_OF_RANGE;
594 }
595
596 unsigned value2 = strtoul(s, (char**)&s, 10);
597
598 if (value2 >= value1)
599 for (unsigned i=value1; i<=value2; i++)
600 list->push_back(i);
601 else {
602 // this is stupid. simple loop like this
603 // for (unsigned i=value1; i>=value2; i--)
604 // does not work for range 4-0, because value2 is 0,
605 // and x>=0 is always true for unsigned numbers,
606 // so we would loop forever... K.O.
607 for (unsigned i=value1; i!=value2; i--)
608 list->push_back(i);
609 list->push_back(value2);
610 }
611 } else {
612 list->push_back(value1);
613 }
614
615 if (*s == ',') {
616 s++; // skip the comma char
617 continue; // back to the begin of loop
618 }
619
620 if (*s == ']') {
621 s++; // skip the closing bracket
622 s = NULL;
623 continue; // done
624 }
625
626 cm_msg(MERROR, method, "invalid char in array index in \"%s\" at \"%s\"", path, s);
627 return DB_OUT_OF_RANGE;
628 }
629
630#if 0
631 printf("parsed array indices for \"%s\" size is %d: ", path, (int)list->size());
632 for (unsigned i=0; i<list->size(); i++)
633 printf(" %d", (*list)[i]);
634 printf("\n");
635#endif
636
637 return SUCCESS;
638}
639
640static MJsonNode* js_db_get_values(const MJsonNode* params)
641{
642 if (!params) {
643 MJSO* doc = MJSO::I();
644 doc->D("get values of ODB data from given subtrees");
645 doc->P("paths[]", MJSON_STRING, "array of ODB subtree paths, see note on array indices");
646 doc->P("omit_names?", MJSON_BOOL, "omit the /name entries");
647 doc->P("omit_last_written?", MJSON_BOOL, "omit the /last_written entries and the last_written[] result");
648 doc->P("omit_tid?", MJSON_BOOL, "omit the tid[] result");
649 doc->P("omit_old_timestamp?", MJSON_NUMBER, "omit data older than given ODB timestamp");
650 doc->P("preserve_case?", MJSON_BOOL, "preserve the capitalization of ODB key names (WARNING: ODB is not case sensitive); note that this will also have side effect of setting the omit_names option");
651 doc->R("data[]", 0, "values of ODB data for each path, all key names are in lower case, all symlinks are followed");
652 doc->R("status[]", MJSON_INT, "return status of db_copy_json_values() or db_copy_json_index() for each path");
653 doc->R("tid?[]", MJSON_INT, "odb type id for each path, absent if omit_tid is true");
654 doc->R("last_written?[]", MJSON_NUMBER, "last_written value of the ODB subtree for each path, absent if omit_last_written is true");
655 return doc;
656 }
657
658 MJsonNode* error = NULL;
659
660 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
661
662 bool omit_names = mjsonrpc_get_param(params, "omit_names", NULL)->GetBool();
663 bool omit_last_written = mjsonrpc_get_param(params, "omit_last_written", NULL)->GetBool();
664 bool omit_tid = mjsonrpc_get_param(params, "omit_tid", NULL)->GetBool();
665 double xomit_old_timestamp = mjsonrpc_get_param(params, "omit_old_timestamp", NULL)->GetDouble();
666 time_t omit_old_timestamp = (time_t)xomit_old_timestamp;
667 bool preserve_case = mjsonrpc_get_param(params, "preserve_case", NULL)->GetBool();
668
669 MJsonNode* dresult = MJsonNode::MakeArray();
670 MJsonNode* sresult = MJsonNode::MakeArray();
671 MJsonNode* tresult = MJsonNode::MakeArray();
672 MJsonNode* lwresult = MJsonNode::MakeArray();
673
674 HNDLE hDB;
676
677 for (unsigned i=0; i<paths->size(); i++) {
678 int status = 0;
679 HNDLE hkey;
680 KEY key;
681 std::string path = (*paths)[i]->GetString();
682
683 status = db_find_key(hDB, 0, path.c_str(), &hkey);
684 if (status != DB_SUCCESS) {
685 dresult->AddToArray(MJsonNode::MakeNull());
686 sresult->AddToArray(MJsonNode::MakeInt(status));
687 tresult->AddToArray(MJsonNode::MakeNull());
688 lwresult->AddToArray(MJsonNode::MakeNull());
689 continue;
690 }
691
692 status = db_get_key(hDB, hkey, &key);
693 if (status != DB_SUCCESS) {
694 dresult->AddToArray(MJsonNode::MakeNull());
695 sresult->AddToArray(MJsonNode::MakeInt(status));
696 tresult->AddToArray(MJsonNode::MakeNull());
697 lwresult->AddToArray(MJsonNode::MakeNull());
698 continue;
699 }
700
701 if (path.find("[") != std::string::npos) {
702 std::vector<unsigned> list;
703 status = parse_array_index_list("js_db_get_values", path.c_str(), &list);
704
705 if (status != SUCCESS) {
706 dresult->AddToArray(MJsonNode::MakeNull());
707 sresult->AddToArray(MJsonNode::MakeInt(status));
708 tresult->AddToArray(MJsonNode::MakeInt(key.type));
709 lwresult->AddToArray(MJsonNode::MakeInt(key.last_written));
710 continue;
711 }
712
713 if (list.size() > 1) {
714 MJsonNode *ddresult = MJsonNode::MakeArray();
715 MJsonNode *ssresult = MJsonNode::MakeArray();
716
717 for (unsigned i=0; i<list.size(); i++) {
718 char* buf = NULL;
719 int bufsize = 0;
720 int end = 0;
721
722 status = db_copy_json_index(hDB, hkey, list[i], &buf, &bufsize, &end);
723 if (status == DB_SUCCESS) {
724 ss_repair_utf8(buf);
725 ddresult->AddToArray(MJsonNode::MakeJSON(buf));
726 ssresult->AddToArray(MJsonNode::MakeInt(status));
727 } else {
728 ddresult->AddToArray(MJsonNode::MakeNull());
729 ssresult->AddToArray(MJsonNode::MakeInt(status));
730 }
731
732 if (buf)
733 free(buf);
734 }
735
736 dresult->AddToArray(ddresult);
737 sresult->AddToArray(ssresult);
738 tresult->AddToArray(MJsonNode::MakeInt(key.type));
739 lwresult->AddToArray(MJsonNode::MakeInt(key.last_written));
740
741 } else {
742 char* buf = NULL;
743 int bufsize = 0;
744 int end = 0;
745
746 status = db_copy_json_index(hDB, hkey, list[0], &buf, &bufsize, &end);
747 if (status == DB_SUCCESS) {
748 ss_repair_utf8(buf);
749 dresult->AddToArray(MJsonNode::MakeJSON(buf));
750 sresult->AddToArray(MJsonNode::MakeInt(status));
751 tresult->AddToArray(MJsonNode::MakeInt(key.type));
752 lwresult->AddToArray(MJsonNode::MakeInt(key.last_written));
753 } else {
754 dresult->AddToArray(MJsonNode::MakeNull());
755 sresult->AddToArray(MJsonNode::MakeInt(status));
756 tresult->AddToArray(MJsonNode::MakeInt(key.type));
757 lwresult->AddToArray(MJsonNode::MakeInt(key.last_written));
758 }
759
760 if (buf)
761 free(buf);
762 }
763 } else {
764 char* buf = NULL;
765 int bufsize = 0;
766 int end = 0;
767
768 status = db_copy_json_values(hDB, hkey, &buf, &bufsize, &end, omit_names,
769 omit_last_written, omit_old_timestamp, preserve_case);
770
771 if (status == DB_SUCCESS) {
772 ss_repair_utf8(buf);
773 dresult->AddToArray(MJsonNode::MakeJSON(buf));
774 sresult->AddToArray(MJsonNode::MakeInt(status));
775 tresult->AddToArray(MJsonNode::MakeInt(key.type));
776 lwresult->AddToArray(MJsonNode::MakeInt(key.last_written));
777 } else {
778 dresult->AddToArray(MJsonNode::MakeNull());
779 sresult->AddToArray(MJsonNode::MakeInt(status));
780 tresult->AddToArray(MJsonNode::MakeInt(key.type));
781 lwresult->AddToArray(MJsonNode::MakeInt(key.last_written));
782 }
783
784 if (buf)
785 free(buf);
786 }
787 }
788
789 MJsonNode* result = MJsonNode::MakeObject();
790
791 result->AddToObject("data", dresult);
792 result->AddToObject("status", sresult);
793 if (!omit_tid)
794 result->AddToObject("tid", tresult);
795 else
796 delete tresult;
797 if (!omit_last_written)
798 result->AddToObject("last_written", lwresult);
799 else
800 delete lwresult;
801
802 return mjsonrpc_make_result(result);
803}
804
805static MJsonNode* js_db_ls(const MJsonNode* params)
806{
807 if (!params) {
808 MJSO* doc = MJSO::I();
809 doc->D("get contents of given ODB subdirectory in the \"ls\" json encoding - similar to odbedit command \"ls -l\"");
810 doc->P("paths[]", MJSON_STRING, "array of ODB subtree paths");
811 doc->R("data[]", MJSON_OBJECT, "keys and values of ODB data for each path");
812 doc->R("status[]", MJSON_INT, "return status of db_copy_json_ls() for each path");
813 return doc;
814 }
815
816 MJsonNode* error = NULL;
817
818 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
819
820 MJsonNode* dresult = MJsonNode::MakeArray();
821 MJsonNode* sresult = MJsonNode::MakeArray();
822
823 HNDLE hDB;
825
826 for (unsigned i=0; i<paths->size(); i++) {
827 int status = 0;
828 HNDLE hkey;
829 std::string path = (*paths)[i]->GetString();
830
831 status = db_find_key(hDB, 0, path.c_str(), &hkey);
832 if (status != DB_SUCCESS) {
833 dresult->AddToArray(MJsonNode::MakeNull());
834 sresult->AddToArray(MJsonNode::MakeInt(status));
835 continue;
836 }
837
838 char* buf = NULL;
839 int bufsize = 0;
840 int end = 0;
841
842 status = db_copy_json_ls(hDB, hkey, &buf, &bufsize, &end);
843
844 if (status == DB_SUCCESS) {
845 ss_repair_utf8(buf);
846 dresult->AddToArray(MJsonNode::MakeJSON(buf));
847 sresult->AddToArray(MJsonNode::MakeInt(status));
848 } else {
849 dresult->AddToArray(MJsonNode::MakeNull());
850 sresult->AddToArray(MJsonNode::MakeInt(status));
851 }
852
853 if (buf)
854 free(buf);
855 }
856
857 return mjsonrpc_make_result("data", dresult, "status", sresult);
858}
859
860static MJsonNode* js_db_copy(const MJsonNode* params)
861{
862 if (!params) {
863 MJSO* doc = MJSO::I();
864 doc->D("get complete ODB data in the \"save\" json encoding, suitable for reloading with odbedit command \"load\"");
865 doc->P("paths[]", MJSON_STRING, "array of ODB subtree paths");
866 doc->R("data[]", MJSON_OBJECT, "keys and values of ODB data for each path");
867 doc->R("status[]", MJSON_INT, "return status of db_copy_json_save() for each path");
868 return doc;
869 }
870
871 MJsonNode* error = NULL;
872
873 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
874
875 MJsonNode* dresult = MJsonNode::MakeArray();
876 MJsonNode* sresult = MJsonNode::MakeArray();
877
878 HNDLE hDB;
880
881 for (unsigned i=0; i<paths->size(); i++) {
882 int status = 0;
883 HNDLE hkey;
884 std::string path = (*paths)[i]->GetString();
885
886 status = db_find_key(hDB, 0, path.c_str(), &hkey);
887 if (status != DB_SUCCESS) {
888 dresult->AddToArray(MJsonNode::MakeNull());
889 sresult->AddToArray(MJsonNode::MakeInt(status));
890 continue;
891 }
892
893 char* buf = NULL;
894 int bufsize = 0;
895 int end = 0;
896
897 status = db_copy_json_save(hDB, hkey, &buf, &bufsize, &end);
898
899 if (status == DB_SUCCESS) {
900 ss_repair_utf8(buf);
901 dresult->AddToArray(MJsonNode::MakeJSON(buf));
902 sresult->AddToArray(MJsonNode::MakeInt(status));
903 } else {
904 dresult->AddToArray(MJsonNode::MakeNull());
905 sresult->AddToArray(MJsonNode::MakeInt(status));
906 }
907
908 if (buf)
909 free(buf);
910 }
911
912 return mjsonrpc_make_result("data", dresult, "status", sresult);
913}
914
915static MJsonNode* js_db_paste(const MJsonNode* params)
916{
917 if (!params) {
918 MJSO* doc = MJSO::I();
919 doc->D("write data into ODB");
920 doc->P("paths[]", MJSON_STRING, "array of ODB subtree paths, see note on array indices");
921 doc->P("values[]", 0, "array of data values written to ODB via db_paste_json() for each path");
922 doc->R("status[]", MJSON_INT, "array of return status of db_paste_json() for each path");
923 return doc;
924 }
925
926 MJsonNode* error = NULL;
927
928 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
929 const MJsonNodeVector* values = mjsonrpc_get_param_array(params, "values", &error); if (error) return error;
930
931 if (paths->size() != values->size()) {
932 return mjsonrpc_make_error(-32602, "Invalid params", "paths and values should have the same length");
933 }
934
935 MJsonNode* sresult = MJsonNode::MakeArray();
936
937 HNDLE hDB;
939
940 for (unsigned i=0; i<paths->size(); i++) {
941 int status = 0;
942 HNDLE hkey;
943 std::string path = (*paths)[i]->GetString();
944
945 status = db_find_key(hDB, 0, path.c_str(), &hkey);
946 if (status != DB_SUCCESS) {
947 sresult->AddToArray(MJsonNode::MakeInt(status));
948 continue;
949 }
950
951 const MJsonNode* v = (*values)[i];
952 assert(v != NULL);
953
954 if (path.find("[*]") != std::string::npos) {
955
956 KEY key;
957 db_get_key(hDB, hkey, &key);
958 for (int j=0 ; j<key.num_values ; j++)
959 status = db_paste_json_node(hDB, hkey, j, v);
960
961 } else if (path.find("[") != std::string::npos) {
962 std::vector<unsigned> list;
963 status = parse_array_index_list("js_db_paste", path.c_str(), &list);
964
965 if (status != SUCCESS) {
966 sresult->AddToArray(MJsonNode::MakeInt(status));
967 continue;
968 }
969
970 // supported permutations of array indices and data values:
971 // single index: intarray[1] -> data should be a single value: MJSON_ARRAY is rejected right here, MJSON_OBJECT is rejected by db_paste
972 // multiple index intarray[1,2,3] -> data should be an array of equal length, or
973 // multiple index intarray[1,2,3] -> if data is a single value, all array elements are set to this same value
974
975 if (list.size() < 1) {
976 cm_msg(MERROR, "js_db_paste", "invalid array indices for array path \"%s\"", path.c_str());
977 sresult->AddToArray(MJsonNode::MakeInt(DB_TYPE_MISMATCH));
978 continue;
979 } else if (list.size() == 1) {
980 if (v->GetType() == MJSON_ARRAY) {
981 cm_msg(MERROR, "js_db_paste", "unexpected array of values for array path \"%s\"", path.c_str());
982 sresult->AddToArray(MJsonNode::MakeInt(DB_TYPE_MISMATCH));
983 continue;
984 }
985
986 status = db_paste_json_node(hDB, hkey, list[0], v);
987 sresult->AddToArray(MJsonNode::MakeInt(status));
988 } else if ((list.size() > 1) && (v->GetType() == MJSON_ARRAY)) {
989 const MJsonNodeVector* vvalues = v->GetArray();
990
991 if (list.size() != vvalues->size()) {
992 cm_msg(MERROR, "js_db_paste", "length of values array %d should be same as number of indices %d for array path \"%s\"", (int)vvalues->size(), (int)list.size(), path.c_str());
993 sresult->AddToArray(MJsonNode::MakeInt(DB_TYPE_MISMATCH));
994 continue;
995 }
996
997 MJsonNode *ssresult = MJsonNode::MakeArray();
998
999 for (unsigned j =0; j <list.size(); j++) {
1000 const MJsonNode* vv = (*vvalues)[j];
1001
1002 if (vv == NULL) {
1003 cm_msg(MERROR, "js_db_paste", "internal error: NULL array value at index %d for array path \"%s\"", j, path.c_str());
1004 sresult->AddToArray(MJsonNode::MakeInt(DB_TYPE_MISMATCH));
1005 continue;
1006 }
1007
1008 status = db_paste_json_node(hDB, hkey, list[j], vv);
1009 ssresult->AddToArray(MJsonNode::MakeInt(status));
1010 }
1011
1012 sresult->AddToArray(ssresult);
1013 } else {
1014 MJsonNode *ssresult = MJsonNode::MakeArray();
1015 for (unsigned j =0; j <list.size(); j++) {
1016 status = db_paste_json_node(hDB, hkey, list[j], v);
1017 ssresult->AddToArray(MJsonNode::MakeInt(status));
1018 }
1019 sresult->AddToArray(ssresult);
1020 }
1021 } else {
1022 status = db_paste_json_node(hDB, hkey, 0, v);
1023 sresult->AddToArray(MJsonNode::MakeInt(status));
1024 }
1025 }
1026
1027 return mjsonrpc_make_result("status", sresult);
1028}
1029
1030static MJsonNode* js_db_create(const MJsonNode* params)
1031{
1032 if (!params) {
1033 MJSO* doc = MJSO::I();
1034 doc->D("Create new ODB entries");
1035 MJSO* o = doc->PA("array of ODB paths to be created")->AddObject("", "arguments to db_create_key() and db_set_num_values()");
1036 o->Add("path", MJSON_STRING, "ODB path to be created");
1037 o->Add("type", MJSON_INT, "MIDAS TID_xxx type");
1038 o->Add("array_length?", MJSON_INT, "optional array length, default is 1");
1039 o->Add("string_length?", MJSON_INT, "for TID_STRING, optional string length, default is NAME_LENGTH");
1040 doc->R("status[]", MJSON_INT, "return status of db_create_key(), db_set_num_values() and db_set_data() (for TID_STRING) for each path");
1041 return doc;
1042 }
1043
1044 MJsonNode* sresult = MJsonNode::MakeArray();
1045
1046 const MJsonNodeVector* pp = params->GetArray();
1047
1048 if (!pp) {
1049 delete sresult;
1050 return mjsonrpc_make_error(-32602, "Invalid params", "parameters must be an array of objects");
1051 }
1052
1053 HNDLE hDB;
1055
1056 for (unsigned i=0; i<pp->size(); i++) {
1057 const MJsonNode* p = (*pp)[i];
1058 std::string path = mjsonrpc_get_param(p, "path", NULL)->GetString();
1059 int type = mjsonrpc_get_param(p, "type", NULL)->GetInt();
1060 int array_length = mjsonrpc_get_param(p, "array_length", NULL)->GetInt();
1061 int string_length = mjsonrpc_get_param(p, "string_length", NULL)->GetInt();
1062
1063 //printf("create odb [%s], type %d, array %d, string %d\n", path.c_str(), type, array_length, string_length);
1064
1065 if (string_length == 0)
1066 string_length = NAME_LENGTH;
1067
1068 int status = db_create_key(hDB, 0, path.c_str(), type);
1069
1070 if (status == DB_SUCCESS && string_length > 0 && type == TID_STRING) {
1071 HNDLE hKey;
1072 status = db_find_key(hDB, 0, path.c_str(), &hKey);
1073 if (status == DB_SUCCESS) {
1074 char* buf = (char*)calloc(1, string_length);
1075 assert(buf != NULL);
1076 int size = string_length;
1077 status = db_set_data(hDB, hKey, buf, size, 1, TID_STRING);
1078 free(buf);
1079 }
1080 }
1081
1082 if (status == DB_SUCCESS && array_length > 1) {
1083 HNDLE hKey;
1084 status = db_find_key(hDB, 0, path.c_str(), &hKey);
1085 if (status == DB_SUCCESS)
1086 status = db_set_num_values(hDB, hKey, array_length);
1087 }
1088
1089 sresult->AddToArray(MJsonNode::MakeInt(status));
1090 }
1091
1092 return mjsonrpc_make_result("status", sresult);
1093}
1094
1095static MJsonNode* js_db_delete(const MJsonNode* params)
1096{
1097 if (!params) {
1098 MJSO* doc = MJSO::I();
1099 doc->D("delete ODB keys");
1100 doc->P("paths[]", MJSON_STRING, "array of ODB paths to delete");
1101 doc->R("status[]", MJSON_INT, "return status of db_delete_key() for each path");
1102 return doc;
1103 }
1104
1105 MJsonNode* error = NULL;
1106
1107 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
1108
1109 MJsonNode* sresult = MJsonNode::MakeArray();
1110
1111 HNDLE hDB;
1113
1114 for (unsigned i=0; i<paths->size(); i++) {
1115 std::string path = (*paths)[i]->GetString();
1116 int status = db_delete(hDB, 0, path.c_str());
1117 sresult->AddToArray(MJsonNode::MakeInt(status));
1118 }
1119
1120 return mjsonrpc_make_result("status", sresult);
1121}
1122
1123static MJsonNode* js_db_resize(const MJsonNode* params)
1124{
1125 if (!params) {
1126 MJSO* doc = MJSO::I();
1127 doc->D("Change size of ODB arrays");
1128 doc->P("paths[]", MJSON_STRING, "array of ODB paths to resize");
1129 doc->P("new_lengths[]", MJSON_INT, "array of new lengths for each ODB path");
1130 doc->R("status[]", MJSON_INT, "return status of db_set_num_values() for each path");
1131 return doc;
1132 }
1133
1134 MJsonNode* error = NULL;
1135
1136 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
1137 const MJsonNodeVector* lengths = mjsonrpc_get_param_array(params, "new_lengths", &error); if (error) return error;
1138
1139 if (paths->size() != lengths->size()) {
1140 return mjsonrpc_make_error(-32602, "Invalid params", "arrays \"paths\" and \"new_lengths\" should have the same length");
1141 }
1142
1143 MJsonNode* sresult = MJsonNode::MakeArray();
1144
1145 HNDLE hDB;
1147
1148 for (unsigned i=0; i<paths->size(); i++) {
1149 int status = 0;
1150 HNDLE hkey;
1151 std::string path = (*paths)[i]->GetString();
1152
1153 status = db_find_key(hDB, 0, path.c_str(), &hkey);
1154 if (status != DB_SUCCESS) {
1155 sresult->AddToArray(MJsonNode::MakeInt(status));
1156 continue;
1157 }
1158
1159 int length = (*lengths)[i]->GetInt();
1160 if (length < 1) {
1161 sresult->AddToArray(MJsonNode::MakeInt(DB_INVALID_PARAM));
1162 continue;
1163 }
1164
1165 status = db_set_num_values(hDB, hkey, length);
1166 sresult->AddToArray(MJsonNode::MakeInt(status));
1167 }
1168
1169 return mjsonrpc_make_result("status", sresult);
1170}
1171
1172static MJsonNode* js_db_resize_string(const MJsonNode* params)
1173{
1174 if (!params) {
1175 MJSO* doc = MJSO::I();
1176 doc->D("Change size of ODB string arrays");
1177 doc->P("paths[]", MJSON_STRING, "array of ODB paths to resize");
1178 doc->P("new_lengths[]", MJSON_INT, "array of new lengths for each ODB path");
1179 doc->P("new_string_lengths[]", MJSON_INT, "array of new string lengths for each ODB path");
1180 doc->R("status[]", MJSON_INT, "return status of db_resize_string() for each path");
1181 return doc;
1182 }
1183
1184 MJsonNode* error = NULL;
1185
1186 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
1187 const MJsonNodeVector* lengths = mjsonrpc_get_param_array(params, "new_lengths", &error); if (error) return error;
1188 const MJsonNodeVector* string_lengths = mjsonrpc_get_param_array(params, "new_string_lengths", &error); if (error) return error;
1189
1190 if (paths->size() != lengths->size()) {
1191 return mjsonrpc_make_error(-32602, "Invalid params", "arrays \"paths\" and \"new_lengths\" should have the same length");
1192 }
1193
1194 if (paths->size() != string_lengths->size()) {
1195 return mjsonrpc_make_error(-32602, "Invalid params", "arrays \"paths\" and \"new_string_lengths\" should have the same length");
1196 }
1197
1198 MJsonNode* sresult = MJsonNode::MakeArray();
1199
1200 HNDLE hDB;
1202
1203 for (unsigned i=0; i<paths->size(); i++) {
1204 std::string path = (*paths)[i]->GetString();
1205
1206 int length = (*lengths)[i]->GetInt();
1207 if (length < 0) {
1208 sresult->AddToArray(MJsonNode::MakeInt(DB_INVALID_PARAM));
1209 continue;
1210 }
1211
1212 int string_length = (*string_lengths)[i]->GetInt();
1213 if (length < 0) {
1214 sresult->AddToArray(MJsonNode::MakeInt(DB_INVALID_PARAM));
1215 continue;
1216 }
1217
1218 int status = db_resize_string(hDB, 0, path.c_str(), length, string_length);
1219 sresult->AddToArray(MJsonNode::MakeInt(status));
1220 }
1221
1222 return mjsonrpc_make_result("status", sresult);
1223}
1224
1225static MJsonNode* js_db_key(const MJsonNode* params)
1226{
1227 if (!params) {
1228 MJSO* doc = MJSO::I();
1229 doc->D("get ODB keys");
1230 doc->P("paths[]", MJSON_STRING, "array of ODB paths");
1231 doc->R("status[]", MJSON_INT, "return status of db_key() for each path");
1232 doc->R("keys[]", MJSON_OBJECT, "key data for each path");
1233 doc->R("keys[].type", MJSON_INT, "key type TID_xxx");
1234 doc->R("keys[].num_values", MJSON_INT, "array length, 1 for normal entries");
1235 doc->R("keys[].name", MJSON_STRING, "key name");
1236 doc->R("keys[].total_size", MJSON_INT, "data total size in bytes");
1237 doc->R("keys[].item_size", MJSON_INT, "array element size, string length for TID_STRING");
1238 doc->R("keys[].access_mode", MJSON_INT, "access mode bitmap of MODE_xxx");
1239 doc->R("keys[].notify_count", MJSON_INT, "number of hotlinks attached to this key");
1240 doc->R("keys[].last_written", MJSON_INT, "timestamp when data was last updated");
1241 return doc;
1242 }
1243
1244 MJsonNode* error = NULL;
1245
1246 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
1247
1248 MJsonNode* kresult = MJsonNode::MakeArray();
1249 MJsonNode* sresult = MJsonNode::MakeArray();
1250
1251 HNDLE hDB;
1253
1254 for (unsigned i=0; i<paths->size(); i++) {
1255 int status = 0;
1256 HNDLE hkey;
1257 KEY key;
1258 std::string path = (*paths)[i]->GetString();
1259
1260 status = db_find_key(hDB, 0, path.c_str(), &hkey);
1261 if (status != DB_SUCCESS) {
1262 kresult->AddToArray(MJsonNode::MakeNull());
1263 sresult->AddToArray(MJsonNode::MakeInt(status));
1264 continue;
1265 }
1266
1267 status = db_get_key(hDB, hkey, &key);
1268 if (status != DB_SUCCESS) {
1269 kresult->AddToArray(MJsonNode::MakeNull());
1270 sresult->AddToArray(MJsonNode::MakeInt(status));
1271 continue;
1272 }
1273
1274 MJsonNode* jkey = MJsonNode::MakeObject();
1275
1276 jkey->AddToObject("type", MJsonNode::MakeInt(key.type));
1277 jkey->AddToObject("num_values", MJsonNode::MakeInt(key.num_values));
1279 jkey->AddToObject("name", MJsonNode::MakeString(key.name));
1280 jkey->AddToObject("total_size", MJsonNode::MakeInt(key.total_size));
1281 jkey->AddToObject("item_size", MJsonNode::MakeInt(key.item_size));
1282 jkey->AddToObject("access_mode", MJsonNode::MakeInt(key.access_mode));
1283 jkey->AddToObject("notify_count", MJsonNode::MakeInt(key.notify_count));
1284 jkey->AddToObject("last_written", MJsonNode::MakeInt(key.last_written));
1285
1286 kresult->AddToArray(jkey);
1287 sresult->AddToArray(MJsonNode::MakeInt(status));
1288 }
1289
1290 return mjsonrpc_make_result("keys", kresult, "status", sresult);
1291}
1292
1293static MJsonNode* js_db_rename(const MJsonNode* params)
1294{
1295 if (!params) {
1296 MJSO* doc = MJSO::I();
1297 doc->D("Change size of ODB arrays");
1298 doc->P("paths[]", MJSON_STRING, "array of ODB paths to rename");
1299 doc->P("new_names[]", MJSON_STRING, "array of new names for each ODB path");
1300 doc->R("status[]", MJSON_INT, "return status of db_rename_key() for each path");
1301 return doc;
1302 }
1303
1304 MJsonNode* error = NULL;
1305
1306 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
1307 const MJsonNodeVector* names = mjsonrpc_get_param_array(params, "new_names", &error); if (error) return error;
1308
1309 if (paths->size() != names->size()) {
1310 return mjsonrpc_make_error(-32602, "Invalid params", "arrays \"paths\" and \"new_names\" should have the same length");
1311 }
1312
1313 MJsonNode* sresult = MJsonNode::MakeArray();
1314
1315 HNDLE hDB;
1317
1318 for (unsigned i=0; i<paths->size(); i++) {
1319 int status = 0;
1320 HNDLE hkey;
1321 std::string path = (*paths)[i]->GetString();
1322
1323 status = db_find_link(hDB, 0, path.c_str(), &hkey);
1324 if (status != DB_SUCCESS) {
1325 sresult->AddToArray(MJsonNode::MakeInt(status));
1326 continue;
1327 }
1328
1329 std::string new_name = (*names)[i]->GetString();
1330 if (new_name.length() < 1) {
1331 sresult->AddToArray(MJsonNode::MakeInt(DB_INVALID_PARAM));
1332 continue;
1333 }
1334
1335 status = db_rename_key(hDB, hkey, new_name.c_str());
1336
1337 sresult->AddToArray(MJsonNode::MakeInt(status));
1338 }
1339
1340 return mjsonrpc_make_result("status", sresult);
1341}
1342
1343static MJsonNode* js_db_link(const MJsonNode* params)
1344{
1345 if (!params) {
1346 MJSO* doc = MJSO::I();
1347 doc->D("Create ODB symlinks");
1348 doc->P("new_links[]", MJSON_STRING, "array of new symlinks to be created");
1349 doc->P("target_paths[]", MJSON_STRING, "array of existing ODB paths for each link");
1350 doc->R("status[]", MJSON_INT, "return status of db_create_link() for each path");
1351 return doc;
1352 }
1353
1354 MJsonNode* error = NULL;
1355
1356 const MJsonNodeVector* target_paths = mjsonrpc_get_param_array(params, "target_paths", &error); if (error) return error;
1357 const MJsonNodeVector* new_links = mjsonrpc_get_param_array(params, "new_links", &error); if (error) return error;
1358
1359 if (target_paths->size() != new_links->size()) {
1360 return mjsonrpc_make_error(-32602, "Invalid params", "arrays \"target_paths\" and \"new_links\" should have the same length");
1361 }
1362
1363 MJsonNode* sresult = MJsonNode::MakeArray();
1364
1365 HNDLE hDB;
1367
1368 for (unsigned i=0; i<new_links->size(); i++) {
1369 int status = 0;
1370 std::string target_path = (*target_paths)[i]->GetString();
1371 std::string new_link = (*new_links)[i]->GetString();
1372 if (new_link.length() < 1) {
1373 sresult->AddToArray(MJsonNode::MakeInt(DB_INVALID_PARAM));
1374 continue;
1375 }
1376
1377 status = db_create_link(hDB, 0, new_link.c_str(), target_path.c_str());
1378
1379 sresult->AddToArray(MJsonNode::MakeInt(status));
1380 }
1381
1382 return mjsonrpc_make_result("status", sresult);
1383}
1384
1385static MJsonNode* js_db_reorder(const MJsonNode* params)
1386{
1387 if (!params) {
1388 MJSO* doc = MJSO::I();
1389 doc->D("Change order of ODB keys in a subdirectory");
1390 doc->P("paths[]", MJSON_STRING, "array of new symlinks to be created");
1391 doc->P("indices[]", MJSON_INT, "array of existing ODB paths for each link");
1392 doc->R("status[]", MJSON_INT, "return status of db_reorder_key() for each path");
1393 return doc;
1394 }
1395
1396 MJsonNode* error = NULL;
1397
1398 const MJsonNodeVector* paths = mjsonrpc_get_param_array(params, "paths", &error); if (error) return error;
1399 const MJsonNodeVector* indices = mjsonrpc_get_param_array(params, "indices", &error); if (error) return error;
1400
1401 if (paths->size() != indices->size()) {
1402 return mjsonrpc_make_error(-32602, "Invalid params", "arrays \"paths\" and \"indices\" should have the same length");
1403 }
1404
1405 MJsonNode* sresult = MJsonNode::MakeArray();
1406
1407 HNDLE hDB;
1409
1410 for (unsigned i=0; i<paths->size(); i++) {
1411 int status = 0;
1412 HNDLE hkey;
1413 std::string path = (*paths)[i]->GetString();
1414 int index = (*indices)[i]->GetInt();
1415
1416 status = db_find_key(hDB, 0, path.c_str(), &hkey);
1417 if (status != DB_SUCCESS) {
1418 sresult->AddToArray(MJsonNode::MakeInt(status));
1419 continue;
1420 }
1421
1422 status = db_reorder_key(hDB, hkey, index);
1423
1424 sresult->AddToArray(MJsonNode::MakeInt(status));
1425 }
1426
1427 return mjsonrpc_make_result("status", sresult);
1428}
1429
1430static MJsonNode* js_db_sor(const MJsonNode* params)
1431{
1432 if (!params) {
1433 MJSO* doc = MJSO::I();
1434 doc->D("Show ODB open records starting from given ODB path");
1435 doc->P("path?", MJSON_STRING, "ODB path");
1436 doc->R("sor", MJSON_JSON, "return value of db_sor()");
1437 return doc;
1438 }
1439
1440 MJsonNode* error = NULL;
1441
1442 std::string path = mjsonrpc_get_param(params, "path", NULL)->GetString(); if (error) return error;
1443
1444 HNDLE hDB;
1446
1447 MJsonNode* sor = db_sor(hDB, path.c_str());
1448
1449 return mjsonrpc_make_result("sor", sor);
1450}
1451
1452static MJsonNode* js_db_scl(const MJsonNode* params)
1453{
1454 if (!params) {
1455 MJSO* doc = MJSO::I();
1456 doc->D("Show ODB clients");
1457 doc->R("scl", MJSON_JSON, "return value of db_scl()");
1458 return doc;
1459 }
1460
1461 HNDLE hDB;
1463
1464 MJsonNode* scl = db_scl(hDB);
1465
1466 return mjsonrpc_make_result("scl", scl);
1467}
1468
1470//
1471// cm_msg code goes here
1472//
1474
1475static MJsonNode* js_cm_msg_facilities(const MJsonNode* params)
1476{
1477 if (!params) {
1478 MJSO* doc = MJSO::I();
1479 doc->D("get message facilities using cm_msg_facilities()");
1480 doc->R("status", MJSON_INT, "return status of cm_msg_facilities()");
1481 doc->R("facilities[]", MJSON_STRING, "array of facility names");
1482 return doc;
1483 }
1484
1486
1488
1489 MJsonNode* facilities = MJsonNode::MakeArray();
1490
1491 for (unsigned i=0; i<list.size(); i++) {
1493 facilities->AddToArray(MJsonNode::MakeString(list[i].c_str()));
1494 }
1495
1496 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status),
1497 "facilities", facilities);
1498}
1499
1500static MJsonNode* js_cm_msg1(const MJsonNode* params)
1501{
1502 if (!params) {
1503 MJSO *doc = MJSO::I();
1504 doc->D("Generate a midas message using cm_msg1()");
1505 doc->P("facility?", MJSON_STRING, "message facility, default is \"midas\"");
1506 doc->P("user?", MJSON_STRING, "message user, default is \"javascript_commands\"");
1507 doc->P("type?", MJSON_INT, "message type, MT_xxx from midas.h, default is MT_INFO");
1508 doc->P("message", MJSON_STRING, "message text");
1509 doc->R("status", MJSON_INT, "return status of cm_msg1()");
1510 return doc;
1511 }
1512
1513 MJsonNode* error = NULL;
1514
1515 std::string facility = mjsonrpc_get_param(params, "facility", NULL)->GetString();
1516 std::string user = mjsonrpc_get_param(params, "user", NULL)->GetString();
1517 int type = mjsonrpc_get_param(params, "type", NULL)->GetInt();
1518 std::string message = mjsonrpc_get_param(params, "message", &error)->GetString(); if (error) return error;
1519
1520 if (facility.size() <1)
1521 facility = "midas";
1522 if (user.size()<1)
1523 user = "javascript_commands";
1524 if (type == 0)
1525 type = MT_INFO;
1526
1527 int status = cm_msg1(type, __FILE__, __LINE__, facility.c_str(), user.c_str(), "%s", message.c_str());
1528
1529 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
1530}
1531
1532static MJsonNode* js_cm_msg_retrieve(const MJsonNode* params)
1533{
1534 if (!params) {
1535 MJSO *doc = MJSO::I();
1536 doc->D("Retrieve midas messages using cm_msg_retrieve2()");
1537 doc->P("facility?", MJSON_STRING, "message facility, default is \"midas\"");
1538 doc->P("min_messages?", MJSON_INT, "get at least this many messages, default is 1");
1539 doc->P("time?", MJSON_NUMBER, "start from given timestamp, value 0 means give me newest messages, default is 0");
1540 doc->R("num_messages", MJSON_INT, "number of messages returned");
1541 doc->R("messages", MJSON_STRING, "messages separated by \\n");
1542 doc->R("status", MJSON_INT, "return status of cm_msg_retrieve2()");
1543 return doc;
1544 }
1545
1546 std::string facility = mjsonrpc_get_param(params, "facility", NULL)->GetString();
1547 int min_messages = mjsonrpc_get_param(params, "min_messages", NULL)->GetInt();
1548 double time = mjsonrpc_get_param(params, "time", NULL)->GetDouble();
1549
1550 if (facility.size() < 1)
1551 facility = "midas";
1552
1553 int num_messages = 0;
1554 char* messages = NULL;
1555
1556 int status = cm_msg_retrieve2(facility.c_str(), (time_t)time, min_messages, &messages, &num_messages);
1557
1558 MJsonNode* result = MJsonNode::MakeObject();
1559
1560 result->AddToObject("status", MJsonNode::MakeInt(status));
1561 result->AddToObject("num_messages", MJsonNode::MakeInt(num_messages));
1562
1563 if (messages) {
1564 ss_repair_utf8(messages);
1565 result->AddToObject("messages", MJsonNode::MakeString(messages));
1566 free(messages);
1567 messages = NULL;
1568 }
1569
1570 return mjsonrpc_make_result(result);
1571}
1572
1574//
1575// Alarm code goes here
1576//
1578
1579static MJsonNode* js_al_reset_alarm(const MJsonNode* params)
1580{
1581 if (!params) {
1582 MJSO* doc = MJSO::I();
1583 doc->D("reset alarms");
1584 doc->P("alarms[]", MJSON_STRING, "array of alarm names");
1585 doc->R("status[]", MJSON_INT, "return status of al_reset_alarm() for each alarm");
1586 return doc;
1587 }
1588
1589 MJsonNode* error = NULL;
1590
1591 const MJsonNodeVector* alarms = mjsonrpc_get_param_array(params, "alarms", &error); if (error) return error;
1592
1593 MJsonNode* sresult = MJsonNode::MakeArray();
1594
1595 for (unsigned i=0; i<alarms->size(); i++) {
1596 int status = al_reset_alarm((*alarms)[i]->GetString().c_str());
1597 sresult->AddToArray(MJsonNode::MakeInt(status));
1598 }
1599
1600 return mjsonrpc_make_result("status", sresult);
1601}
1602
1603static MJsonNode* js_al_trigger_alarm(const MJsonNode* params)
1604{
1605 if (!params) {
1606 MJSO* doc = MJSO::I();
1607 doc->D("trigger an alarm");
1608 doc->P("name", MJSON_STRING, "alarm name");
1609 doc->P("message", MJSON_STRING, "alarm message");
1610 doc->P("class", MJSON_STRING, "alarm class");
1611 doc->P("condition", MJSON_STRING, "alarm condition");
1612 doc->P("type", MJSON_INT, "alarm type (AT_xxx)");
1613 doc->R("status", MJSON_INT, "return status of al_trigger_alarm()");
1614 return doc;
1615 }
1616
1617 MJsonNode* error = NULL;
1618
1619 std::string name = mjsonrpc_get_param(params, "name", &error)->GetString(); if (error) return error;
1620 std::string message = mjsonrpc_get_param(params, "message", &error)->GetString(); if (error) return error;
1621 std::string xclass = mjsonrpc_get_param(params, "class", &error)->GetString(); if (error) return error;
1622 std::string condition = mjsonrpc_get_param(params, "condition", &error)->GetString(); if (error) return error;
1623 int type = mjsonrpc_get_param(params, "type", &error)->GetInt(); if (error) return error;
1624
1625 int status = al_trigger_alarm(name.c_str(), message.c_str(), xclass.c_str(), condition.c_str(), type);
1626
1627 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
1628}
1629
1630static MJsonNode* js_al_trigger_class(const MJsonNode* params)
1631{
1632 if (!params) {
1633 MJSO* doc = MJSO::I();
1634 doc->D("trigger an alarm");
1635 doc->P("class", MJSON_STRING, "alarm class");
1636 doc->P("message", MJSON_STRING, "alarm message");
1637 doc->P("first?", MJSON_BOOL, "see al_trigger_class() in midas.c");
1638 doc->R("status", MJSON_INT, "return status of al_trigger_class()");
1639 return doc;
1640 }
1641
1642 MJsonNode* error = NULL;
1643
1644 std::string xclass = mjsonrpc_get_param(params, "class", &error)->GetString(); if (error) return error;
1645 std::string message = mjsonrpc_get_param(params, "message", &error)->GetString(); if (error) return error;
1646 bool first = mjsonrpc_get_param(params, "first", NULL)->GetBool();
1647
1648 int status = al_trigger_class(xclass.c_str(), message.c_str(), first);
1649
1650 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
1651}
1652
1654//
1655// History code goes here
1656//
1658
1659#include "history.h"
1660
1661static MJsonNode* js_hs_get_active_events(const MJsonNode* params)
1662{
1663 if (!params) {
1664 MJSO* doc = MJSO::I();
1665 doc->D("get list of active history events using hs_read_event_list()");
1666 doc->R("status", MJSON_INT, "return status of hs_read_event_list()");
1667 doc->R("events[]", MJSON_STRING, "array of history event names");
1668 return doc;
1669 }
1670
1672
1674
1675 MJsonNode* events = MJsonNode::MakeArray();
1676
1677 for (unsigned i=0; i<list.size(); i++) {
1679 events->AddToArray(MJsonNode::MakeString(list[i].c_str()));
1680 }
1681
1682 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "events", events);
1683}
1684
1685typedef std::map<std::string,MidasHistoryInterface*> MhiMap;
1686
1688
1690{
1691 // empty name means use the default reader channel
1692
1693 MhiMap::iterator ci = gHistoryChannels.find(name);
1694 if (ci != gHistoryChannels.end()) {
1695 return ci->second;
1696 };
1697
1698 int verbose = 0;
1699
1700 HNDLE hDB;
1702
1703 HNDLE hKey = 0;
1704
1705 if (strlen(name) < 1) {
1707 if (status != HS_SUCCESS) {
1708 return NULL;
1709 }
1710 } else {
1711 HNDLE hKeyChan;
1712 int status = db_find_key(hDB, 0, "/Logger/History", &hKeyChan);
1713 if (status != DB_SUCCESS) {
1714 return NULL;
1715 }
1716 status = db_find_key(hDB, hKeyChan, name, &hKey);
1717 if (status != DB_SUCCESS) {
1718 return NULL;
1719 }
1720 }
1721
1722 MidasHistoryInterface* mh = NULL;
1723
1725 if (status != HS_SUCCESS || mh==NULL) {
1726 cm_msg(MERROR, "GetHistory", "Cannot configure history, hs_get_history() status %d", status);
1727 return NULL;
1728 }
1729
1730 //printf("hs_get_history: \"%s\" -> mh %p\n", name, mh);
1731
1733
1734 // cm_msg(MINFO, "GetHistory", "Reading history channel \"%s\" from channel \'%s\' type \'%s\'", name, mh->name, mh->type);
1735
1736 return mh;
1737}
1738
1739static void js_hs_exit()
1740{
1741 for (auto& e : gHistoryChannels) {
1742 //printf("history channel \"%s\" mh %p\n", e.first.c_str(), e.second);
1743 delete e.second;
1744 }
1745 gHistoryChannels.clear();
1746}
1747
1748static MJsonNode* js_hs_get_channels(const MJsonNode* params)
1749{
1750 if (!params) {
1751 MJSO* doc = MJSO::I();
1752 doc->D("get list of history channels in /Logger/History");
1753 doc->R("status", MJSON_INT, "return success or failure status");
1754 doc->R("default_channel", MJSON_STRING, "name of the default logger history channel");
1755 doc->R("channels[]", MJSON_STRING, "all logger history channel names");
1756 doc->R("active_channels[]", MJSON_STRING, "active logger history channel names");
1757 return doc;
1758 }
1759
1760 MJsonNode* channels = MJsonNode::MakeArray();
1761 MJsonNode* active_channels = MJsonNode::MakeArray();
1762
1763 HNDLE hDB;
1765
1766 // get history channel name selected by user in ODB
1767
1768 //std::string selected_channel;
1769 //db_get_value_string(hDB, 0, "/History/LoggerHistoryChannel", 0, &selected_channel, TRUE);
1770
1771 int status;
1772 HNDLE hKeyChan;
1773
1774 status = db_find_key(hDB, 0, "/Logger/History", &hKeyChan);
1775 if (status == DB_SUCCESS) {
1776 for (int ichan=0; ; ichan++) {
1777 HNDLE hKey;
1778 status = db_enum_key(hDB, hKeyChan, ichan, &hKey);
1779 if (status == DB_NO_MORE_SUBKEYS) {
1781 break;
1782 }
1783 if (status != DB_SUCCESS)
1784 break;
1785
1786 KEY key;
1787
1789
1790 if (status == DB_SUCCESS) {
1792 channels->AddToArray(MJsonNode::MakeString(key.name));
1793
1794 INT active = 0;
1795 INT size = sizeof(active);
1796 status = db_get_value(hDB, hKey, "Active", &active, &size, TID_BOOL, FALSE);
1797 if (status == DB_SUCCESS) {
1798 if (active) {
1799 active_channels->AddToArray(MJsonNode::MakeString(key.name));
1800 }
1801 }
1802 }
1803 }
1804 }
1805
1806 std::string default_channel;
1807
1808 HNDLE hKey;
1810 if (status == DB_SUCCESS) {
1811 KEY key;
1813 if (status == DB_SUCCESS) {
1814 default_channel = key.name;
1815 }
1816 }
1817
1818 return mjsonrpc_make_result("status", MJsonNode::MakeInt(1),
1819 //"selected_channel", MJsonNode::MakeString(selected_channel.c_str()),
1820 "default_channel", MJsonNode::MakeString(default_channel.c_str()),
1821 "active_channels", active_channels,
1822 "channels", channels);
1823}
1824
1825static MJsonNode* js_hs_get_events(const MJsonNode* params)
1826{
1827 if (!params) {
1828 MJSO* doc = MJSO::I();
1829 doc->D("get list of history events that existed at give time using hs_get_events()");
1830 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
1831 doc->P("time?", MJSON_NUMBER, "timestamp, value 0 means current time, default is 0");
1832 doc->R("status", MJSON_INT, "return status of hs_get_events()");
1833 doc->R("channel", MJSON_STRING, "logger history channel name");
1834 doc->R("events[]", MJSON_STRING, "array of history event names");
1835 return doc;
1836 }
1837
1838 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
1839 double time = mjsonrpc_get_param(params, "time", NULL)->GetDouble();
1840
1842
1843 MJsonNode* events = MJsonNode::MakeArray();
1844
1845 if (!mh) {
1846 int status = HS_FILE_ERROR;
1847 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "events", events);
1848 }
1849
1850 if (time == 0) {
1851 time = ::time(NULL);
1852 }
1853
1855
1856 int status = mh->hs_get_events(time, &list);
1857
1858 for (unsigned i=0; i<list.size(); i++) {
1860 events->AddToArray(MJsonNode::MakeString(list[i].c_str()));
1861 }
1862
1863 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "channel", MJsonNode::MakeString(mh->name), "events", events);
1864}
1865
1866static MJsonNode* js_hs_reopen(const MJsonNode* params)
1867{
1868 if (!params) {
1869 MJSO* doc = MJSO::I();
1870 doc->D("reopen the history channel to make sure we see the latest list of events using hs_clear_cache()");
1871 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
1872 doc->R("status", MJSON_INT, "return status of hs_get_events()");
1873 doc->R("channel", MJSON_STRING, "logger history channel name");
1874 return doc;
1875 }
1876
1877 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
1878
1880
1881 if (!mh) {
1882 int status = HS_FILE_ERROR;
1883 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
1884 }
1885
1886 int status = mh->hs_clear_cache();
1887
1888 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "channel", MJsonNode::MakeString(mh->name));
1889}
1890
1891static MJsonNode* js_hs_get_tags(const MJsonNode* params)
1892{
1893 if (!params) {
1894 MJSO* doc = MJSO::I();
1895 doc->D("get list of history tags for given history events that existed at give time using hs_get_tags()");
1896 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
1897 doc->P("time?", MJSON_NUMBER, "timestamp, value 0 means current time, default is 0");
1898 doc->P("events[]?", MJSON_STRING, "array of history event names, default is get all events using hs_get_events()");
1899 doc->R("status", MJSON_INT, "return status");
1900 doc->R("channel", MJSON_STRING, "logger history channel name");
1901 doc->R("events[].name", MJSON_STRING, "array of history event names for each history event");
1902 doc->R("events[].status", MJSON_INT, "array of status ohistory tags for each history event");
1903 doc->R("events[].tags[]", MJSON_STRING, "array of history tags for each history event");
1904 doc->R("events[].tags[].name", MJSON_STRING, "history tag name");
1905 doc->R("events[].tags[].type", MJSON_INT, "history tag midas data type");
1906 doc->R("events[].tags[].n_data?", MJSON_INT, "history tag number of array elements, omitted if 1");
1907 return doc;
1908 }
1909
1910 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
1911 double time = mjsonrpc_get_param(params, "time", NULL)->GetDouble();
1912 const MJsonNodeVector* events_array = mjsonrpc_get_param_array(params, "events", NULL);
1913
1914 if (time == 0) {
1915 time = ::time(NULL);
1916 }
1917
1919
1920 MJsonNode* events = MJsonNode::MakeArray();
1921
1922 if (!mh) {
1923 int status = HS_FILE_ERROR;
1924 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "events", events);
1925 }
1926
1927 std::vector<std::string> event_names;
1928
1929 if (events_array && events_array->size() > 0) {
1930 for (unsigned i=0; i<events_array->size(); i++) {
1931 event_names.push_back((*events_array)[i]->GetString());
1932 }
1933 }
1934
1935 if (event_names.size() < 1) {
1936 int status = mh->hs_get_events(time, &event_names);
1937 if (status != HS_SUCCESS) {
1938 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "events", events);
1939 }
1940 }
1941
1942 for (unsigned i=0; i<event_names.size(); i++) {
1943 MJsonNode* o = MJsonNode::MakeObject();
1944 const char* event_name = event_names[i].c_str();
1945 std::vector<TAG> tags;
1946 int status = mh->hs_get_tags(event_name, time, &tags);
1947 //ss_repair_utf8(event_name); redundant!
1948 o->AddToObject("name", MJsonNode::MakeString(event_name));
1949 o->AddToObject("status", MJsonNode::MakeInt(status));
1950 MJsonNode *ta = MJsonNode::MakeArray();
1951 for (unsigned j=0; j<tags.size(); j++) {
1952 MJsonNode* to = MJsonNode::MakeObject();
1953 ss_repair_utf8(tags[j].name);
1954 to->AddToObject("name", MJsonNode::MakeString(tags[j].name));
1955 to->AddToObject("type", MJsonNode::MakeInt(tags[j].type));
1956 if (tags[j].n_data != 1) {
1957 to->AddToObject("n_data", MJsonNode::MakeInt(tags[j].n_data));
1958 }
1959 ta->AddToArray(to);
1960 }
1961 o->AddToObject("tags", ta);
1962 events->AddToArray(o);
1963 }
1964
1965 int status = HS_SUCCESS;
1966 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "channel", MJsonNode::MakeString(mh->name), "events", events);
1967}
1968
1969static MJsonNode* js_hs_get_last_written(const MJsonNode* params)
1970{
1971 if (!params) {
1972 MJSO* doc = MJSO::I();
1973 doc->D("get list of history tags for given history events that existed at give time using hs_get_last_written()");
1974 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
1975 doc->P("time?", MJSON_NUMBER, "timestamp, value 0 means current time, default is 0");
1976 doc->P("events[]", MJSON_STRING, "array of history event names");
1977 doc->P("tags[]", MJSON_STRING, "array of history event tag names");
1978 doc->P("index[]", MJSON_STRING, "array of history event tag array indices");
1979 doc->R("status", MJSON_INT, "return status");
1980 doc->R("channel", MJSON_STRING, "logger history channel name");
1981 doc->R("last_written[]", MJSON_NUMBER, "array of last-written times for each history event");
1982 return doc;
1983 }
1984
1985 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
1986 double time = mjsonrpc_get_param(params, "time", NULL)->GetDouble();
1987
1988 const MJsonNodeVector* events_array = mjsonrpc_get_param_array(params, "events", NULL);
1989 const MJsonNodeVector* tags_array = mjsonrpc_get_param_array(params, "tags", NULL);
1990 const MJsonNodeVector* index_array = mjsonrpc_get_param_array(params, "index", NULL);
1991
1993
1994 MJsonNode* lw = MJsonNode::MakeArray();
1995
1996 if (!mh) {
1997 int status = HS_FILE_ERROR;
1998 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "last_written", lw);
1999 }
2000
2001 unsigned num_var = events_array->size();
2002
2003 if (tags_array->size() != num_var) {
2004 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and tags should have the same length");
2005 }
2006
2007 if (index_array->size() != num_var) {
2008 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and index should have the same length");
2009 }
2010
2011 std::vector<std::string> event_names(num_var);
2012 std::vector<std::string> tag_names(num_var);
2013 // const char** event_name = new const char*[num_var];
2014 // const char** tag_name = new const char*[num_var];
2015 int* var_index = new int[num_var];
2016 time_t* last_written = new time_t[num_var];
2017
2018 for (unsigned i=0; i<num_var; i++) {
2019 //event_name[i] = (*events_array)[i]->GetString().c_str();
2020 //tag_name[i] = (*tags_array)[i]->GetString().c_str();
2021 event_names[i] = (*events_array)[i]->GetString();
2022 tag_names[i] = (*tags_array)[i]->GetString();
2023 var_index[i] = (*index_array)[i]->GetInt();
2024 }
2025
2026 if (/* DISABLES CODE */ (0)) {
2027 printf("time %f, num_vars %d:\n", time, num_var);
2028 for (unsigned i=0; i<num_var; i++) {
2029 printf("%d: [%s] [%s] [%d]\n", i, event_names[i].c_str(), tag_names[i].c_str(), var_index[i]);
2030 }
2031 }
2032
2033 if (time == 0) {
2034 time = ::time(NULL);
2035 }
2036
2037
2038 const char** event_name = new const char*[num_var];
2039 const char** tag_name = new const char*[num_var];
2040 for (unsigned i=0; i<num_var; i++) {
2041 event_name[i] = event_names[i].c_str();
2042 tag_name[i] = tag_names[i].c_str();
2043 }
2044 int status = mh->hs_get_last_written(time, num_var, event_name, tag_name, var_index, last_written);
2045
2046 for (unsigned i=0; i<num_var; i++) {
2047 if (/* DISABLES CODE */ (0)) {
2048 printf("%d: last_written %d\n", i, (int)last_written[i]);
2049 }
2050 lw->AddToArray(MJsonNode::MakeNumber(last_written[i]));
2051 }
2052
2053 delete[] event_name;
2054 delete[] tag_name;
2055 delete[] var_index;
2056 delete[] last_written;
2057
2058 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "channel", MJsonNode::MakeString(mh->name), "last_written", lw);
2059}
2060
2062{
2063public:
2065 std::string fTimeJson;
2066 std::string fValueJson;
2067
2068public:
2070 {
2071 fCount = 0;
2072
2073 fTimeJson = "[";
2074 fValueJson = "[";
2075 }
2076
2077 void Add(time_t t, double v)
2078 {
2079 //printf("add time %d, value %f\n", (int)t, v);
2080
2081 if (fCount>0) {
2082 fTimeJson += ",";
2083 fValueJson += ",";
2084 }
2085 fCount++;
2086
2087 fTimeJson += MJsonNode::EncodeDouble(t);
2088 fValueJson += MJsonNode::EncodeDouble(v);
2089 }
2090
2091 void Finish()
2092 {
2093 fTimeJson += "]";
2094 fValueJson += "]";
2095 }
2096};
2097
2098static MJsonNode* js_hs_read(const MJsonNode* params)
2099{
2100 if (!params) {
2101 MJSO* doc = MJSO::I();
2102 doc->D("get history data for given history events that existed at give time using hs_read_buffer()");
2103 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
2104 doc->P("start_time", MJSON_NUMBER, "start time of the data");
2105 doc->P("end_time", MJSON_NUMBER, "end time of the data");
2106 doc->P("events[]", MJSON_STRING, "array of history event names");
2107 doc->P("tags[]", MJSON_STRING, "array of history event tag names");
2108 doc->P("index[]", MJSON_STRING, "array of history event tag array indices");
2109 doc->R("status", MJSON_INT, "return status");
2110 doc->R("channel", MJSON_STRING, "logger history channel name");
2111 doc->R("data[]", MJSON_ARRAY, "array of history data");
2112 doc->R("data[].status", MJSON_INT, "status for each event");
2113 doc->R("data[].count", MJSON_INT, "number of data for each event");
2114 doc->R("data[].time[]", MJSON_NUMBER, "time data");
2115 doc->R("data[].value[]", MJSON_NUMBER, "value data");
2116 return doc;
2117 }
2118
2119 MJsonNode* error = NULL;
2120
2121 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
2122 double start_time = mjsonrpc_get_param(params, "start_time", &error)->GetDouble(); if (error) return error;
2123 double end_time = mjsonrpc_get_param(params, "end_time", &error)->GetDouble(); if (error) return error;
2124
2125 const MJsonNodeVector* events_array = mjsonrpc_get_param_array(params, "events", NULL);
2126 const MJsonNodeVector* tags_array = mjsonrpc_get_param_array(params, "tags", NULL);
2127 const MJsonNodeVector* index_array = mjsonrpc_get_param_array(params, "index", NULL);
2128
2130
2131 MJsonNode* data = MJsonNode::MakeArray();
2132
2133 if (!mh) {
2134 int status = HS_FILE_ERROR;
2135 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "data", data);
2136 }
2137
2138 unsigned num_var = events_array->size();
2139
2140 if (tags_array->size() != num_var) {
2141 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and tags should have the same length");
2142 }
2143
2144 if (index_array->size() != num_var) {
2145 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and index should have the same length");
2146 }
2147
2148 std::vector<std::string> event_names(num_var);
2149 std::vector<std::string> tag_names(num_var);
2150 int* var_index = new int[num_var];
2151 JsonHistoryBuffer** jbuf = new JsonHistoryBuffer*[num_var];
2153 int* hs_status = new int[num_var];
2154
2155 for (unsigned i=0; i<num_var; i++) {
2156 //event_name[i] = (*events_array)[i]->GetString().c_str();
2157 //tag_name[i] = (*tags_array)[i]->GetString().c_str();
2158 event_names[i] = (*events_array)[i]->GetString();
2159 tag_names[i] = (*tags_array)[i]->GetString();
2160 var_index[i] = (*index_array)[i]->GetInt();
2161 jbuf[i] = new JsonHistoryBuffer();
2162 buf[i] = jbuf[i];
2163 hs_status[i] = 0;
2164 }
2165
2166 if (/* DISABLES CODE */ (0)) {
2167 printf("time %f %f, num_vars %d:\n", start_time, end_time, num_var);
2168 for (unsigned i=0; i<num_var; i++) {
2169 printf("%d: [%s] [%s] [%d]\n", i, event_names[i].c_str(), tag_names[i].c_str(), var_index[i]);
2170 }
2171 }
2172
2173 const char** event_name = new const char*[num_var];
2174 const char** tag_name = new const char*[num_var];
2175 for (unsigned i=0; i<num_var; i++) {
2176 event_name[i] = event_names[i].c_str();
2177 tag_name[i] = tag_names[i].c_str();
2178 }
2179
2180 int status = mh->hs_read_buffer(start_time, end_time, num_var, event_name, tag_name, var_index, buf, hs_status);
2181
2182 for (unsigned i=0; i<num_var; i++) {
2183 jbuf[i]->Finish();
2184
2185 MJsonNode* obj = MJsonNode::MakeObject();
2186 obj->AddToObject("status", MJsonNode::MakeInt(hs_status[i]));
2187 obj->AddToObject("count", MJsonNode::MakeInt(jbuf[i]->fCount));
2188 obj->AddToObject("time", MJsonNode::MakeJSON(jbuf[i]->fTimeJson.c_str()));
2189 obj->AddToObject("value", MJsonNode::MakeJSON(jbuf[i]->fValueJson.c_str()));
2190 data->AddToArray(obj);
2191
2192 delete jbuf[i];
2193 jbuf[i] = NULL;
2194 buf[i] = NULL;
2195 }
2196
2197 delete[] event_name;
2198 delete[] tag_name;
2199 delete[] var_index;
2200 delete[] buf;
2201 delete[] jbuf;
2202 delete[] hs_status;
2203
2204 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "channel", MJsonNode::MakeString(mh->name), "data", data);
2205}
2206
2207static MJsonNode* js_hs_read_binned(const MJsonNode* params)
2208{
2209 if (!params) {
2210 MJSO* doc = MJSO::I();
2211 doc->D("get history data for given history events that existed at give time using hs_read_buffer()");
2212 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
2213 doc->P("start_time", MJSON_NUMBER, "start time of the data");
2214 doc->P("end_time", MJSON_NUMBER, "end time of the data");
2215 doc->P("num_bins", MJSON_INT, "number of time bins");
2216 doc->P("events[]", MJSON_STRING, "array of history event names");
2217 doc->P("tags[]", MJSON_STRING, "array of history event tag names");
2218 doc->P("index[]", MJSON_STRING, "array of history event tag array indices");
2219 doc->R("status", MJSON_INT, "return status");
2220 doc->R("channel", MJSON_STRING, "logger history channel name");
2221 doc->R("data[]", MJSON_ARRAY, "array of history data");
2222 doc->R("data[].status", MJSON_INT, "status for each event");
2223 doc->R("data[].num_entries", MJSON_INT, "number of data points for each event");
2224 doc->R("data[].count[]", MJSON_INT, "number of data points for each bin");
2225 doc->R("data[].mean[]", MJSON_NUMBER, "mean for each bin");
2226 doc->R("data[].rms[]", MJSON_NUMBER, "rms for each bin");
2227 doc->R("data[].min[]", MJSON_NUMBER, "minimum value for each bin");
2228 doc->R("data[].max[]", MJSON_NUMBER, "maximum value for each bin");
2229 doc->R("data[].bins_first_time[]", MJSON_NUMBER, "first data point in each bin");
2230 doc->R("data[].bins_first_value[]", MJSON_NUMBER, "first data point in each bin");
2231 doc->R("data[].bins_last_time[]", MJSON_NUMBER, "last data point in each bin");
2232 doc->R("data[].bins_last_value[]", MJSON_NUMBER, "last data point in each bin");
2233 doc->R("data[].last_time", MJSON_NUMBER, "time of last data entry");
2234 doc->R("data[].last_value", MJSON_NUMBER, "value of last data entry");
2235 return doc;
2236 }
2237
2238 MJsonNode* error = NULL;
2239
2240 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
2241 double start_time = mjsonrpc_get_param(params, "start_time", &error)->GetDouble(); if (error) return error;
2242 double end_time = mjsonrpc_get_param(params, "end_time", &error)->GetDouble(); if (error) return error;
2243 int num_bins = mjsonrpc_get_param(params, "num_bins", &error)->GetInt(); if (error) return error;
2244
2245 if (num_bins < 1) {
2246 return mjsonrpc_make_error(-32602, "Invalid params", "Value of num_bins should be 1 or more");
2247 }
2248
2249 const MJsonNodeVector* events_array = mjsonrpc_get_param_array(params, "events", NULL);
2250 const MJsonNodeVector* tags_array = mjsonrpc_get_param_array(params, "tags", NULL);
2251 const MJsonNodeVector* index_array = mjsonrpc_get_param_array(params, "index", NULL);
2252
2254
2255 MJsonNode* data = MJsonNode::MakeArray();
2256
2257 if (!mh) {
2258 int status = HS_FILE_ERROR;
2259 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "data", data);
2260 }
2261
2262 unsigned num_var = events_array->size();
2263
2264 if (num_var < 1) {
2265 return mjsonrpc_make_error(-32602, "Invalid params", "Array of events should have 1 or more elements");
2266 }
2267
2268 if (tags_array->size() != num_var) {
2269 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and tags should have the same length");
2270 }
2271
2272 if (index_array->size() != num_var) {
2273 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and index should have the same length");
2274 }
2275
2276 std::vector<std::string> event_names(num_var);
2277 std::vector<std::string> tag_names(num_var);
2278 //const char** event_name = new const char*[num_var];
2279 //const char** tag_name = new const char*[num_var];
2280 int* var_index = new int[num_var];
2281
2282 int* num_entries = new int[num_var];
2283 time_t* last_time = new time_t[num_var];
2284 double* last_value = new double[num_var];
2285 int* hs_status = new int[num_var];
2286
2287 int** count_bins = new int*[num_var];
2288 double** mean_bins = new double*[num_var];
2289 double** rms_bins = new double*[num_var];
2290 double** min_bins = new double*[num_var];
2291 double** max_bins = new double*[num_var];
2292
2293 time_t** bins_first_time = new time_t*[num_var];
2294 time_t** bins_last_time = new time_t*[num_var];
2295
2296 double** bins_first_value = new double*[num_var];
2297 double** bins_last_value = new double*[num_var];
2298
2299 for (unsigned i=0; i<num_var; i++) {
2300 //event_name[i] = (*events_array)[i]->GetString().c_str();
2301 //tag_name[i] = (*tags_array)[i]->GetString().c_str();
2302 event_names[i] = (*events_array)[i]->GetString();
2303 tag_names[i] = (*tags_array)[i]->GetString();
2304 var_index[i] = (*index_array)[i]->GetInt();
2305 num_entries[i] = 0;
2306 last_time[i] = 0;
2307 last_value[i] = 0;
2308 hs_status[i] = 0;
2309 count_bins[i] = new int[num_bins];
2310 mean_bins[i] = new double[num_bins];
2311 rms_bins[i] = new double[num_bins];
2312 min_bins[i] = new double[num_bins];
2313 max_bins[i] = new double[num_bins];
2314
2315 bins_first_time[i] = new time_t[num_bins];
2316 bins_last_time[i] = new time_t[num_bins];
2317
2318 bins_first_value[i] = new double[num_bins];
2319 bins_last_value[i] = new double[num_bins];
2320 }
2321
2322 if (/* DISABLES CODE */ (0)) {
2323 printf("time %f %f, num_vars %d:\n", start_time, end_time, num_var);
2324 for (unsigned i=0; i<num_var; i++) {
2325 printf("%d: [%s] [%s] [%d]\n", i, event_names[i].c_str(), tag_names[i].c_str(), var_index[i]);
2326 }
2327 }
2328
2329 const char** event_name = new const char*[num_var];
2330 const char** tag_name = new const char*[num_var];
2331 for (unsigned i=0; i<num_var; i++) {
2332 event_name[i] = event_names[i].c_str();
2333 tag_name[i] = tag_names[i].c_str();
2334 }
2335
2336 int status = mh->hs_read_binned(start_time, end_time, num_bins, num_var, event_name, tag_name, var_index, num_entries, count_bins, mean_bins, rms_bins, min_bins, max_bins, bins_first_time, bins_first_value, bins_last_time, bins_last_value, last_time, last_value, hs_status);
2337
2338 for (unsigned i=0; i<num_var; i++) {
2339 MJsonNode* obj = MJsonNode::MakeObject();
2340 obj->AddToObject("status", MJsonNode::MakeInt(hs_status[i]));
2341 obj->AddToObject("num_entries", MJsonNode::MakeInt(num_entries[i]));
2342
2343 MJsonNode* a1 = MJsonNode::MakeArray();
2344 MJsonNode* a2 = MJsonNode::MakeArray();
2345 MJsonNode* a3 = MJsonNode::MakeArray();
2346 MJsonNode* a4 = MJsonNode::MakeArray();
2347 MJsonNode* a5 = MJsonNode::MakeArray();
2348
2349 MJsonNode* b1 = MJsonNode::MakeArray();
2350 MJsonNode* b2 = MJsonNode::MakeArray();
2351 MJsonNode* b3 = MJsonNode::MakeArray();
2352 MJsonNode* b4 = MJsonNode::MakeArray();
2353
2354 for (int j=0; j<num_bins; j++) {
2355 a1->AddToArray(MJsonNode::MakeInt(count_bins[i][j]));
2356 a2->AddToArray(MJsonNode::MakeNumber(mean_bins[i][j]));
2357 a3->AddToArray(MJsonNode::MakeNumber(rms_bins[i][j]));
2358 a4->AddToArray(MJsonNode::MakeNumber(min_bins[i][j]));
2359 a5->AddToArray(MJsonNode::MakeNumber(max_bins[i][j]));
2360
2361 b1->AddToArray(MJsonNode::MakeNumber(bins_first_time[i][j]));
2362 b2->AddToArray(MJsonNode::MakeNumber(bins_first_value[i][j]));
2363 b3->AddToArray(MJsonNode::MakeNumber(bins_last_time[i][j]));
2364 b4->AddToArray(MJsonNode::MakeNumber(bins_last_value[i][j]));
2365 }
2366
2367 obj->AddToObject("count", a1);
2368 obj->AddToObject("mean", a2);
2369 obj->AddToObject("rms", a3);
2370 obj->AddToObject("min", a4);
2371 obj->AddToObject("max", a5);
2372 obj->AddToObject("bins_first_time", b1);
2373 obj->AddToObject("bins_first_value", b2);
2374 obj->AddToObject("bins_last_time", b3);
2375 obj->AddToObject("bins_last_value", b4);
2376 obj->AddToObject("last_time", MJsonNode::MakeNumber(last_time[i]));
2377 obj->AddToObject("last_value", MJsonNode::MakeNumber(last_value[i]));
2378 data->AddToArray(obj);
2379
2380 delete count_bins[i];
2381 delete mean_bins[i];
2382 delete rms_bins[i];
2383 delete min_bins[i];
2384 delete max_bins[i];
2385
2386 delete bins_first_time[i];
2387 delete bins_first_value[i];
2388 delete bins_last_time[i];
2389 delete bins_last_value[i];
2390 }
2391
2392 delete[] count_bins;
2393 delete[] mean_bins;
2394 delete[] rms_bins;
2395 delete[] min_bins;
2396 delete[] max_bins;
2397
2398 delete[] bins_first_time;
2399 delete[] bins_first_value;
2400 delete[] bins_last_time;
2401 delete[] bins_last_value;
2402
2403 delete[] event_name;
2404 delete[] tag_name;
2405 delete[] var_index;
2406
2407 delete[] num_entries;
2408 delete[] last_time;
2409 delete[] last_value;
2410 delete[] hs_status;
2411
2412 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "channel", MJsonNode::MakeString(mh->name), "data", data);
2413}
2414
2416{
2417public:
2418 std::vector<double> fTimes;
2419 std::vector<double> fValues;
2420
2421public:
2423 {
2424 // empty
2425 }
2426
2427 void Add(time_t t, double v)
2428 {
2429 //printf("add time %d, value %f\n", (int)t, v);
2430
2431 fTimes.push_back(t);
2432 fValues.push_back(v);
2433 }
2434
2435 void Finish()
2436 {
2437 assert(fTimes.size() == fValues.size());
2438 }
2439};
2440
2441static MJsonNode* js_hs_read_arraybuffer(const MJsonNode* params)
2442{
2443 if (!params) {
2444 MJSO* doc = MJSO::I();
2445 doc->D("get history data for given history events that existed at give time using hs_read_buffer()");
2446 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
2447 doc->P("start_time", MJSON_NUMBER, "start time of the data");
2448 doc->P("end_time", MJSON_NUMBER, "end time of the data");
2449 doc->P("events[]", MJSON_STRING, "array of history event names");
2450 doc->P("tags[]", MJSON_STRING, "array of history event tag names");
2451 doc->P("index[]", MJSON_STRING, "array of history event tag array indices");
2452 doc->R("binary data", MJSON_ARRAYBUFFER, "binary data, see documentation");
2453 return doc;
2454 }
2455
2456 MJsonNode* error = NULL;
2457
2458 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
2459 double start_time = mjsonrpc_get_param(params, "start_time", &error)->GetDouble(); if (error) return error;
2460 double end_time = mjsonrpc_get_param(params, "end_time", &error)->GetDouble(); if (error) return error;
2461
2462 const MJsonNodeVector* events_array = mjsonrpc_get_param_array(params, "events", NULL);
2463 const MJsonNodeVector* tags_array = mjsonrpc_get_param_array(params, "tags", NULL);
2464 const MJsonNodeVector* index_array = mjsonrpc_get_param_array(params, "index", NULL);
2465
2467
2468 if (!mh) {
2469 int status = HS_FILE_ERROR;
2470 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
2471 }
2472
2473 size_t num_var = events_array->size();
2474
2475 if (tags_array->size() != num_var) {
2476 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and tags should have the same length");
2477 }
2478
2479 if (index_array->size() != num_var) {
2480 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and index should have the same length");
2481 }
2482
2483 std::vector<std::string> event_names(num_var);
2484 std::vector<std::string> tag_names(num_var);
2485 int* var_index = new int[num_var];
2486 BinaryHistoryBuffer** jbuf = new BinaryHistoryBuffer*[num_var];
2488 int* hs_status = new int[num_var];
2489
2490 for (size_t i=0; i<num_var; i++) {
2491 //event_name[i] = (*events_array)[i]->GetString().c_str();
2492 //tag_name[i] = (*tags_array)[i]->GetString().c_str();
2493 event_names[i] = (*events_array)[i]->GetString();
2494 tag_names[i] = (*tags_array)[i]->GetString();
2495 var_index[i] = (*index_array)[i]->GetInt();
2496 jbuf[i] = new BinaryHistoryBuffer();
2497 buf[i] = jbuf[i];
2498 hs_status[i] = 0;
2499 }
2500
2501 if (/* DISABLES CODE */ (0)) {
2502 printf("time %f %f, num_vars %d:\n", start_time, end_time, int(num_var));
2503 for (size_t i=0; i<num_var; i++) {
2504 printf("%d: [%s] [%s] [%d]\n", int(i), event_names[i].c_str(), tag_names[i].c_str(), var_index[i]);
2505 }
2506 }
2507
2508 const char** event_name = new const char*[num_var];
2509 const char** tag_name = new const char*[num_var];
2510 for (unsigned i=0; i<num_var; i++) {
2511 event_name[i] = event_names[i].c_str();
2512 tag_name[i] = tag_names[i].c_str();
2513 }
2514
2515 int status = mh->hs_read_buffer(start_time, end_time, num_var, event_name, tag_name, var_index, buf, hs_status);
2516
2517 size_t num_values = 0;
2518
2519 for (unsigned i=0; i<num_var; i++) {
2520 jbuf[i]->Finish();
2521 num_values += jbuf[i]->fValues.size();
2522 }
2523
2524 // NB: beware of 32-bit integer overflow. all values are now 64-bit size_t, overflow should not happen.
2525 size_t p0_size = sizeof(double)*(2+2*num_var+2*num_values);
2526
2527 size_t size_limit = 1000*1024*1024;
2528
2529 if (p0_size > size_limit) {
2530 cm_msg(MERROR, "js_hs_read_binned_arraybuffer", "Refusing to return %zu bytes of history data, limit is %zu bytes\n", p0_size, size_limit);
2531
2532 for (size_t i=0; i<num_var; i++) {
2533 delete jbuf[i];
2534 jbuf[i] = NULL;
2535 buf[i] = NULL;
2536 }
2537
2538 delete[] event_name;
2539 delete[] tag_name;
2540 delete[] var_index;
2541 delete[] buf;
2542 delete[] jbuf;
2543 delete[] hs_status;
2544
2545 return mjsonrpc_make_error(-32603, "Internal error", "Too much history data");
2546 }
2547
2548 double* p0 = (double*)malloc(p0_size);
2549
2550 if (p0 == NULL) {
2551 cm_msg(MERROR, "js_hs_read_binned_arraybuffer", "Cannot allocate return buffer %d bytes\n", int(p0_size));
2552
2553 for (size_t i=0; i<num_var; i++) {
2554 delete jbuf[i];
2555 jbuf[i] = NULL;
2556 buf[i] = NULL;
2557 }
2558
2559 delete[] event_name;
2560 delete[] tag_name;
2561 delete[] var_index;
2562 delete[] buf;
2563 delete[] jbuf;
2564 delete[] hs_status;
2565
2566 return mjsonrpc_make_error(-32603, "Internal error", "Cannot allocate buffer, too much data");
2567 }
2568
2569 double *pptr = p0;
2570
2571 //
2572 // Binary data format:
2573 //
2574 // - hs_read() status
2575 // - num_var
2576 // - hs_status[0..num_var-1]
2577 // - num_values[0..num_var-1]
2578 // - data for var0:
2579 // - t[0][0], v[0][0] ... t[0][num_values[0]-1], v[0][num_values[0]-1]
2580 // - data for var1:
2581 // - t[1][0], v[1][0] ... t[1][num_values[1]-1], v[1][num_values[1]-1]
2582 // ...
2583 // - data for last variable:
2584 // - t[num_var-1][0], v[num_var-1][0] ... t[num_var-1][num_values[num_var-1]-1], v[num_var-1][num_values[num_var-1]-1]
2585 //
2586
2587 *pptr++ = status;
2588 *pptr++ = num_var;
2589
2590 for (size_t i=0; i<num_var; i++) {
2591 *pptr++ = hs_status[i];
2592 }
2593
2594 for (size_t i=0; i<num_var; i++) {
2595 *pptr++ = jbuf[i]->fValues.size();
2596 }
2597
2598 for (size_t i=0; i<num_var; i++) {
2599 size_t nv = jbuf[i]->fValues.size();
2600 for (size_t j=0; j<nv; j++) {
2601 *pptr++ = jbuf[i]->fTimes[j];
2602 *pptr++ = jbuf[i]->fValues[j];
2603 }
2604
2605 delete jbuf[i];
2606 jbuf[i] = NULL;
2607 buf[i] = NULL;
2608 }
2609
2610 //printf("p0_size %d, %d/%d\n", (int)p0_size, (int)(pptr-p0), (int)((pptr-p0)*sizeof(double)));
2611
2612 assert(p0_size == ((pptr-p0)*sizeof(double)));
2613
2614 delete[] event_name;
2615 delete[] tag_name;
2616 delete[] var_index;
2617 delete[] buf;
2618 delete[] jbuf;
2619 delete[] hs_status;
2620
2621 MJsonNode* result = MJsonNode::MakeArrayBuffer((char*)p0, p0_size);
2622
2623 return result;
2624}
2625
2626static MJsonNode* js_hs_read_binned_arraybuffer(const MJsonNode* params)
2627{
2628 if (!params) {
2629 MJSO* doc = MJSO::I();
2630 doc->D("get history data for given history events that existed at give time using hs_read_buffer()");
2631 doc->P("channel?", MJSON_STRING, "midas history channel, default is the default reader channel");
2632 doc->P("start_time", MJSON_NUMBER, "start time of the data");
2633 doc->P("end_time", MJSON_NUMBER, "end time of the data");
2634 doc->P("num_bins", MJSON_INT, "number of time bins");
2635 doc->P("events[]", MJSON_STRING, "array of history event names");
2636 doc->P("tags[]", MJSON_STRING, "array of history event tag names");
2637 doc->P("index[]", MJSON_STRING, "array of history event tag array indices");
2638 doc->R("binary data", MJSON_ARRAYBUFFER, "binary data, see documentation");
2639 return doc;
2640 }
2641
2642 MJsonNode* error = NULL;
2643
2644 std::string channel = mjsonrpc_get_param(params, "channel", NULL)->GetString();
2645 double start_time = mjsonrpc_get_param(params, "start_time", &error)->GetDouble(); if (error) return error;
2646 double end_time = mjsonrpc_get_param(params, "end_time", &error)->GetDouble(); if (error) return error;
2647 int inum_bins = mjsonrpc_get_param(params, "num_bins", &error)->GetInt(); if (error) return error;
2648
2649 if (inum_bins < 1) {
2650 return mjsonrpc_make_error(-32602, "Invalid params", "Value of num_bins should be 1 or more");
2651 }
2652
2653 size_t num_bins = inum_bins;
2654
2655 const MJsonNodeVector* events_array = mjsonrpc_get_param_array(params, "events", NULL);
2656 const MJsonNodeVector* tags_array = mjsonrpc_get_param_array(params, "tags", NULL);
2657 const MJsonNodeVector* index_array = mjsonrpc_get_param_array(params, "index", NULL);
2658
2660
2661 if (!mh) {
2662 int status = HS_FILE_ERROR;
2663 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
2664 }
2665
2666 size_t num_var = events_array->size();
2667
2668 if (num_var < 1) {
2669 return mjsonrpc_make_error(-32602, "Invalid params", "Array of events should have 1 or more elements");
2670 }
2671
2672 if (tags_array->size() != num_var) {
2673 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and tags should have the same length");
2674 }
2675
2676 if (index_array->size() != num_var) {
2677 return mjsonrpc_make_error(-32602, "Invalid params", "Arrays events and index should have the same length");
2678 }
2679
2680 std::vector<std::string> event_names(num_var);
2681 std::vector<std::string> tag_names(num_var);
2682 //const char** event_name = new const char*[num_var];
2683 //const char** tag_name = new const char*[num_var];
2684 int* var_index = new int[num_var];
2685
2686 int* num_entries = new int[num_var];
2687 time_t* last_time = new time_t[num_var];
2688 double* last_value = new double[num_var];
2689 int* hs_status = new int[num_var];
2690
2691 int** count_bins = new int*[num_var];
2692 double** mean_bins = new double*[num_var];
2693 double** rms_bins = new double*[num_var];
2694 double** min_bins = new double*[num_var];
2695 double** max_bins = new double*[num_var];
2696
2697 time_t** bins_first_time = new time_t*[num_var];
2698 time_t** bins_last_time = new time_t*[num_var];
2699
2700 double** bins_first_value = new double*[num_var];
2701 double** bins_last_value = new double*[num_var];
2702
2703 for (unsigned i=0; i<num_var; i++) {
2704 //event_name[i] = (*events_array)[i]->GetString().c_str();
2705 //tag_name[i] = (*tags_array)[i]->GetString().c_str();
2706 event_names[i] = (*events_array)[i]->GetString();
2707 tag_names[i] = (*tags_array)[i]->GetString();
2708 var_index[i] = (*index_array)[i]->GetInt();
2709 num_entries[i] = 0;
2710 last_time[i] = 0;
2711 last_value[i] = 0;
2712 hs_status[i] = 0;
2713 count_bins[i] = new int[num_bins];
2714 mean_bins[i] = new double[num_bins];
2715 rms_bins[i] = new double[num_bins];
2716 min_bins[i] = new double[num_bins];
2717 max_bins[i] = new double[num_bins];
2718 bins_first_time[i] = new time_t[num_bins];
2719 bins_last_time[i] = new time_t[num_bins];
2720 bins_first_value[i] = new double[num_bins];
2721 bins_last_value[i] = new double[num_bins];
2722 }
2723
2724 if (/* DISABLES CODE */ (0)) {
2725 printf("time %f %f, num_vars %d:\n", start_time, end_time, int(num_var));
2726 for (size_t i=0; i<num_var; i++) {
2727 printf("%d: [%s] [%s] [%d]\n", int(i), event_names[i].c_str(), tag_names[i].c_str(), var_index[i]);
2728 }
2729 }
2730
2731 const char** event_name = new const char*[num_var];
2732 const char** tag_name = new const char*[num_var];
2733 for (size_t i=0; i<num_var; i++) {
2734 event_name[i] = event_names[i].c_str();
2735 tag_name[i] = tag_names[i].c_str();
2736 }
2737
2738 int status = mh->hs_read_binned(start_time, end_time, num_bins, num_var, event_name, tag_name, var_index, num_entries, count_bins, mean_bins, rms_bins, min_bins, max_bins, bins_first_time, bins_first_value, bins_last_time, bins_last_value, last_time, last_value, hs_status);
2739
2740 // NB: beware of 32-bit integer overflow: all variables are now 64-bit size_t, overflow should not happen
2741 size_t p0_size = sizeof(double)*(5+4*num_var+9*num_var*num_bins);
2742
2743 size_t size_limit = 100*1024*1024;
2744
2745 if (p0_size > size_limit) {
2746 cm_msg(MERROR, "js_hs_read_binned_arraybuffer", "Refusing to return %d bytes. limit is %d bytes\n", int(p0_size), int(size_limit));
2747
2748 for (size_t i=0; i<num_var; i++) {
2749 delete count_bins[i];
2750 delete mean_bins[i];
2751 delete rms_bins[i];
2752 delete min_bins[i];
2753 delete max_bins[i];
2754 delete bins_first_time[i];
2755 delete bins_first_value[i];
2756 delete bins_last_time[i];
2757 delete bins_last_value[i];
2758 }
2759
2760 delete[] count_bins;
2761 delete[] mean_bins;
2762 delete[] rms_bins;
2763 delete[] min_bins;
2764 delete[] max_bins;
2765
2766 delete[] bins_first_time;
2767 delete[] bins_first_value;
2768 delete[] bins_last_time;
2769 delete[] bins_last_value;
2770
2771 delete[] event_name;
2772 delete[] tag_name;
2773 delete[] var_index;
2774
2775 delete[] num_entries;
2776 delete[] last_time;
2777 delete[] last_value;
2778 delete[] hs_status;
2779
2780 return mjsonrpc_make_error(-32603, "Internal error", "Refuse to return too much data");
2781 }
2782
2783 double* p0 = (double*)malloc(p0_size);
2784
2785 if (p0 == NULL) {
2786 cm_msg(MERROR, "js_hs_read_binned_arraybuffer", "Cannot allocate return buffer %d bytes\n", int(p0_size));
2787
2788 for (size_t i=0; i<num_var; i++) {
2789 delete count_bins[i];
2790 delete mean_bins[i];
2791 delete rms_bins[i];
2792 delete min_bins[i];
2793 delete max_bins[i];
2794 delete bins_first_time[i];
2795 delete bins_first_value[i];
2796 delete bins_last_time[i];
2797 delete bins_last_value[i];
2798 }
2799
2800 delete[] count_bins;
2801 delete[] mean_bins;
2802 delete[] rms_bins;
2803 delete[] min_bins;
2804 delete[] max_bins;
2805
2806 delete[] bins_first_time;
2807 delete[] bins_first_value;
2808 delete[] bins_last_time;
2809 delete[] bins_last_value;
2810
2811 delete[] event_name;
2812 delete[] tag_name;
2813 delete[] var_index;
2814
2815 delete[] num_entries;
2816 delete[] last_time;
2817 delete[] last_value;
2818 delete[] hs_status;
2819
2820 return mjsonrpc_make_error(-32603, "Internal error", "Cannot allocate buffer, too much data");
2821 }
2822
2823 double *pptr = p0;
2824
2825 //
2826 // Binary data format:
2827 //
2828 // * header
2829 // -- hs_read() status
2830 // -- start_time
2831 // -- end_time
2832 // -- num_bins
2833 // -- num_var
2834 // * per variable info
2835 // -- hs_status[0..num_var-1]
2836 // -- num_entries[0..num_var-1]
2837 // -- last_time[0..num_var-1]
2838 // -- last_value[0..num_var-1]
2839 // * data for var0 bin0
2840 // -- count - number of entries in this bin
2841 // -- mean - mean value
2842 // -- rms - rms value
2843 // -- min - minimum value
2844 // -- max - maximum value
2845 // -- bins_first_time - first data point in each bin
2846 // -- bins_first_value
2847 // -- bins_last_time - last data point in each bin
2848 // -- bins_last_value
2849 // - data for var0 bin1
2850 // - ... bin[num_bins-1]
2851 // - data for var1 bin0
2852 // - ...
2853 // - data for var[num_vars-1] bin[0]
2854 // - ...
2855 // - data for var[num_vars-1] bin[num_bins-1]
2856 //
2857
2858 *pptr++ = status;
2859 *pptr++ = start_time;
2860 *pptr++ = end_time;
2861 *pptr++ = num_bins;
2862 *pptr++ = num_var;
2863
2864 for (unsigned i=0; i<num_var; i++) {
2865 *pptr++ = hs_status[i];
2866 }
2867
2868 for (unsigned i=0; i<num_var; i++) {
2869 *pptr++ = num_entries[i];
2870 }
2871
2872 for (unsigned i=0; i<num_var; i++) {
2873 *pptr++ = last_time[i];
2874 }
2875
2876 for (unsigned i=0; i<num_var; i++) {
2877 *pptr++ = last_value[i];
2878 }
2879
2880 for (size_t i=0; i<num_var; i++) {
2881 for (size_t j=0; j<num_bins; j++) {
2882 *pptr++ = count_bins[i][j];
2883 *pptr++ = mean_bins[i][j];
2884 *pptr++ = rms_bins[i][j];
2885 *pptr++ = min_bins[i][j];
2886 *pptr++ = max_bins[i][j];
2887 *pptr++ = bins_first_time[i][j];
2888 *pptr++ = bins_first_value[i][j];
2889 *pptr++ = bins_last_time[i][j];
2890 *pptr++ = bins_last_value[i][j];
2891 }
2892
2893 delete count_bins[i];
2894 delete mean_bins[i];
2895 delete rms_bins[i];
2896 delete min_bins[i];
2897 delete max_bins[i];
2898 delete bins_first_time[i];
2899 delete bins_first_value[i];
2900 delete bins_last_time[i];
2901 delete bins_last_value[i];
2902 }
2903
2904 //printf("p0_size %d, %d/%d\n", (int)p0_size, (int)(pptr-p0), (int)((pptr-p0)*sizeof(double)));
2905
2906 assert(p0_size == ((pptr-p0)*sizeof(double)));
2907
2908 delete[] count_bins;
2909 delete[] mean_bins;
2910 delete[] rms_bins;
2911 delete[] min_bins;
2912 delete[] max_bins;
2913
2914 delete[] bins_first_time;
2915 delete[] bins_first_value;
2916 delete[] bins_last_time;
2917 delete[] bins_last_value;
2918
2919 delete[] event_name;
2920 delete[] tag_name;
2921 delete[] var_index;
2922
2923 delete[] num_entries;
2924 delete[] last_time;
2925 delete[] last_value;
2926 delete[] hs_status;
2927
2928 MJsonNode* result = MJsonNode::MakeArrayBuffer((char*)p0, p0_size);
2929
2930 return result;
2931}
2932
2934//
2935// image history code goes here
2936//
2938
2939static MJsonNode* js_hs_image_retrieve(const MJsonNode* params) {
2940 if (!params) {
2941 MJSO *doc = MJSO::I();
2942 doc->D("Get a list of history image files");
2943 doc->P("image?", MJSON_STRING, "image name as defined under /History/Images/<image>");
2944 doc->P("start_time", MJSON_NUMBER, "start time of the data");
2945 doc->P("end_time", MJSON_NUMBER, "end time of the data");
2946 doc->R("time[]", MJSON_ARRAYBUFFER, "array of time stamps in seconds");
2947 doc->R("filename[]", MJSON_ARRAYBUFFER, "array of file names");
2948 return doc;
2949 }
2950
2951 MJsonNode* error = NULL;
2952
2953 std::string image = mjsonrpc_get_param(params, "image", NULL)->GetString();
2954 double start_time = mjsonrpc_get_param(params, "start_time", &error)->GetDouble(); if (error) return error;
2955 double end_time = mjsonrpc_get_param(params, "end_time", &error)->GetDouble(); if (error) return error;
2956
2957 std::vector<time_t>vtime{};
2958 std::vector<std::string>vfilename{};
2959
2960 int status = hs_image_retrieve(image, start_time, end_time, vtime, vfilename);
2961 int count = 10;
2962 MJsonNode *tj = MJsonNode::MakeArray();
2963 MJsonNode *fj = MJsonNode::MakeArray();
2964
2965 for (int i=0 ; i<(int)vtime.size() ; i++) {
2966 tj->AddToArray(MJsonNode::MakeInt(vtime[i]));
2967 ss_repair_utf8(vfilename[i]);
2968 fj->AddToArray(MJsonNode::MakeString(vfilename[i].c_str()));
2969 }
2970 MJsonNode* data = MJsonNode::MakeObject();
2971 data->AddToObject("count", MJsonNode::MakeInt(count));
2972 data->AddToObject("time", tj);
2973 data->AddToObject("filename", fj);
2974
2975 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "data", data);
2976}
2977
2979//
2980// elog code goes here
2981//
2983
2984static MJsonNode* js_el_retrieve(const MJsonNode* params)
2985{
2986 if (!params) {
2987 MJSO* doc = MJSO::I();
2988 doc->D("Get an elog message");
2989 doc->P("tag", MJSON_STRING, "elog message tag");
2990 doc->R("status", MJSON_INT, "return status of el_retrieve");
2991 doc->R("msg.tag", MJSON_STRING, "message tag");
2992 return doc;
2993 }
2994
2995 MJsonNode* error = NULL;
2996
2997 std::string tag = mjsonrpc_get_param(params, "tag", &error)->GetString(); if (error) return error;
2998
2999 int run = 0;
3000 char date[80], author[80], type[80], system[80], subject[256], text[10000];
3001 char orig_tag[80], reply_tag[80], attachment[3][256], encoding[80];
3002
3003 char xtag[80];
3004 mstrlcpy(xtag, tag.c_str(), sizeof(xtag));
3005
3006 int size = sizeof(text);
3007
3008 int status = el_retrieve(xtag,
3009 date, &run, author, type, system, subject,
3010 text, &size, orig_tag, reply_tag,
3011 attachment[0], attachment[1], attachment[2], encoding);
3012
3013 //printf("js_el_retrieve: size %d, status %d, tag [%s]\n", size, status, xtag);
3014
3015 MJsonNode* msg = MJsonNode::MakeObject();
3016
3017 if (status == EL_SUCCESS) {
3018 ss_repair_utf8(xtag);
3019 msg->AddToObject("tag", MJsonNode::MakeString(xtag));
3020 ss_repair_utf8(date);
3021 msg->AddToObject("date", MJsonNode::MakeString(date));
3022 msg->AddToObject("run", MJsonNode::MakeInt(run));
3023 ss_repair_utf8(author);
3024 msg->AddToObject("author", MJsonNode::MakeString(author));
3026 msg->AddToObject("type", MJsonNode::MakeString(type));
3027 ss_repair_utf8(system);
3028 msg->AddToObject("system", MJsonNode::MakeString(system));
3029 ss_repair_utf8(subject);
3030 msg->AddToObject("subject", MJsonNode::MakeString(subject));
3031 ss_repair_utf8(text);
3032 msg->AddToObject("text", MJsonNode::MakeString(text));
3033 ss_repair_utf8(orig_tag);
3034 msg->AddToObject("orig_tag", MJsonNode::MakeString(orig_tag));
3035 ss_repair_utf8(reply_tag);
3036 msg->AddToObject("reply_tag", MJsonNode::MakeString(reply_tag));
3037 ss_repair_utf8(attachment[0]);
3038 msg->AddToObject("attachment0", MJsonNode::MakeString(attachment[0]));
3039 ss_repair_utf8(attachment[1]);
3040 msg->AddToObject("attachment1", MJsonNode::MakeString(attachment[1]));
3041 ss_repair_utf8(attachment[2]);
3042 msg->AddToObject("attachment2", MJsonNode::MakeString(attachment[2]));
3043 ss_repair_utf8(encoding);
3044 msg->AddToObject("encoding", MJsonNode::MakeString(encoding));
3045 }
3046
3047 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "msg", msg);
3048}
3049
3050static MJsonNode* js_el_query(const MJsonNode* params)
3051{
3052 if (!params) {
3053 MJSO* doc = MJSO::I();
3054 doc->D("Query elog messages");
3055 doc->P("last_n_hours?", MJSON_INT, "return messages from the last N hours");
3056 doc->R("status", MJSON_INT, "return status of el_retrieve");
3057 doc->R("msg[].tag", MJSON_STRING, "message tag");
3058 return doc;
3059 }
3060
3061 //MJsonNode* error = NULL;
3062
3063 //int last_n = mjsonrpc_get_param(params, "last_n_hours", &error)->GetInt(); if (error) return error;
3064 int last_n = mjsonrpc_get_param(params, "last_n_hours", NULL)->GetInt();
3065
3066 std::string pd1 = mjsonrpc_get_param(params, "d1", NULL)->GetString();
3067 std::string pm1 = mjsonrpc_get_param(params, "m1", NULL)->GetString();
3068 std::string py1 = mjsonrpc_get_param(params, "y1", NULL)->GetString();
3069
3070 std::string pd2 = mjsonrpc_get_param(params, "d2", NULL)->GetString();
3071 std::string pm2 = mjsonrpc_get_param(params, "m2", NULL)->GetString();
3072 std::string py2 = mjsonrpc_get_param(params, "y2", NULL)->GetString();
3073
3074 std::string pr1 = mjsonrpc_get_param(params, "r1", NULL)->GetString();
3075 std::string pr2 = mjsonrpc_get_param(params, "r2", NULL)->GetString();
3076
3077 std::string ptype = mjsonrpc_get_param(params, "type", NULL)->GetString();
3078 std::string psystem = mjsonrpc_get_param(params, "system", NULL)->GetString();
3079 std::string pauthor = mjsonrpc_get_param(params, "author", NULL)->GetString();
3080 std::string psubject = mjsonrpc_get_param(params, "subject", NULL)->GetString();
3081 std::string psubtext = mjsonrpc_get_param(params, "subtext", NULL)->GetString();
3082
3083 MJsonNode* msg_array = MJsonNode::MakeArray();
3084
3085 int i, size, run, status;
3086 char date[80], author[80], type[80], system[80], subject[256], text[10000],
3087 orig_tag[80], reply_tag[80], attachment[3][256], encoding[80];
3088 char str[256], str2[10000], tag[256];
3089 struct tm tms;
3090
3091 // month name from midas.c
3092 extern const char *mname[];
3093
3094 /*---- convert end date to ltime ----*/
3095
3096 int y1 = -1;
3097 int m1 = -1;
3098 int d1 = -1;
3099
3100 int y2 = -1;
3101 int m2 = -1;
3102 int d2 = -1;
3103
3104 int r1 = -1;
3105 int r2 = -1;
3106
3107 if (pr1.length()>0)
3108 r1 = atoi(pr1.c_str());
3109
3110 if (pr2.length()>0)
3111 r2 = atoi(pr2.c_str());
3112
3113 time_t ltime_start = 0;
3114 time_t ltime_end = 0;
3115
3116 if (!last_n) {
3117 // decode starting date year, day and month
3118
3119 if (py1.length() > 0)
3120 y1 = atoi(py1.c_str());
3121
3122 if (pd1.length() > 0)
3123 d1 = atoi(pd1.c_str());
3124
3125 mstrlcpy(str, pm1.c_str(), sizeof(str));
3126 for (m1 = 0; m1 < 12; m1++)
3127 if (equal_ustring(str, mname[m1]))
3128 break;
3129 if (m1 == 12)
3130 m1 = 0;
3131
3132 if (pd2.length() > 0) {
3133 d2 = atoi(pd2.c_str());
3134 }
3135
3136 if (py2.length() > 0) {
3137 // decode ending date year, day and month
3138
3139 mstrlcpy(str, pm2.c_str(), sizeof(str));
3140 for (m2 = 0; m2 < 12; m2++)
3141 if (equal_ustring(str, mname[m2]))
3142 break;
3143 if (m2 == 12) {
3144 m2 = 0;
3145 }
3146 }
3147
3148 if (py2.length() > 0) {
3149 y2 = atoi(py2.c_str());
3150 }
3151
3152 if (y2>=0 && m2>=0 && d2>=0) {
3153 memset(&tms, 0, sizeof(struct tm));
3154 tms.tm_year = y2 % 100;
3155 tms.tm_mon = m2;
3156 tms.tm_mday = d2;
3157 tms.tm_hour = 24;
3158
3159 if (tms.tm_year < 90)
3160 tms.tm_year += 100;
3161 ltime_end = ss_mktime(&tms);
3162 }
3163 }
3164
3165 /*---- do query ----*/
3166
3167 tag[0] = 0;
3168
3169 if (last_n) {
3170 ss_tzset(); // required for localtime_r()
3171 time_t now = time(NULL);
3172 ltime_start = now - 3600 * last_n;
3173 struct tm tms;
3174 localtime_r(&ltime_start, &tms);
3175 sprintf(tag, "%02d%02d%02d.0", tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday);
3176 } else if (r1 > 0) {
3177 /* do run query */
3178 el_search_run(r1, tag);
3179 } else if (y1>=0 && m1>=0 && d1>=0) {
3180 /* do date-date query */
3181 sprintf(tag, "%02d%02d%02d.0", y1 % 100, m1 + 1, d1);
3182 }
3183
3184#if 0
3185 printf("js_el_query: y1 %d, m1 %d, d1 %d, y2 %d, m2 %d, d2 %d, r1 %d, r2 %d, last_n_hours %d, start time %lu, end time %lu, tag [%s]\n",
3186 y1, m1, d1,
3187 y2, m2, d2,
3188 r1, r2,
3189 last_n,
3190 ltime_start,
3191 ltime_end,
3192 tag);
3193#endif
3194
3195 do {
3196 size = sizeof(text);
3197 status = el_retrieve(tag, date, &run, author, type, system, subject,
3198 text, &size, orig_tag, reply_tag,
3199 attachment[0], attachment[1], attachment[2], encoding);
3200
3201 std::string this_tag = tag;
3202
3203 //printf("js_el_query: el_retrieve: size %d, status %d, tag [%s], run %d, tags [%s] [%s]\n", size, status, tag, run, orig_tag, reply_tag);
3204
3205 mstrlcat(tag, "+1", sizeof(tag));
3206
3207 /* check for end run */
3208 if ((r2 > 0) && (r2 < run)) {
3209 break;
3210 }
3211
3212 /* convert date to unix format */
3213 memset(&tms, 0, sizeof(struct tm));
3214 tms.tm_year = (tag[0] - '0') * 10 + (tag[1] - '0');
3215 tms.tm_mon = (tag[2] - '0') * 10 + (tag[3] - '0') - 1;
3216 tms.tm_mday = (tag[4] - '0') * 10 + (tag[5] - '0');
3217 tms.tm_hour = (date[11] - '0') * 10 + (date[12] - '0');
3218 tms.tm_min = (date[14] - '0') * 10 + (date[15] - '0');
3219 tms.tm_sec = (date[17] - '0') * 10 + (date[18] - '0');
3220
3221 if (tms.tm_year < 90)
3222 tms.tm_year += 100;
3223
3224 time_t ltime_current = ss_mktime(&tms);
3225
3226 //printf("js_el_query: ltime: start %ld, end %ld, current %ld\n", ltime_start, ltime_end, ltime_current);
3227
3228 /* check for start date */
3229 if (ltime_start > 0)
3230 if (ltime_current < ltime_start)
3231 continue;
3232
3233 /* check for end date */
3234 if (ltime_end > 0) {
3235 if (ltime_current > ltime_end)
3236 break;
3237 }
3238
3239 if (status == EL_SUCCESS) {
3240 /* do filtering */
3241 if ((ptype.length()>0) && !equal_ustring(ptype.c_str(), type))
3242 continue;
3243 if ((psystem.length()>0) && !equal_ustring(psystem.c_str(), system))
3244 continue;
3245
3246 if (pauthor.length()>0) {
3247 mstrlcpy(str, pauthor.c_str(), sizeof(str));
3248 for (i = 0; i < (int) strlen(str); i++)
3249 str[i] = toupper(str[i]);
3250 str[i] = 0;
3251 for (i = 0; i < (int) strlen(author) && author[i] != '@'; i++)
3252 str2[i] = toupper(author[i]);
3253 str2[i] = 0;
3254
3255 if (strstr(str2, str) == NULL)
3256 continue;
3257 }
3258
3259 if (psubject.length()>0) {
3260 mstrlcpy(str, psubject.c_str(), sizeof(str));
3261 for (i = 0; i < (int) strlen(str); i++)
3262 str[i] = toupper(str[i]);
3263 str[i] = 0;
3264 for (i = 0; i < (int) strlen(subject); i++)
3265 str2[i] = toupper(subject[i]);
3266 str2[i] = 0;
3267
3268 if (strstr(str2, str) == NULL)
3269 continue;
3270 }
3271
3272 if (psubtext.length()>0) {
3273 mstrlcpy(str, psubtext.c_str(), sizeof(str));
3274 for (i = 0; i < (int) strlen(str); i++)
3275 str[i] = toupper(str[i]);
3276 str[i] = 0;
3277 for (i = 0; i < (int) strlen(text); i++)
3278 str2[i] = toupper(text[i]);
3279 str2[i] = 0;
3280
3281 if (strstr(str2, str) == NULL)
3282 continue;
3283 }
3284
3285 /* filter passed: display line */
3286
3287 MJsonNode* msg = MJsonNode::MakeObject();
3288
3289 ss_repair_utf8(this_tag);
3290 msg->AddToObject("tag", MJsonNode::MakeString(this_tag.c_str()));
3291 ss_repair_utf8(date);
3292 msg->AddToObject("date", MJsonNode::MakeString(date));
3293 msg->AddToObject("run", MJsonNode::MakeInt(run));
3294 ss_repair_utf8(author);
3295 msg->AddToObject("author", MJsonNode::MakeString(author));
3297 msg->AddToObject("type", MJsonNode::MakeString(type));
3298 ss_repair_utf8(system);
3299 msg->AddToObject("system", MJsonNode::MakeString(system));
3300 ss_repair_utf8(subject);
3301 msg->AddToObject("subject", MJsonNode::MakeString(subject));
3302 ss_repair_utf8(text);
3303 msg->AddToObject("text", MJsonNode::MakeString(text));
3304 ss_repair_utf8(orig_tag);
3305 msg->AddToObject("orig_tag", MJsonNode::MakeString(orig_tag));
3306 ss_repair_utf8(reply_tag);
3307 msg->AddToObject("reply_tag", MJsonNode::MakeString(reply_tag));
3308 ss_repair_utf8(attachment[0]);
3309 msg->AddToObject("attachment0", MJsonNode::MakeString(attachment[0]));
3310 ss_repair_utf8(attachment[1]);
3311 msg->AddToObject("attachment1", MJsonNode::MakeString(attachment[1]));
3312 ss_repair_utf8(attachment[2]);
3313 msg->AddToObject("attachment2", MJsonNode::MakeString(attachment[2]));
3314 ss_repair_utf8(encoding);
3315 msg->AddToObject("encoding", MJsonNode::MakeString(encoding));
3316
3317 msg_array->AddToArray(msg);
3318 }
3319
3320 } while (status == EL_SUCCESS);
3321
3322 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "msg", msg_array);
3323}
3324
3325static MJsonNode* js_el_delete(const MJsonNode* params)
3326{
3327 if (!params) {
3328 MJSO* doc = MJSO::I();
3329 doc->D("Delete elog message");
3330 doc->P("tag", MJSON_STRING, "tag of message to delete");
3331 doc->R("status", MJSON_INT, "return status of el_delete");
3332 return doc;
3333 }
3334
3335 MJsonNode* error = NULL;
3336 std::string tag = mjsonrpc_get_param(params, "tag", &error)->GetString(); if (error) return error;
3337 int status = el_delete_message(tag.c_str());
3338 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3339}
3340
3341
3343//
3344// jrpc code goes here
3345//
3347
3348static MJsonNode* jrpc_cxx(const MJsonNode* params)
3349{
3350 if (!params) {
3351 MJSO* doc = MJSO::I();
3352 doc->D("make RPC call into frontend program via RPC_JRPC_CXX");
3353 doc->P("client_name", MJSON_STRING, "Connect to this MIDAS client, see cm_connect_client()");
3354 doc->P("cmd", MJSON_STRING, "Command passed to client");
3355 doc->P("args", MJSON_STRING, "Parameters passed to client as a string, could be JSON encoded");
3356 doc->R("reply", MJSON_STRING, "Reply from client as a string, could be JSON encoded");
3357 doc->R("status", MJSON_INT, "return status of cm_connect_client() and rpc_client_call()");
3358 return doc;
3359 }
3360
3361 MJsonNode* error = NULL;
3362
3363 std::string name = mjsonrpc_get_param(params, "client_name", &error)->GetString(); if (error) return error;
3364 std::string cmd = mjsonrpc_get_param(params, "cmd", &error)->GetString(); if (error) return error;
3365 std::string args = mjsonrpc_get_param(params, "args", &error)->GetString(); if (error) return error;
3366
3367 int status;
3368
3369 HNDLE hconn;
3370
3371 status = cm_connect_client(name.c_str(), &hconn);
3372
3373 if (status != RPC_SUCCESS) {
3374 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3375 }
3376
3377 std::string reply;
3378
3379 status = rpc_client_call(hconn, RPC_JRPC_CXX, cmd.c_str(), args.c_str(), &reply);
3380
3381 // disconnect return status ignored on purpose.
3382 // disconnect not needed, there is no limit on number
3383 // of connections. dead and closed connections are reaped
3384 // automatically. K.O. Feb 2021.
3385 // cm_disconnect_client(hconn, FALSE);
3386
3387 if (status != RPC_SUCCESS) {
3388 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3389 }
3390
3391 ss_repair_utf8(reply);
3392
3393 MJsonNode* rn = MJsonNode::MakeString(reply.c_str());
3394
3395 return mjsonrpc_make_result("reply", rn, "status", MJsonNode::MakeInt(SUCCESS));
3396}
3397
3398static MJsonNode* jrpc_old(const MJsonNode* params)
3399{
3400 if (!params) {
3401 MJSO* doc = MJSO::I();
3402 doc->D("make RPC call into frontend program via RPC_JRPC");
3403 doc->P("client_name", MJSON_STRING, "Connect to this MIDAS client, see cm_connect_client()");
3404 doc->P("cmd", MJSON_STRING, "Command passed to client");
3405 doc->P("args", MJSON_STRING, "Parameters passed to client as a string, could be JSON encoded");
3406 doc->P("max_reply_length?", MJSON_INT, "Optional maximum length of client reply. MIDAS RPC does not support returning strings of arbitrary length, maximum length has to be known ahead of time.");
3407 doc->R("reply", MJSON_STRING, "Reply from client as a string, could be JSON encoded");
3408 doc->R("status", MJSON_INT, "return status of cm_connect_client() and rpc_client_call()");
3409 return doc;
3410 }
3411
3412 MJsonNode* error = NULL;
3413
3414 std::string name = mjsonrpc_get_param(params, "client_name", &error)->GetString(); if (error) return error;
3415 std::string cmd = mjsonrpc_get_param(params, "cmd", &error)->GetString(); if (error) return error;
3416 std::string args = mjsonrpc_get_param(params, "args", &error)->GetString(); if (error) return error;
3417 int max_reply_length = mjsonrpc_get_param(params, "max_reply_length", NULL)->GetInt();
3418
3419 int status;
3420
3421 int buf_length = 1024;
3422
3423 if (max_reply_length > buf_length)
3424 buf_length = max_reply_length;
3425
3426 char* buf = (char*)malloc(buf_length);
3427
3428 if (buf == NULL) {
3429 return mjsonrpc_make_error(-32602, "Invalid params", msprintf("malloc(%d) failed, likely invalid max_reply_length value %d", buf_length, max_reply_length).c_str());
3430 }
3431
3432 buf[0] = 0;
3433
3434 HNDLE hconn;
3435
3436 status = cm_connect_client(name.c_str(), &hconn);
3437
3438 if (status != RPC_SUCCESS) {
3439 free(buf);
3440 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3441 }
3442
3443 status = rpc_client_call(hconn, RPC_JRPC, cmd.c_str(), args.c_str(), buf, buf_length);
3444
3445 // disconnect return status ignored on purpose.
3446 // disconnect not needed, there is no limit on number
3447 // of connections. dead and closed connections are reaped
3448 // automatically. K.O. Feb 2021.
3449 // cm_disconnect_client(hconn, FALSE);
3450
3451 if (status != RPC_SUCCESS) {
3452 free(buf);
3453 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3454 }
3455
3456 ss_repair_utf8(buf);
3457
3458 MJsonNode* reply = MJsonNode::MakeString(buf);
3459 free(buf);
3460
3461 return mjsonrpc_make_result("reply", reply, "status", MJsonNode::MakeInt(SUCCESS));
3462}
3463
3465//
3466// brpc code goes here
3467//
3469
3470static MJsonNode* brpc_cxx(const MJsonNode* params)
3471{
3472 if (!params) {
3473 MJSO* doc = MJSO::I();
3474 doc->D("make RPC call into frontend program via RPC_BRPC_CXX");
3475 doc->P("client_name", MJSON_STRING, "Connect to this MIDAS client, see cm_connect_client()");
3476 doc->P("cmd", MJSON_STRING, "Command passed to client");
3477 doc->P("args", MJSON_STRING, "Parameters passed to client as a string, could be JSON encoded");
3478 doc->R("reply", MJSON_STRING, "Reply from client as a string, could be JSON encoded");
3479 doc->R("status", MJSON_INT, "return status of cm_connect_client() and rpc_client_call()");
3480 return doc;
3481 }
3482
3483 MJsonNode* error = NULL;
3484
3485 std::string name = mjsonrpc_get_param(params, "client_name", &error)->GetString(); if (error) return error;
3486 std::string cmd = mjsonrpc_get_param(params, "cmd", &error)->GetString(); if (error) return error;
3487 std::string args = mjsonrpc_get_param(params, "args", &error)->GetString(); if (error) return error;
3488
3489 int status;
3490
3491 HNDLE hconn;
3492
3493 status = cm_connect_client(name.c_str(), &hconn);
3494
3495 if (status != RPC_SUCCESS) {
3496 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3497 }
3498
3499 std::vector<char> *pbuf = new std::vector<char>;
3500
3501 status = rpc_client_call(hconn, RPC_BRPC_CXX, cmd.c_str(), args.c_str(), pbuf);
3502
3503 // disconnect return status ignored on purpose.
3504 // disconnect not needed, there is no limit on number
3505 // of connections. dead and closed connections are reaped
3506 // automatically. K.O. Feb 2021.
3507 // cm_disconnect_client(hconn, FALSE);
3508
3509 if (status != RPC_SUCCESS) {
3510 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3511 }
3512
3513 return MJsonNode::MakeArrayBuffer(pbuf);
3514}
3515
3516static MJsonNode* brpc_old(const MJsonNode* params)
3517{
3518 if (!params) {
3519 MJSO* doc = MJSO::I();
3520 doc->D("make RPC call into frontend program via RPC_BRPC");
3521 doc->P("client_name", MJSON_STRING, "Connect to this MIDAS client, see cm_connect_client()");
3522 doc->P("cmd", MJSON_STRING, "Command passed to client");
3523 doc->P("args", MJSON_STRING, "Parameters passed to client as a string, could be JSON encoded");
3524 doc->P("max_reply_length?", MJSON_INT, "Optional maximum length of client reply. MIDAS RPC does not support returning data of arbitrary length, maximum length has to be known ahead of time.");
3525 doc->R("reply", MJSON_STRING, "Reply from client as a string, could be JSON encoded");
3526 doc->R("status", MJSON_INT, "return status of cm_connect_client() and rpc_client_call()");
3527 return doc;
3528 }
3529
3530 MJsonNode* error = NULL;
3531
3532 std::string name = mjsonrpc_get_param(params, "client_name", &error)->GetString(); if (error) return error;
3533 std::string cmd = mjsonrpc_get_param(params, "cmd", &error)->GetString(); if (error) return error;
3534 std::string args = mjsonrpc_get_param(params, "args", &error)->GetString(); if (error) return error;
3535 int max_reply_length = mjsonrpc_get_param(params, "max_reply_length", NULL)->GetInt();
3536
3537 int status;
3538
3539 int buf_length = 1024;
3540
3541 if (max_reply_length > buf_length)
3542 buf_length = max_reply_length;
3543
3544 char* buf = (char*)malloc(buf_length);
3545
3546 if (buf == NULL) {
3547 return mjsonrpc_make_error(-32602, "Invalid params", msprintf("malloc(%d) failed, likely invalid max_reply_length value %d", buf_length, max_reply_length).c_str());
3548 }
3549
3550 buf[0] = 0;
3551
3552 HNDLE hconn;
3553
3554 status = cm_connect_client(name.c_str(), &hconn);
3555
3556 if (status != RPC_SUCCESS) {
3557 free(buf);
3558 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3559 }
3560
3561 status = rpc_client_call(hconn, RPC_BRPC, cmd.c_str(), args.c_str(), buf, &buf_length);
3562
3563 // disconnect return status ignored on purpose.
3564 // disconnect not needed, there is no limit on number
3565 // of connections. dead and closed connections are reaped
3566 // automatically. K.O. Feb 2021.
3567 // cm_disconnect_client(hconn, FALSE);
3568
3569 if (status != RPC_SUCCESS) {
3570 free(buf);
3571 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3572 }
3573
3574 return MJsonNode::MakeArrayBuffer(buf, buf_length);
3575}
3576
3578//
3579// Run transition code goes here
3580//
3582
3583static MJsonNode* js_cm_transition(const MJsonNode* params)
3584{
3585 if (!params) {
3586 MJSO* doc = MJSO::I();
3587 doc->D("start and stop runs");
3588 doc->P("transition", MJSON_STRING, "requested transition: TR_START, TR_STOP, TR_PAUSE, TR_RESUME");
3589 doc->P("run_number?", MJSON_INT, "New run number, value 0 means /runinfo/run_number + 1, default is 0");
3590 doc->P("async_flag?", MJSON_INT, "Transition type. Default is multithreaded transition TR_MTHREAD");
3591 doc->P("debug_flag?", MJSON_INT, "See cm_transition(), value 1: trace to stdout, value 2: trace to midas.log");
3592 doc->R("status", MJSON_INT, "return status of cm_transition()");
3593 doc->R("error_string?", MJSON_STRING, "return error string from cm_transition()");
3594 return doc;
3595 }
3596
3597 MJsonNode* error = NULL;
3598
3599 std::string xtransition = mjsonrpc_get_param(params, "transition", &error)->GetString(); if (error) return error;
3600 int run_number = mjsonrpc_get_param(params, "run_number", NULL)->GetInt();
3601 int async_flag = mjsonrpc_get_param(params, "async_flag", NULL)->GetInt();
3602 int debug_flag = mjsonrpc_get_param(params, "debug_flag", NULL)->GetInt();
3603
3604 int status;
3605
3606 int transition = 0;
3607
3608 if (xtransition == "TR_START")
3610 else if (xtransition == "TR_STOP")
3612 else if (xtransition == "TR_PAUSE")
3614 else if (xtransition == "TR_RESUME")
3616 else {
3617 return mjsonrpc_make_error(15, "invalid value of \"transition\"", xtransition.c_str());
3618 }
3619
3620 if (async_flag == 0)
3621 async_flag = TR_MTHREAD;
3622
3623 char error_str[1024];
3624
3625 status = cm_transition(transition, run_number, error_str, sizeof(error_str), async_flag, debug_flag);
3626
3627 MJsonNode* result = MJsonNode::MakeObject();
3628
3629 result->AddToObject("status", MJsonNode::MakeInt(status));
3630 if (strlen(error_str) > 0) {
3631 ss_repair_utf8(error_str);
3632 result->AddToObject("error_string", MJsonNode::MakeString(error_str));
3633 }
3634 return mjsonrpc_make_result(result);
3635}
3636
3638//
3639// Event buffer code goes here
3640//
3642
3643static const EVENT_HEADER* CopyEvent(const EVENT_HEADER* pevent)
3644{
3645 size_t event_size = sizeof(EVENT_HEADER) + pevent->data_size;
3646 //size_t total_size = ALIGN8(event_size);
3647 EVENT_HEADER* ptr = (EVENT_HEADER*)malloc(event_size);
3648 assert(ptr);
3649 memcpy(ptr, pevent, event_size);
3650 return ptr;
3651}
3652
3654{
3655 std::string buffer_name;
3656 int event_id = 0;
3658 const EVENT_HEADER* pevent = NULL;
3659
3661 {
3662 //Print(); printf(", dtor!\n");
3663 buffer_name.clear();
3664 event_id = 0;
3665 trigger_mask = 0;
3666 if (pevent)
3667 free((void*)pevent);
3668 pevent = NULL;
3669 }
3670
3671 void ReplaceEvent(const EVENT_HEADER* xpevent)
3672 {
3673 if (pevent) {
3674 free((void*)pevent);
3675 pevent = NULL;
3676 }
3677 pevent = CopyEvent(xpevent);
3678 }
3679
3680 void Print() const
3681 {
3682 printf("EventStashEntry: %s,%d,0x%x,%p", buffer_name.c_str(), event_id, trigger_mask, pevent);
3683 if (pevent)
3684 printf(", size %d, serial %d, time %d, event_id %d, trigger_mask %x", pevent->data_size, pevent->serial_number, pevent->time_stamp, pevent->event_id, pevent->trigger_mask);
3685 }
3686};
3687
3688static std::mutex gEventStashMutex;
3689static std::vector<EventStashEntry*> gEventStash;
3690
3691static void StashEvent(const std::string buffer_name, int event_id, int trigger_mask, const EVENT_HEADER* pevent)
3692{
3693 std::lock_guard<std::mutex> guard(gEventStashMutex);
3694 bool found = false;
3695 for (EventStashEntry* s : gEventStash) {
3696 if (s->buffer_name != buffer_name)
3697 continue;
3698 if (s->event_id == event_id && s->trigger_mask == trigger_mask) {
3699 found = true;
3700 s->ReplaceEvent(pevent);
3701 //s->Print(); printf(", replaced\n");
3702 } else if (bm_match_event(s->event_id, s->trigger_mask, pevent)) {
3703 s->ReplaceEvent(pevent);
3704 //s->Print(); printf(", matched\n");
3705 }
3706 }
3707 if (!found) {
3710 s->event_id = event_id;
3712 s->pevent = CopyEvent(pevent);
3713 //s->Print(); printf(", added\n");
3714 gEventStash.push_back(s);
3715 }
3716}
3717
3718static void MatchEvent(const std::string buffer_name, const EVENT_HEADER* pevent)
3719{
3720 std::lock_guard<std::mutex> guard(gEventStashMutex);
3721 for (EventStashEntry* s : gEventStash) {
3722 if (s->buffer_name != buffer_name)
3723 continue;
3724 if (bm_match_event(s->event_id, s->trigger_mask, pevent)) {
3725 s->ReplaceEvent(pevent);
3726 //s->Print(); printf(", matched\n");
3727 }
3728 }
3729}
3730
3731static void DeleteEventStash()
3732{
3733 std::lock_guard<std::mutex> guard(gEventStashMutex);
3734 for (size_t i=0; i<gEventStash.size(); i++) {
3735 if (gEventStash[i]) {
3736 delete gEventStash[i];
3737 gEventStash[i] = NULL;
3738 }
3739 }
3740}
3741
3742static const EVENT_HEADER* FindEvent(const std::string buffer_name, int event_id, int trigger_mask, int last_event_id, int last_trigger_mask, DWORD last_serial_number, DWORD last_time_stamp)
3743{
3744 std::lock_guard<std::mutex> guard(gEventStashMutex);
3745 for (EventStashEntry* s : gEventStash) {
3746 if (s->buffer_name != buffer_name)
3747 continue;
3748 if (bm_match_event(event_id, trigger_mask, s->pevent)) {
3749 if (s->pevent->event_id == last_event_id
3750 && s->pevent->trigger_mask == last_trigger_mask
3751 && s->pevent->serial_number == last_serial_number
3752 && s->pevent->time_stamp == last_time_stamp) {
3753 //s->Print(); printf(", already sent for %d,0x%x\n", event_id, trigger_mask);
3754 return NULL;
3755 } else {
3756 //s->Print(); printf(", serving for %d,0x%x\n", event_id, trigger_mask);
3757 return CopyEvent(s->pevent);
3758 }
3759 }
3760 }
3761 return NULL;
3762}
3763
3764static MJsonNode* js_bm_receive_event(const MJsonNode* params)
3765{
3766 if (!params) {
3767 MJSO* doc = MJSO::I();
3768 doc->D("read event buffers");
3769 doc->P("buffer_name", MJSON_STRING, "name of event buffer");
3770 doc->P("event_id?", MJSON_INT, "requested event id, -1 means any event id");
3771 doc->P("trigger_mask?", MJSON_INT, "requested trigger mask, -1 means any trigger mask");
3772 doc->P("get_recent?", MJSON_BOOL, "get last available event that matches this event request");
3773 doc->P("last_event_header[]?", MJSON_INT, "do not resend an event we already received: event header of last received event [event_id,trigger_mask,serial_number,time_stamp]");
3774 doc->P("timeout_millisec?", MJSON_NUMBER, "how long to wait for an event");
3775 doc->R("binary data", MJSON_ARRAYBUFFER, "binary event data");
3776 doc->R("status", MJSON_INT, "return status of bm_open_buffer(), bm_request_event(), bm_set_cache_size(), bm_receive_alloc()");
3777 return doc;
3778 }
3779
3780 MJsonNode* error = NULL;
3781
3782 std::string buffer_name = mjsonrpc_get_param(params, "buffer_name", &error)->GetString(); if (error) return error;
3783 int event_id = mjsonrpc_get_param(params, "event_id", NULL)->GetInt();
3784 int trigger_mask = mjsonrpc_get_param(params, "trigger_mask", NULL)->GetInt();
3785 bool get_recent = mjsonrpc_get_param(params, "get_recent", NULL)->GetBool();
3786 const MJsonNodeVector* last_event_header = mjsonrpc_get_param(params, "last_event_header", NULL)->GetArray();
3787 int timeout_millisec = mjsonrpc_get_param(params, "timeout_millisec", NULL)->GetInt();
3788
3789 int last_event_id = 0;
3790 int last_trigger_mask = 0;
3791 int last_serial_number = 0;
3792 int last_time_stamp = 0;
3793
3794 if (last_event_header && last_event_header->size() > 0) {
3795 if (last_event_header->size() != 4) {
3796 return mjsonrpc_make_error(-32602, "Invalid params", "last_event_header should be an array with 4 elements");
3797 }
3798
3799 last_event_id = (*last_event_header)[0]->GetInt();
3800 last_trigger_mask = (*last_event_header)[1]->GetInt();
3801 last_serial_number = (*last_event_header)[2]->GetInt();
3802 last_time_stamp = (*last_event_header)[3]->GetInt();
3803 }
3804
3805 //printf("last event header: %d %d %d %d\n", last_event_id, last_trigger_mask, last_serial_number, last_time_stamp);
3806
3807 if (event_id == 0)
3809
3810 if (trigger_mask == 0)
3812
3813 //printf("js_bm_receive_event: buffer \"%s\", event_id %d, trigger_mask 0x%04x\n", buffer_name.c_str(), event_id, trigger_mask);
3814
3815 int status;
3816
3817 HNDLE buffer_handle = 0;
3818
3819 status = bm_get_buffer_handle(buffer_name.c_str(), &buffer_handle);
3820
3821 if (status != BM_SUCCESS) {
3822 // if buffer not already open, we need to open it,
3823 // but we must hold a lock in case multiple RPC handler threads
3824 // try to open it at the same time. K.O.
3825 static std::mutex gMutex;
3826 std::lock_guard<std::mutex> lock_guard(gMutex); // lock the mutex
3827
3828 // we have the lock. now we check if some other thread
3829 // opened the buffer while we were waiting for the lock. K.O.
3830 status = bm_get_buffer_handle(buffer_name.c_str(), &buffer_handle);
3831
3832 if (status != BM_SUCCESS) {
3833 status = bm_open_buffer(buffer_name.c_str(), 0, &buffer_handle);
3834 if (status != BM_SUCCESS && status != BM_CREATED) {
3835 MJsonNode* result = MJsonNode::MakeObject();
3836 result->AddToObject("status", MJsonNode::MakeInt(status));
3837 return mjsonrpc_make_result(result);
3838 }
3839 status = bm_set_cache_size(buffer_handle, 0, 0);
3840 if (status != BM_SUCCESS) {
3841 MJsonNode* result = MJsonNode::MakeObject();
3842 result->AddToObject("status", MJsonNode::MakeInt(status));
3843 return mjsonrpc_make_result(result);
3844 }
3845 int request_id = 0;
3846 status = bm_request_event(buffer_handle, EVENTID_ALL, TRIGGER_ALL, GET_NONBLOCKING, &request_id, NULL);
3847 if (status != BM_SUCCESS) {
3848 MJsonNode* result = MJsonNode::MakeObject();
3849 result->AddToObject("status", MJsonNode::MakeInt(status));
3850 return mjsonrpc_make_result(result);
3851 }
3852 }
3853 }
3854
3855 if (timeout_millisec <= 0)
3856 timeout_millisec = 100.0;
3857
3858 double start_time = ss_time_sec();
3859 double end_time = start_time + timeout_millisec/1000.0;
3860
3861 // in "GET_RECENT" mode, we read all avialable events from the event buffer
3862 // and save them in the event stash (MatchEvent()), after we empty the event
3863 // buffer (BM_ASYNC_RETURN), we send the last saved event. K.O.
3864
3865 while (1) {
3866 EVENT_HEADER* pevent = NULL;
3867
3868 status = bm_receive_event_alloc(buffer_handle, &pevent, BM_NO_WAIT);
3869
3870 if (status == BM_SUCCESS) {
3871 //printf("got event_id %d, trigger_mask 0x%04x\n", pevent->event_id, pevent->trigger_mask);
3872
3873 if (get_recent) {
3874 if (bm_match_event(event_id, trigger_mask, pevent)) {
3876 } else {
3877 MatchEvent(buffer_name, pevent);
3878 }
3879 free(pevent);
3880 pevent = NULL;
3881 } else {
3882 if (bm_match_event(event_id, trigger_mask, pevent)) {
3884
3885 size_t event_size = sizeof(EVENT_HEADER) + pevent->data_size;
3886 //size_t total_size = ALIGN8(event_size);
3887 return MJsonNode::MakeArrayBuffer((char*)pevent, event_size);
3888 }
3889
3890 MatchEvent(buffer_name, pevent);
3891
3892 free(pevent);
3893 pevent = NULL;
3894 }
3895 } else if (status == BM_ASYNC_RETURN) {
3896 if (get_recent) {
3897 //printf("bm_async_return!\n");
3898 break;
3899 }
3900 ss_sleep(10);
3901 } else {
3902 MJsonNode* result = MJsonNode::MakeObject();
3903 result->AddToObject("status", MJsonNode::MakeInt(status));
3904 return mjsonrpc_make_result(result);
3905 }
3906
3907 if (ss_time_sec() > end_time) {
3908 //printf("timeout!\n");
3909 break;
3910 }
3911 }
3912
3913 const EVENT_HEADER* pevent = FindEvent(buffer_name, event_id, trigger_mask, last_event_id, last_trigger_mask, last_serial_number, last_time_stamp);
3914 if (pevent) {
3915 size_t event_size = sizeof(EVENT_HEADER) + pevent->data_size;
3916 //size_t total_size = ALIGN8(event_size);
3917 return MJsonNode::MakeArrayBuffer((char*)pevent, event_size);
3918 }
3919
3920 MJsonNode* result = MJsonNode::MakeObject();
3921 result->AddToObject("status", MJsonNode::MakeInt(BM_ASYNC_RETURN));
3922 return mjsonrpc_make_result(result);
3923}
3924
3926//
3927// ss_system code goes here
3928//
3930
3931static MJsonNode* js_ss_millitime(const MJsonNode* params)
3932{
3933 if (!params) {
3934 MJSO *doc = MJSO::I();
3935 doc->D("get current MIDAS time using ss_millitime()");
3936 doc->P(NULL, 0, "there are no input parameters");
3937 doc->R(NULL, MJSON_INT, "current value of ss_millitime()");
3938 return doc;
3939 }
3940
3941 return mjsonrpc_make_result(MJsonNode::MakeNumber(ss_millitime()));
3942}
3943
3945//
3946// Alarm code goes here
3947//
3949
3950static MJsonNode* get_alarms(const MJsonNode* params)
3951{
3952 if (!params) {
3953 MJSO* doc = MJSO::I();
3954 doc->D("get alarm data");
3955 doc->P("get_all?", MJSON_BOOL, "get all alarms, even in alarm system not active and alarms not triggered");
3956 doc->R("status", MJSON_INT, "return status of midas library calls");
3957 doc->R("alarm_system_active", MJSON_BOOL, "value of ODB \"/Alarms/alarm system active\"");
3958 doc->R("alarms", MJSON_OBJECT, "alarm data, keyed by alarm name");
3959 doc->R("alarms[].triggered", MJSON_BOOL, "alarm is triggered");
3960 doc->R("alarms[].active", MJSON_BOOL, "alarm is enabled");
3961 doc->R("alarms[].class", MJSON_STRING, "alarm class");
3962 doc->R("alarms[].type", MJSON_INT, "alarm type AT_xxx");
3963 doc->R("alarms[].bgcolor", MJSON_STRING, "display background color");
3964 doc->R("alarms[].fgcolor", MJSON_STRING, "display foreground color");
3965 doc->R("alarms[].message", MJSON_STRING, "alarm ODB message field");
3966 doc->R("alarms[].condition", MJSON_STRING, "alarm ODB condition field");
3967 doc->R("alarms[].evaluated_value?", MJSON_STRING, "evaluated alarm condition (AT_EVALUATED alarms only)");
3968 doc->R("alarms[].periodic_next_time?", MJSON_STRING, "next time the periodic alarm will fire (AT_PERIODIC alarms only)");
3969 doc->R("alarms[].time_triggered_first", MJSON_STRING, "time when alarm was triggered");
3970 doc->R("alarms[].show_to_user", MJSON_STRING, "final alarm text shown to user by mhttpd");
3971 return doc;
3972 }
3973
3974 //MJsonNode* error = NULL;
3975
3976 bool get_all = mjsonrpc_get_param(params, "get_all", NULL)->GetBool();
3977
3978 int status;
3979 HNDLE hDB;
3980
3982
3983 if (status != DB_SUCCESS) {
3984 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3985 }
3986
3987 int flag;
3988 int size;
3989 int alarm_system_active = 0;
3990
3991 /* check global alarm flag */
3992 flag = TRUE;
3993 size = sizeof(flag);
3994 status = db_get_value(hDB, 0, "/Alarms/Alarm System active", &flag, &size, TID_BOOL, TRUE);
3995
3996 if (status != DB_SUCCESS) {
3997 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
3998 }
3999
4000 alarm_system_active = flag;
4001
4002 if (!alarm_system_active)
4003 if (!get_all) {
4004 return mjsonrpc_make_result("status", MJsonNode::MakeInt(SUCCESS),
4005 "alarm_system_active", MJsonNode::MakeBool(alarm_system_active!=0),
4006 "alarms", MJsonNode::MakeObject());
4007 }
4008
4009 /* go through all alarms */
4010 HNDLE hkey;
4011 status = db_find_key(hDB, 0, "/Alarms/Alarms", &hkey);
4012
4013 if (status != DB_SUCCESS) {
4014 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
4015 }
4016
4017 MJsonNode* alarms = MJsonNode::MakeObject();
4018
4019 for (int i = 0;; i++) {
4020 HNDLE hsubkey;
4021 KEY key;
4022
4023 db_enum_link(hDB, hkey, i, &hsubkey);
4024
4025 if (!hsubkey)
4026 break;
4027
4028 status = db_get_key(hDB, hsubkey, &key);
4029
4030 const char* name = key.name;
4031
4032 flag = 0;
4033 size = sizeof(flag);
4034 status = db_get_value(hDB, hsubkey, "Triggered", &flag, &size, TID_INT, TRUE);
4035
4036 // skip un-triggered alarms
4037 if (!flag)
4038 if (!get_all)
4039 continue;
4040
4041 MJsonNode* a = MJsonNode::MakeObject();
4042
4043 a->AddToObject("triggered", MJsonNode::MakeBool(flag!=0));
4044
4045 flag = 1;
4046 size = sizeof(BOOL);
4047 status = db_get_value(hDB, hsubkey, "Active", &flag, &size, TID_BOOL, TRUE);
4048
4049 a->AddToObject("active", MJsonNode::MakeBool(flag!=0));
4050
4051 char alarm_class[NAME_LENGTH];
4052 strcpy(alarm_class, "Alarm");
4053 size = sizeof(alarm_class);
4054 status = db_get_value(hDB, hsubkey, "Alarm Class", alarm_class, &size, TID_STRING, TRUE);
4055
4056 ss_repair_utf8(alarm_class);
4057 a->AddToObject("class", MJsonNode::MakeString(alarm_class));
4058
4059 int atype = 0;
4060 size = sizeof(atype);
4061 status = db_get_value(hDB, hsubkey, "Type", &atype, &size, TID_INT, TRUE);
4062
4063 a->AddToObject("type", MJsonNode::MakeInt(atype));
4064
4065 char str[256];
4066
4067 char bgcol[256];
4068 strcpy(bgcol, "red");
4069
4070 if (strlen(alarm_class) > 0) {
4071 sprintf(str, "/Alarms/Classes/%s/Display BGColor", alarm_class);
4072 size = sizeof(bgcol);
4073 status = db_get_value(hDB, 0, str, bgcol, &size, TID_STRING, TRUE);
4074 }
4075
4076 ss_repair_utf8(bgcol);
4077 a->AddToObject("bgcolor", MJsonNode::MakeString(bgcol));
4078
4079 char fgcol[256];
4080 strcpy(fgcol, "black");
4081
4082 if (strlen(alarm_class) > 0) {
4083 sprintf(str, "/Alarms/Classes/%s/Display FGColor", alarm_class);
4084 size = sizeof(fgcol);
4085 status = db_get_value(hDB, 0, str, fgcol, &size, TID_STRING, TRUE);
4086 }
4087
4088 ss_repair_utf8(fgcol);
4089 a->AddToObject("fgcolor", MJsonNode::MakeString(fgcol));
4090
4091 flag = 1;
4092 if (strlen(alarm_class) > 0) {
4093 size = sizeof(BOOL);
4094 sprintf(str, "/Alarms/Classes/%s/Alarm sound", alarm_class);
4095 status = db_get_value(hDB, 0, str, &flag, &size, TID_BOOL, TRUE);
4096 }
4097 a->AddToObject("alarm_sound", MJsonNode::MakeBool(flag!=0));
4098
4099 char msg[256];
4100 msg[0] = 0;
4101 size = sizeof(msg);
4102 status = db_get_value(hDB, hsubkey, "Alarm Message", msg, &size, TID_STRING, TRUE);
4103
4104 ss_repair_utf8(msg);
4105 a->AddToObject("message", MJsonNode::MakeString(msg));
4106
4107 char cond[256];
4108 cond[0] = 0;
4109 size = sizeof(cond);
4110 status = db_get_value(hDB, hsubkey, "Condition", cond, &size, TID_STRING, TRUE);
4111
4112 ss_repair_utf8(cond);
4113 a->AddToObject("condition", MJsonNode::MakeString(cond));
4114
4115 std::string show_to_user;
4116
4117 if (atype == AT_EVALUATED) {
4118 /* retrieve value */
4119 std::string value;
4121 show_to_user = msprintf(msg, value.c_str());
4123 a->AddToObject("evaluated_value", MJsonNode::MakeString(value.c_str()));
4124 } else
4125 show_to_user = msg;
4126
4127 ss_repair_utf8(show_to_user);
4128 a->AddToObject("show_to_user", MJsonNode::MakeString(show_to_user.c_str()));
4129
4130 str[0] = 0;
4131 size = sizeof(str);
4132 status = db_get_value(hDB, hsubkey, "Time triggered first", str, &size, TID_STRING, TRUE);
4133
4135 a->AddToObject("time_triggered_first", MJsonNode::MakeString(str));
4136
4137 if (atype == AT_PERIODIC) {
4138 DWORD last = 0;
4139 size = sizeof(last);
4140 db_get_value(hDB, hsubkey, "Checked last", &last, &size, TID_DWORD, TRUE);
4141
4142 if (last == 0) {
4143 last = ss_time();
4144 db_set_value(hDB, hsubkey, "Checked last", &last, size, 1, TID_DWORD);
4145 }
4146
4147 int interval = 0;
4148 size = sizeof(interval);
4149 db_get_value(hDB, hsubkey, "Check interval", &interval, &size, TID_INT, TRUE);
4150
4151 time_t tnext = last + interval;
4152
4153 char ctimebuf[32];
4154 ctime_r(&tnext, ctimebuf);
4155
4156 //ss_repair_utf8(ctimebuf); redundant!
4157 a->AddToObject("periodic_next_time", MJsonNode::MakeString(ctimebuf));
4158 }
4159
4160 alarms->AddToObject(name, a);
4161 }
4162
4163 return mjsonrpc_make_result("status", MJsonNode::MakeInt(SUCCESS),
4164 "alarm_system_active", MJsonNode::MakeBool(alarm_system_active!=0),
4165 "alarms", alarms);
4166}
4167
4169//
4170// Sequencer and file_picker code goes here
4171//
4173
4174static MJsonNode* js_make_subdir(const MJsonNode* params)
4175{
4176 if (!params) {
4177 MJSO* doc = MJSO::I();
4178 doc->D("js_make_subdir");
4179 doc->P("subdir", MJSON_STRING, "Create folder experiment_directory/userfiles/subdir");
4180 doc->R("status", MJSON_INT, "return status of midas library calls");
4181 doc->R("path", MJSON_STRING, "Search path");
4182 return doc;
4183 }
4184
4185 MJsonNode* error = NULL;
4186
4187 std::string subdir = mjsonrpc_get_param(params, "subdir", &error)->GetString(); if (error) return error;
4188
4189 /*---- Not allowed to contain ../ - safety feature ----*/
4190 if (subdir.find("..") != std::string::npos) {
4191 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("The subdir is not permitted"));
4192 }
4193
4194 int status;
4195 HNDLE hDB;
4196
4198
4199 if (status != DB_SUCCESS) {
4200 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
4201 }
4202
4203 std::string path = cm_expand_env(cm_get_path().c_str());
4204 if (path[path.length()-1] != DIR_SEPARATOR) {
4205 path += DIR_SEPARATOR_STR;
4206 }
4207 path += "userfiles";
4208
4209 // Check if the userfiles folder exists
4210 if (access(path.c_str(), F_OK) != 0) {
4211 // Create the path if it doesn't exist
4212 if (mkdir(path.c_str(), 0777) != 0) {
4213 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Failed to create the userfiles folder"));
4214 }
4215 }
4216
4217 // Add subdir to userfiles
4218 if (subdir.length() > 0) {
4219 if (subdir[0] != DIR_SEPARATOR) {
4220 path += DIR_SEPARATOR_STR;
4221 }
4222 path += subdir;
4223 }
4224 // Check if the subdir exisits in userfiles, otherwise create it
4225 if (access(path.c_str(), F_OK) != 0) {
4226 // Create the path if it doesn't exist
4227 if (mkdir(path.c_str(), 0777) != 0) {
4228 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Failed to create subdirectory"));
4229 }
4230 }
4231
4232
4233 MJsonNode* r = MJsonNode::MakeObject();
4234 r->AddToObject("status", MJsonNode::MakeInt(SUCCESS));
4235 ss_repair_utf8(path);
4236 r->AddToObject("path", MJsonNode::MakeString(path.c_str()));
4237 return mjsonrpc_make_result(r);
4238}
4239
4240static MJsonNode* js_ext_list_files(const MJsonNode* params)
4241{
4242 if (!params) {
4243 MJSO* doc = MJSO::I();
4244 doc->D("js_ext_list_files");
4245 doc->P("subdir", MJSON_STRING, "List files in experiment_directory/userfiles/subdir");
4246 doc->P("fileext", MJSON_STRING, "Filename extension");
4247 doc->R("status", MJSON_INT, "return status of midas library calls");
4248 doc->R("path", MJSON_STRING, "Search path");
4249 doc->R("subdirs[]", MJSON_STRING, "list of subdirectories");
4250 doc->R("files[].filename", MJSON_STRING, "script filename");
4251 doc->R("files[].description", MJSON_STRING, "script description");
4252 return doc;
4253 }
4254
4255 MJsonNode* error = NULL;
4256 std::string subdir = mjsonrpc_get_param(params, "subdir", &error)->GetString(); if (error) return error;
4257 std::string fileext = mjsonrpc_get_param(params, "fileext", &error)->GetString(); if (error) return error;
4258
4259 /*---- Not allowed to contain ../ - safety feature ----*/
4260 if (subdir.find("..") != std::string::npos) {
4261 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("The subdir is not permitted"));
4262 }
4263
4264 /*---- ext must start with *. and some not allowed ext - safety feature */
4265 if (fileext.find("..") != std::string::npos) {
4266 /*
4267 fileext.find("/") != std::string::npos ||
4268 fileext.find("*.") != 0 ||
4269 fileext.find("*.html") != std::string::npos || fileext.find("*.HTML") != std::string::npos ||
4270 fileext.find("*.htm") != std::string::npos || fileext.find("*.HTM") != std::string::npos ||
4271 fileext.find("*.js") != std::string::npos || fileext.find("*.JS") != std::string::npos ||
4272 fileext.find("*.pl") != std::string::npos || fileext.find("*.PL") != std::string::npos ||
4273 fileext.find("*.cgi") != std::string::npos || fileext.find("*.CGI") != std::string::npos ||
4274 fileext.find("*.*") != std::string::npos
4275 ) {
4276 */
4277 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("The filename extension is not permitted"));
4278 }
4279
4280 int status;
4281 HNDLE hDB;
4282
4284
4285 if (status != DB_SUCCESS) {
4286 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status));
4287 }
4288
4289 std::string path = cm_expand_env(cm_get_path().c_str());
4290 if (path[path.length()-1] != DIR_SEPARATOR) {
4291 path += DIR_SEPARATOR_STR;
4292 }
4293 path += "userfiles";
4294
4295 // Check if the userfiles folder exists
4296 if (access(path.c_str(), F_OK) != 0) {
4297 // Create the path if it doesn't exist
4298 if (mkdir(path.c_str(), 0777) != 0) {
4299 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Failed to create the userfiles folder"));
4300 }
4301 }
4302
4303 if (subdir.length() > 0) {
4304 if (subdir[0] != DIR_SEPARATOR) {
4305 path += DIR_SEPARATOR_STR;
4306 }
4307 path += subdir;
4308 }
4309
4310 char* flist = NULL;
4311 MJsonNode* s = MJsonNode::MakeArray();
4312
4313 /*---- go over subdirectories ----*/
4314 int n = ss_dirlink_find(path.c_str(), "*", &flist);
4315
4316 for (int i=0 ; i<n ; i++) {
4317 if (flist[i*MAX_STRING_LENGTH] != '.') {
4318 //printf("subdir %d: [%s]\n", i, flist+i*MAX_STRING_LENGTH);
4320 s->AddToArray(MJsonNode::MakeString(flist+i*MAX_STRING_LENGTH));
4321 }
4322 }
4323
4324 MJsonNode* f = MJsonNode::MakeArray();
4325 time_t modtime = time(NULL);
4326 double fsize;
4327 /*---- go over files with extension fileext in path ----*/
4328 n = ss_file_find(path.c_str(), fileext.c_str(), &flist);
4329
4330 if (n == -1) {
4331 // path does not exist, return an error
4332 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Subdirectory does not exist, create it first."));
4333 }
4334
4335 for (int i=0 ; i<n ; i++) {
4336 //printf("file %d: [%s]\n", i, flist+i*MAX_STRING_LENGTH);
4337 MJsonNode* o = MJsonNode::MakeObject();
4339 o->AddToObject("filename", MJsonNode::MakeString(flist+i*MAX_STRING_LENGTH));
4340 /* description is msl specific, do we need it? */
4341 std::string full_name = path;
4342 if (full_name.back() != DIR_SEPARATOR)
4343 full_name += DIR_SEPARATOR;
4344 full_name.append(flist+i*MAX_STRING_LENGTH);
4345 // o->AddToObject("description", MJsonNode::MakeString(full_name.c_str()));
4346 o->AddToObject("description", MJsonNode::MakeString("description"));
4347 modtime = ss_file_time(full_name.c_str());
4348 o->AddToObject("modtime", MJsonNode::MakeInt(modtime));
4349 fsize = ss_file_size(full_name.c_str());
4350 o->AddToObject("size", MJsonNode::MakeInt(fsize));
4351 f->AddToArray(o);
4352 }
4353
4354 free(flist);
4355 flist = NULL;
4356
4357 MJsonNode* r = MJsonNode::MakeObject();
4358 r->AddToObject("status", MJsonNode::MakeInt(SUCCESS));
4359 ss_repair_utf8(path);
4360 r->AddToObject("path", MJsonNode::MakeString(path.c_str()));
4361 r->AddToObject("subdirs", s);
4362 r->AddToObject("files", f);
4363
4364 return mjsonrpc_make_result(r);
4365
4366}
4367
4368static MJsonNode* js_ext_save_file(const MJsonNode* params)
4369{
4370 if (!params) {
4371 MJSO* doc = MJSO::I();
4372 doc->D("js_ext_save_file");
4373 doc->P("filename", MJSON_STRING, "File name, save in experiment_directory/userfiles/filename");
4374 doc->P("script", MJSON_STRING, "ASCII content");
4375 doc->R("status", MJSON_INT, "return status of midas library calls");
4376 doc->R("error", MJSON_STRING, "error text");
4377 return doc;
4378 }
4379
4380 /* Need to make sure that content cannot be abused (e.g. not Javascript code), how?? */
4381
4382 MJsonNode* error = NULL;
4383 std::string filename = mjsonrpc_get_param(params, "filename", &error)->GetString(); if (error) return error;
4384 std::string script = mjsonrpc_get_param(params, "script", &error)->GetString(); if (error) return error;
4385
4386 /*---- filename should not contain the following - safety feature */
4387 if (filename.find("..") != std::string::npos ) {
4388 /*
4389 filename.find("*") != std::string::npos ||
4390 filename.find(".html") != std::string::npos || filename.find(".HTML") != std::string::npos ||
4391 filename.find(".htm") != std::string::npos || filename.find(".HTM") != std::string::npos ||
4392 filename.find(".js") != std::string::npos || filename.find(".JS") != std::string::npos ||
4393 filename.find(".pl") != std::string::npos || filename.find(".PL") != std::string::npos ||
4394 filename.find(".cgi") != std::string::npos || filename.find(".CGI") != std::string::npos
4395 ) {
4396 */
4397 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("The filename is not permitted"));
4398 }
4399
4400 int status;
4401 HNDLE hDB;
4402
4404
4405 if (status != DB_SUCCESS) {
4406 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString("cm_get_experiment_database() error"));
4407 }
4408
4409 std::string path = cm_expand_env(cm_get_path().c_str());
4410 path += "userfiles";
4411
4412 // Check if the userfiles folder exists
4413 if (access(path.c_str(), F_OK) != 0) {
4414 // Create the path if it doesn't exist
4415 if (mkdir(path.c_str(), 0777) != 0) {
4416 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Failed to create the userfiles folder"));
4417 }
4418 }
4419
4420 path += DIR_SEPARATOR_STR;
4421 path += filename;
4422
4423 FILE* fp = fopen(path.c_str(), "w");
4424 if (!fp) {
4426 char errstr[256];
4427 sprintf(errstr, "fopen() errno %d (%s)", errno, strerror(errno));
4428 ss_repair_utf8(errstr);
4429 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString(errstr));
4430 }
4431
4432 fwrite(script.c_str(), script.length(), 1, fp);
4433 //fprintf(fp, "\n");
4434 fclose(fp);
4435 fp = NULL;
4436
4438 std::string errstr = "no error";
4439
4440 //ss_repair_utf8(errstr); redundant!
4441 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString(errstr.c_str()));
4442}
4443
4444static MJsonNode* js_ext_read_file(const MJsonNode* params)
4445{
4446 if (!params) {
4447 MJSO* doc = MJSO::I();
4448 doc->D("js_ext_read_script");
4449 doc->P("filename", MJSON_STRING, "File name, read from experiment_directory/userfiles/filename");
4450 doc->R("content", MJSON_STRING, "ASCII file content");
4451 doc->R("status", MJSON_INT, "return status of midas library calls");
4452 doc->R("error", MJSON_STRING, "error text");
4453 return doc;
4454 }
4455
4456 MJsonNode* error = NULL;
4457 std::string filename = mjsonrpc_get_param(params, "filename", &error)->GetString(); if (error) return error;
4458
4459 /*---- filename should not contain the following - safety feature */
4460 if (filename.find("..") != std::string::npos ||
4461 filename.find("*") != std::string::npos) {
4462 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("The filename is not permitted"));
4463 }
4464
4465 int status;
4466 HNDLE hDB;
4467
4469
4470 if (status != DB_SUCCESS) {
4471 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString("cm_get_experiment_database() error"));
4472 }
4473
4474 std::string path = cm_expand_env(cm_get_path().c_str());
4475 if (path[path.length()-1] != DIR_SEPARATOR) {
4476 path += DIR_SEPARATOR_STR;
4477 }
4478 path += "userfiles";
4479
4480 // Check if the userfiles folder exists
4481 if (access(path.c_str(), F_OK) != 0) {
4482 // Create the path if it doesn't exist
4483 if (mkdir(path.c_str(), 0777) != 0) {
4484 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Failed to create the userfiles folder"));
4485 }
4486 }
4487
4488 path += DIR_SEPARATOR_STR;
4489 path += filename;
4490
4491 FILE* fp = fopen(path.c_str(), "r");
4492 if (!fp) {
4494 char errstr[256];
4495 sprintf(errstr, "fopen() errno %d (%s)", errno, strerror(errno));
4496 ss_repair_utf8(errstr);
4497 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString(errstr));
4498 }
4499
4500 fseek(fp, 0, SEEK_END);
4501 size_t file_size = ftell(fp);
4502 rewind(fp);
4503
4504 char* buffer = new char[file_size+1];
4505 fread(buffer, file_size, 1, fp);
4506 // Maybe not needed here
4507 buffer[file_size] = '\0';
4508 fclose(fp);
4509
4510 std::string content = buffer;
4511 delete[] buffer;
4512 buffer = NULL;
4513
4515 std::string errstr = "no error";
4516
4517 return mjsonrpc_make_result("content", MJsonNode::MakeString(content.c_str()), "status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString(errstr.c_str()));
4518}
4519
4521//
4522// Binary files reading for file_picker code goes here
4523//
4525
4526static MJsonNode* js_read_binary_file(const MJsonNode* params) {
4527 if (!params) {
4528 MJSO* doc = MJSO::I();
4529 doc->D("js_read_binary_file");
4530 doc->P("filename", MJSON_STRING, "File name, read from experiment_directory/userfiles/filename");
4531 doc->R("binary data", MJSON_ARRAYBUFFER, "Binary file content");
4532 doc->R("status", MJSON_INT, "Return status of midas library calls");
4533 doc->R("error", MJSON_STRING, "Error text");
4534 return doc;
4535 }
4536
4537 MJsonNode* error = NULL;
4538 std::string filename = mjsonrpc_get_param(params, "filename", &error)->GetString();
4539 if (error) return error;
4540
4541 /*---- filename should not contain the following - safety feature */
4542 if (filename.find("..") != std::string::npos ||
4543 filename.find("*") != std::string::npos) {
4544 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("The filename is not permitted"));
4545 }
4546
4547 int status;
4548 HNDLE hDB;
4549
4551
4552 if (status != DB_SUCCESS) {
4553 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString("cm_get_experiment_database() error"));
4554 }
4555
4556 std::string path = cm_expand_env(cm_get_path().c_str());
4557 if (path[path.length()-1] != DIR_SEPARATOR) {
4558 path += DIR_SEPARATOR_STR;
4559 }
4560 path += "userfiles";
4561
4562 // Check if the userfiles folder exists
4563 if (access(path.c_str(), F_OK) != 0) {
4564 // Create the path if it doesn't exist
4565 if (mkdir(path.c_str(), 0777) != 0) {
4566 return mjsonrpc_make_result("status", MJsonNode::MakeInt(DB_INVALID_PARAM), "error", MJsonNode::MakeString("Failed to create the userfiles folder"));
4567 }
4568 }
4569
4570 path += DIR_SEPARATOR_STR;
4571 path += filename;
4572
4573 FILE* fp = fopen(path.c_str(), "rb");
4574 if (!fp) {
4576 char errstr[256];
4577 sprintf(errstr, "fopen() errno %d (%s)", errno, strerror(errno));
4578 ss_repair_utf8(errstr);
4579 return mjsonrpc_make_result("status", MJsonNode::MakeInt(status), "error", MJsonNode::MakeString(errstr));
4580 }
4581
4582 fseek(fp, 0, SEEK_END);
4583 size_t file_size = ftell(fp);
4584 rewind(fp);
4585
4586 char* buffer = new char[file_size];
4587 fread(buffer, file_size, 1, fp);
4588 // maybe not needed here
4589 //buffer[file_size] = '\0';
4590 fclose(fp);
4591
4593 std::string errstr = "no error";
4594
4595 MJsonNode* result = MJsonNode::MakeArrayBuffer(buffer, file_size);
4596 return result;
4597}
4598
4599
4601//
4602// JSON-RPC management code goes here
4603//
4605
4606static MJsonNode* get_debug(const MJsonNode* params)
4607{
4608 if (!params) {
4609 MJSO *doc = MJSO::I();
4610 doc->D("get current value of mjsonrpc_debug");
4611 doc->P(NULL, 0, "there are no input parameters");
4612 doc->R(NULL, MJSON_INT, "current value of mjsonrpc_debug");
4613 return doc;
4614 }
4615
4616 return mjsonrpc_make_result("debug", MJsonNode::MakeInt(mjsonrpc_debug));
4617}
4618
4619static MJsonNode* set_debug(const MJsonNode* params)
4620{
4621 if (!params) {
4622 MJSO* doc = MJSO::I();
4623 doc->D("set new value of mjsonrpc_debug");
4624 doc->P(NULL, MJSON_INT, "new value of mjsonrpc_debug");
4625 doc->R(NULL, MJSON_INT, "new value of mjsonrpc_debug");
4626 return doc;
4627 }
4628
4629 mjsonrpc_debug = params->GetInt();
4630 return mjsonrpc_make_result("debug", MJsonNode::MakeInt(mjsonrpc_debug));
4631}
4632
4633static MJsonNode* get_sleep(const MJsonNode* params)
4634{
4635 if (!params) {
4636 MJSO *doc = MJSO::I();
4637 doc->D("get current value of mjsonrpc_sleep");
4638 doc->P(NULL, 0, "there are no input parameters");
4639 doc->R(NULL, MJSON_INT, "current value of mjsonrpc_sleep");
4640 return doc;
4641 }
4642
4643 return mjsonrpc_make_result("sleep", MJsonNode::MakeInt(mjsonrpc_sleep));
4644}
4645
4646static MJsonNode* set_sleep(const MJsonNode* params)
4647{
4648 if (!params) {
4649 MJSO* doc = MJSO::I();
4650 doc->D("set new value of mjsonrpc_sleep");
4651 doc->P(NULL, MJSON_INT, "new value of mjsonrpc_sleep");
4652 doc->R(NULL, MJSON_INT, "new value of mjsonrpc_sleep");
4653 return doc;
4654 }
4655
4656 mjsonrpc_sleep = params->GetInt();
4657 return mjsonrpc_make_result("sleep", MJsonNode::MakeInt(mjsonrpc_sleep));
4658}
4659
4660static MJsonNode* get_time(const MJsonNode* params)
4661{
4662 if (!params) {
4663 MJSO *doc = MJSO::I();
4664 doc->D("get current value of mjsonrpc_time");
4665 doc->P(NULL, 0, "there are no input parameters");
4666 doc->R(NULL, MJSON_INT, "current value of mjsonrpc_time");
4667 return doc;
4668 }
4669
4670 return mjsonrpc_make_result("time", MJsonNode::MakeInt(mjsonrpc_time));
4671}
4672
4673static MJsonNode* set_time(const MJsonNode* params)
4674{
4675 if (!params) {
4676 MJSO* doc = MJSO::I();
4677 doc->D("set new value of mjsonrpc_time");
4678 doc->P(NULL, MJSON_INT, "new value of mjsonrpc_time");
4679 doc->R(NULL, MJSON_INT, "new value of mjsonrpc_time");
4680 return doc;
4681 }
4682
4683 mjsonrpc_time = params->GetInt();
4684 return mjsonrpc_make_result("time", MJsonNode::MakeInt(mjsonrpc_time));
4685}
4686
4687static MJsonNode* get_schema(const MJsonNode* params)
4688{
4689 if (!params) {
4690 MJSO* doc = MJSO::I();
4691 doc->D("Get the MIDAS JSON-RPC schema JSON object");
4692 doc->P(NULL, 0, "there are no input parameters");
4693 doc->R(NULL, MJSON_OBJECT, "returns the MIDAS JSON-RPC schema JSON object");
4694 return doc;
4695 }
4696
4698}
4699
4700static MJsonNode* js_get_timezone(const MJsonNode* params)
4701{
4702 if (!params) {
4703 MJSO *doc = MJSO::I();
4704 doc->D("get current server timezone offset in seconds");
4705 doc->P(NULL, 0, "there are no input parameters");
4706 doc->R(NULL, MJSON_INT, "offset in seconds");
4707 return doc;
4708 }
4709
4710 ss_tzset(); // required for localtime_r()
4711 time_t rawtime = time(NULL);
4712 struct tm gmt_tms;
4713 gmtime_r(&rawtime, &gmt_tms);
4714 time_t gmt = ss_mktime(&gmt_tms);
4715 struct tm tms;
4716 localtime_r(&rawtime, &tms);
4717 time_t offset = rawtime - gmt + (tms.tm_isdst ? 3600 : 0);
4718
4719 return mjsonrpc_make_result(MJsonNode::MakeNumber(offset));
4720}
4721
4722
4724//
4725// No RPC handlers beyound here
4726//
4728
4734
4735typedef std::map<std::string, MethodsTableEntry> MethodsTable;
4736typedef MethodsTable::iterator MethodsTableIterator;
4737
4739static std::mutex* gMutex = NULL;
4740
4741void mjsonrpc_add_handler(const char* method, mjsonrpc_handler_t* handler, bool needs_locking)
4742{
4744 e.fHandler = handler;
4745 e.fNeedsLocking = needs_locking;
4746 gMethodsTable[method] = e;
4747}
4748
4749void mjsonrpc_set_std_mutex(void* mutex)
4750{
4751 gMutex = (std::mutex*)mutex;
4752}
4753
4755{
4756 if (mjsonrpc_debug) {
4757 printf("mjsonrpc_init!\n");
4758 }
4759
4760 if (!gNullNode)
4761 gNullNode = MJsonNode::MakeNull();
4762
4763 // test, debug and control methods for the rpc system
4764 mjsonrpc_add_handler("null", xnull);
4765 mjsonrpc_add_handler("get_debug", get_debug);
4766 mjsonrpc_add_handler("set_debug", set_debug);
4767 mjsonrpc_add_handler("get_sleep", get_sleep);
4768 mjsonrpc_add_handler("set_sleep", set_sleep);
4769 mjsonrpc_add_handler("get_time", get_time);
4770 mjsonrpc_add_handler("set_time", set_time);
4771 mjsonrpc_add_handler("get_schema", get_schema);
4772 // interface to alarm functions
4773 mjsonrpc_add_handler("al_reset_alarm", js_al_reset_alarm, true);
4774 mjsonrpc_add_handler("al_trigger_alarm", js_al_trigger_alarm, true);
4775 mjsonrpc_add_handler("al_trigger_class", js_al_trigger_class, true);
4776 // interface to midas.c functions
4777 mjsonrpc_add_handler("cm_exist", js_cm_exist, true);
4778 mjsonrpc_add_handler("cm_msg_facilities", js_cm_msg_facilities);
4779 mjsonrpc_add_handler("cm_msg_retrieve", js_cm_msg_retrieve);
4780 mjsonrpc_add_handler("cm_msg1", js_cm_msg1);
4781 mjsonrpc_add_handler("cm_shutdown", js_cm_shutdown, true);
4782 mjsonrpc_add_handler("cm_transition", js_cm_transition, true);
4783 mjsonrpc_add_handler("bm_receive_event", js_bm_receive_event, true);
4784 // interface to odb functions
4785 mjsonrpc_add_handler("db_copy", js_db_copy);
4786 mjsonrpc_add_handler("db_paste", js_db_paste);
4787 mjsonrpc_add_handler("db_get_values", js_db_get_values);
4789 mjsonrpc_add_handler("db_create", js_db_create);
4790 mjsonrpc_add_handler("db_delete", js_db_delete);
4791 mjsonrpc_add_handler("db_resize", js_db_resize);
4792 mjsonrpc_add_handler("db_resize_string", js_db_resize_string);
4793 mjsonrpc_add_handler("db_rename", js_db_rename);
4796 mjsonrpc_add_handler("db_link", js_db_link);
4797 mjsonrpc_add_handler("db_reorder", js_db_reorder);
4799 // interface to elog functions
4800 mjsonrpc_add_handler("el_retrieve", js_el_retrieve, true);
4801 mjsonrpc_add_handler("el_query", js_el_query, true);
4802 mjsonrpc_add_handler("el_delete", js_el_delete, true);
4803 // interface to midas history
4804 mjsonrpc_add_handler("hs_get_active_events", js_hs_get_active_events, true);
4805 mjsonrpc_add_handler("hs_get_channels", js_hs_get_channels, true);
4806 mjsonrpc_add_handler("hs_get_events", js_hs_get_events, true);
4807 mjsonrpc_add_handler("hs_get_tags", js_hs_get_tags, true);
4808 mjsonrpc_add_handler("hs_get_last_written", js_hs_get_last_written, true);
4809 mjsonrpc_add_handler("hs_reopen", js_hs_reopen, true);
4810 mjsonrpc_add_handler("hs_read", js_hs_read, true);
4811 mjsonrpc_add_handler("hs_read_binned", js_hs_read_binned, true);
4812 mjsonrpc_add_handler("hs_read_arraybuffer", js_hs_read_arraybuffer, true);
4813 mjsonrpc_add_handler("hs_read_binned_arraybuffer", js_hs_read_binned_arraybuffer, true);
4814 // interface to image history
4815 mjsonrpc_add_handler("hs_image_retrieve", js_hs_image_retrieve, true);
4816 // sequencer and file_picker
4817 mjsonrpc_add_handler("make_subdir", js_make_subdir, true);
4818 mjsonrpc_add_handler("ext_list_files", js_ext_list_files, true);
4819 mjsonrpc_add_handler("ext_save_file", js_ext_save_file, true);
4820 mjsonrpc_add_handler("ext_read_file", js_ext_read_file, true);
4821 // Read binary files of Uint8Arry
4822 mjsonrpc_add_handler("read_binary_file", js_read_binary_file, true);
4823 // interface to ss_system functions
4824 mjsonrpc_add_handler("ss_millitime", js_ss_millitime);
4825 // methods that perform computations or invoke actions
4826 mjsonrpc_add_handler("get_alarms", get_alarms);
4827 //mjsonrpc_add_handler("get_messages", get_messages);
4829 mjsonrpc_add_handler("jrpc_cxx", jrpc_cxx);
4830 mjsonrpc_add_handler("jrpc_old", jrpc_old);
4832 mjsonrpc_add_handler("brpc_cxx", brpc_cxx);
4833 mjsonrpc_add_handler("brpc_old", brpc_old);
4834 mjsonrpc_add_handler("start_program", start_program);
4835 mjsonrpc_add_handler("exec_script", exec_script);
4836 // timezone function
4837 mjsonrpc_add_handler("get_timezone", js_get_timezone);
4838
4840}
4841
4843{
4844 if (mjsonrpc_debug) {
4845 printf("mjsonrpc_exit!\n");
4846 }
4847
4848 js_hs_exit();
4850}
4851
4853{
4854 MJsonNode* s = MJsonNode::MakeObject();
4855
4856 s->AddToObject("$schema", MJsonNode::MakeString("http://json-schema.org/schema#"));
4857 s->AddToObject("id", MJsonNode::MakeString("MIDAS JSON-RPC autogenerated schema"));
4858 s->AddToObject("title", MJsonNode::MakeString("MIDAS JSON-RPC schema"));
4859 s->AddToObject("description", MJsonNode::MakeString("Autogenerated schema for all MIDAS JSON-RPC methods"));
4860 s->AddToObject("type", MJsonNode::MakeString("object"));
4861
4862 MJsonNode* m = MJsonNode::MakeObject();
4863
4864 for (MethodsTableIterator iterator = h->begin(); iterator != h->end(); iterator++) {
4865 // iterator->first = key
4866 // iterator->second = value
4867 //printf("build schema for method \"%s\"!\n", iterator->first.c_str());
4868 MJsonNode* doc = iterator->second.fHandler(NULL);
4869 if (doc == NULL)
4870 doc = MJsonNode::MakeObject();
4871 m->AddToObject(iterator->first.c_str(), doc);
4872 }
4873
4874 s->AddToObject("properties", m);
4875 s->AddToObject("required", MJsonNode::MakeArray());
4876
4877 return s;
4878}
4879
4881{
4883}
4884
4885#ifdef MJSON_DEBUG
4886static void mjsonrpc_print_schema()
4887{
4888 MJsonNode *s = mjsonrpc_get_schema();
4889 s->Dump(0);
4890 std::string str = s->Stringify(1);
4891 printf("MJSON-RPC schema:\n");
4892 printf("%s\n", str.c_str());
4893 delete s;
4894}
4895#endif
4896
4897static std::string indent(int x, const char* p = " ")
4898{
4899 if (x<1)
4900 return "";
4901 std::string s;
4902 for (int i=0; i<x; i++)
4903 s += p;
4904 return s;
4905}
4906
4908 int nest;
4909 bool span;
4910 std::string text;
4911};
4912
4914{
4915public:
4916 std::vector<NestedLine> fLines;
4917public:
4918 void Clear()
4919 {
4920 fLines.clear();
4921 }
4922
4923 void Output(int nest, bool span, std::string text)
4924 {
4925 if (text.length() < 1)
4926 return;
4927
4928 NestedLine l;
4929 l.nest = nest;
4930 l.span = span;
4931 l.text = text;
4932 fLines.push_back(l);
4933 };
4934
4935 std::string Print()
4936 {
4937 std::vector<int> tablen;
4938 std::vector<std::string> tab;
4939 std::vector<std::string> tabx;
4940
4941 tablen.push_back(0);
4942 tab.push_back("");
4943 tabx.push_back("");
4944
4945 std::string xtab = "";
4946 int maxlen = 0;
4947 for (int n=0; ; n++) {
4948 int len = -1;
4949 for (unsigned i=0; i<fLines.size(); i++) {
4950 int nn = fLines[i].nest;
4951 bool pp = fLines[i].span;
4952 if (pp)
4953 continue;
4954 if (nn != n)
4955 continue;
4956 int l = fLines[i].text.length();
4957 if (l>len)
4958 len = l;
4959 }
4960 //printf("nest %d len %d\n", n, len);
4961 if (len < 0)
4962 break; // nothing with this nest level
4963 tablen.push_back(len);
4964 tab.push_back(indent(len, " ") + " | ");
4965 xtab += indent(len, " ") + " | ";
4966 tabx.push_back(xtab);
4967 maxlen += 3+len;
4968 }
4969
4970 std::string s;
4971 int nest = 0;
4972
4973 for (unsigned i=0; i<fLines.size(); i++) {
4974 int n = fLines[i].nest;
4975 bool p = fLines[i].span;
4976
4977 std::string pad;
4978
4979 if (!p) {
4980 int ipad = tablen[n+1] - fLines[i].text.length();
4981 pad = indent(ipad, " ");
4982 }
4983
4984 std::string hr = indent(maxlen-tabx[n].length(), "-");
4985
4986 if (n > nest)
4987 s += std::string(" | ") + fLines[i].text + pad;
4988 else if (n == nest) {
4989 s += "\n";
4990 if (n == 0 || n == 1)
4991 s += tabx[n] + hr + "\n";
4992 s += tabx[n] + fLines[i].text + pad;
4993 } else {
4994 s += "\n";
4995 if (n == 0 || n == 1)
4996 s += tabx[n] + hr + "\n";
4997 s += tabx[n] + fLines[i].text + pad;
4998 }
4999
5000 nest = n;
5001 }
5002
5003 return s;
5004 }
5005};
5006
5007static std::string mjsonrpc_schema_to_html_anything(const MJsonNode* schema, int nest_level, NestedOutput* o);
5008
5009static std::string mjsonrpc_schema_to_html_object(const MJsonNode* schema, int nest_level, NestedOutput* o)
5010{
5011 const MJsonNode* d = schema->FindObjectNode("description");
5012 std::string description;
5013 if (d)
5014 description = d->GetString();
5015
5016 std::string xshort = "object";
5017 if (description.length() > 1)
5018 xshort += "</td><td>" + description;
5019
5020 const MJsonNode* properties = schema->FindObjectNode("properties");
5021
5022 const MJsonNodeVector* required_list = NULL;
5023 const MJsonNode* r = schema->FindObjectNode("required");
5024 if (r)
5025 required_list = r->GetArray();
5026
5027 if (!properties) {
5028 o->Output(nest_level, false, "object");
5029 o->Output(nest_level+1, true, description);
5030 return xshort;
5031 }
5032
5033 const MJsonStringVector *names = properties->GetObjectNames();
5034 const MJsonNodeVector *nodes = properties->GetObjectNodes();
5035
5036 if (!names || !nodes) {
5037 o->Output(nest_level, false, "object");
5038 o->Output(nest_level+1, true, description);
5039 return xshort;
5040 }
5041
5042 std::string nest = indent(nest_level * 4);
5043
5044 std::string s;
5045
5046 s += nest + "<table border=1>\n";
5047
5048 if (description.length() > 1) {
5049 s += nest + "<tr>\n";
5050 s += nest + " <td colspan=3>" + description + "</td>\n";
5051 s += nest + "</tr>\n";
5052 }
5053
5054 o->Output(nest_level, true, description);
5055
5056 for (unsigned i=0; i<names->size(); i++) {
5057 std::string name = (*names)[i];
5058 const MJsonNode* node = (*nodes)[i];
5059
5060 bool required = false;
5061 if (required_list)
5062 for (unsigned j=0; j<required_list->size(); j++)
5063 if ((*required_list)[j])
5064 if ((*required_list)[j]->GetString() == name) {
5065 required = true;
5066 break;
5067 }
5068
5069 bool is_array = false;
5070 const MJsonNode* type = node->FindObjectNode("type");
5071 if (type && type->GetString() == "array")
5072 is_array = true;
5073
5074 if (is_array)
5075 name += "[]";
5076
5077 if (!required)
5078 name += "?";
5079
5080 o->Output(nest_level, false, name);
5081
5082 s += nest + "<tr>\n";
5083 s += nest + " <td>" + name + "</td>\n";
5084 s += nest + " <td>";
5085 s += mjsonrpc_schema_to_html_anything(node, nest_level + 1, o);
5086 s += "</td>\n";
5087 s += nest + "</tr>\n";
5088 }
5089
5090 s += nest + "</table>\n";
5091
5092 return s;
5093}
5094
5095static std::string mjsonrpc_schema_to_html_array(const MJsonNode* schema, int nest_level, NestedOutput* o)
5096{
5097 const MJsonNode* d = schema->FindObjectNode("description");
5098 std::string description;
5099 if (d)
5100 description = d->GetString();
5101
5102 std::string xshort = "array";
5103 if (description.length() > 1)
5104 xshort += "</td><td>" + description;
5105
5106 const MJsonNode* items = schema->FindObjectNode("items");
5107
5108 if (!items) {
5109 o->Output(nest_level, false, "array");
5110 o->Output(nest_level+1, true, description);
5111 return xshort;
5112 }
5113
5114 const MJsonNodeVector *nodes = items->GetArray();
5115
5116 if (!nodes) {
5117 o->Output(nest_level, false, "array");
5118 o->Output(nest_level+1, true, description);
5119 return xshort;
5120 }
5121
5122 std::string nest = indent(nest_level * 4);
5123
5124 std::string s;
5125
5126 //s += "array</td><td>";
5127
5128 s += nest + "<table border=1>\n";
5129
5130 if (description.length() > 1) {
5131 s += nest + "<tr>\n";
5132 s += nest + " <td>" + description + "</td>\n";
5133 s += nest + "</tr>\n";
5134 }
5135
5136 o->Output(nest_level, true, description);
5137
5138 for (unsigned i=0; i<nodes->size(); i++) {
5139 o->Output(nest_level, false, "array of");
5140
5141 s += nest + "<tr>\n";
5142 s += nest + " <td> array of " + mjsonrpc_schema_to_html_anything((*nodes)[i], nest_level + 1, o) + "</td>\n";
5143 s += nest + "</tr>\n";
5144 }
5145
5146 s += nest + "</table>\n";
5147
5148 return s;
5149}
5150
5151std::string mjsonrpc_schema_to_html_anything(const MJsonNode* schema, int nest_level, NestedOutput* o)
5152{
5153 std::string type;
5154 std::string description;
5155 //bool optional = false;
5156
5157 const MJsonNode* t = schema->FindObjectNode("type");
5158 if (t)
5159 type = t->GetString();
5160 else
5161 type = "any";
5162
5163 const MJsonNode* d = schema->FindObjectNode("description");
5164 if (d)
5165 description = d->GetString();
5166
5167 //const MJsonNode* o = schema->FindObjectNode("optional");
5168 //if (o)
5169 // optional = o->GetBool();
5170
5171 if (type == "object") {
5172 return mjsonrpc_schema_to_html_object(schema, nest_level, o);
5173 } else if (type == "array") {
5174 return mjsonrpc_schema_to_html_array(schema, nest_level, o);
5175 } else {
5176 //if (optional)
5177 // output(nest_level, false, "?");
5178 //else
5179 // output(nest_level, false, "!");
5180 o->Output(nest_level, false, type);
5181 o->Output(nest_level+1, true, description);
5182 if (description.length() > 1) {
5183 return (type + "</td><td>" + description);
5184 } else {
5185 return (type);
5186 }
5187 }
5188}
5189
5190std::string mjsonrpc_schema_to_text(const MJsonNode* schema)
5191{
5192 std::string s;
5193 NestedOutput out;
5194 out.Clear();
5195 mjsonrpc_schema_to_html_anything(schema, 0, &out);
5196 //s += "<pre>\n";
5197 //s += nested_dump();
5198 //s += "</pre>\n";
5199 s += out.Print();
5200 return s;
5201}
5202
5203static void add(std::string* s, const char* text)
5204{
5205 assert(s != NULL);
5206 if (s->length() > 0)
5207 *s += ", ";
5208 *s += text;
5209}
5210
5211static MJsonNode* mjsonrpc_handle_request(const MJsonNode* request)
5212{
5213 // find required request elements
5214 const MJsonNode* version = request->FindObjectNode("jsonrpc");
5215 const MJsonNode* method = request->FindObjectNode("method");
5216 const MJsonNode* params = request->FindObjectNode("params");
5217 const MJsonNode* id = request->FindObjectNode("id");
5218
5219 std::string bad = "";
5220
5221 if (!version)
5222 add(&bad, "jsonrpc version is missing");
5223 if (!method)
5224 add(&bad, "method is missing");
5225 if (!params)
5226 add(&bad, "params is missing");
5227 if (!id)
5228 add(&bad, "id is missing");
5229
5230 if (version && (version->GetType() != MJSON_STRING))
5231 add(&bad, "jsonrpc version is not a string");
5232 if (version && (version->GetString() != "2.0"))
5233 add(&bad, "jsonrpc version is not 2.0");
5234
5235 if (method && (method->GetType() != MJSON_STRING))
5236 add(&bad, "method is not a string");
5237
5238 if (!method || bad.length() > 0) {
5239 MJsonNode* response = mjsonrpc_make_error(-32600, "Invalid request", bad.c_str());
5240 response->AddToObject("jsonrpc", MJsonNode::MakeString("2.0"));
5241 if (id) {
5242 response->AddToObject("id", id->Copy());
5243 } else {
5244 response->AddToObject("id", MJsonNode::MakeNull());
5245 }
5246
5247 if (mjsonrpc_debug) {
5248 printf("mjsonrpc: invalid request: reply:\n");
5249 printf("%s\n", response->Stringify().c_str());
5250 printf("\n");
5251 }
5252
5253 return response;
5254 }
5255
5256 double start_time = 0;
5257
5258 if (mjsonrpc_time) {
5259 start_time = GetTimeSec();
5260 }
5261
5262 const std::string ms = method->GetString();
5263 const char* m = ms.c_str();
5264
5265 MJsonNode* result = NULL;
5266
5267 // special built-in methods
5268
5269 if (strcmp(m, "echo") == 0) {
5270 result = mjsonrpc_make_result(request->Copy());
5271 } else if (strcmp(m, "error") == 0) {
5272 result = mjsonrpc_make_error(1, "test error", "test error");
5273 } else if (strcmp(m, "invalid_json") == 0) {
5274 if (mjsonrpc_debug) {
5275 printf("mjsonrpc: reply with invalid json\n");
5276 }
5277 return MJsonNode::MakeJSON("this is invalid json data");
5278 } else if (strcmp(m, "test_nan_inf") == 0) {
5279 double one = 1;
5280 double zero = 0;
5281 double nan = zero/zero;
5282 double plusinf = one/zero;
5283 double minusinf = -one/zero;
5284 MJsonNode* n = MJsonNode::MakeArray();
5285 n->AddToArray(MJsonNode::MakeNumber(nan));
5286 n->AddToArray(MJsonNode::MakeNumber(plusinf));
5287 n->AddToArray(MJsonNode::MakeNumber(minusinf));
5288 result = mjsonrpc_make_result("test_nan_plusinf_minusinf", n);
5289 } else if (strcmp(m, "test_arraybuffer") == 0) {
5290 if (mjsonrpc_debug) {
5291 printf("mjsonrpc: reply with test arraybuffer data\n");
5292 }
5293 size_t size = 32;
5294 char* ptr = (char*)malloc(size);
5295 assert(ptr != NULL);
5296 for (size_t i=0; i<size; i++) {
5297 ptr[i] = 'A' + i;
5298 }
5299 *((short*)(ptr+4*2*1)) = 111; // int16[4]
5300 *((int*)(ptr+4*2*2)) = 1234; // int32[4]
5301 *((double*)(ptr+4*2*3)) = 3.14; // float64[3]
5302 return MJsonNode::MakeArrayBuffer(ptr, size);
5303 } else {
5305 if (s != gMethodsTable.end()) {
5306 bool lock = s->second.fNeedsLocking;
5307 if (lock && gMutex)
5308 gMutex->lock();
5309 result = s->second.fHandler(params);
5310 if (lock && gMutex)
5311 gMutex->unlock();
5312 } else {
5313 result = mjsonrpc_make_error(-32601, "Method not found", (std::string("unknown method: ") + ms).c_str());
5314 }
5315 }
5316
5317 if (mjsonrpc_debug) {
5318 printf("mjsonrpc: handler reply:\n");
5319 result->Dump();
5320 printf("\n");
5321 }
5322
5323 double end_time = 0;
5324 double elapsed_time = 0;
5325 if (mjsonrpc_time) {
5326 end_time = GetTimeSec();
5327 elapsed_time = end_time - start_time;
5328 if (mjsonrpc_time > 1) {
5329 printf("request took %.3f seconds, method [%s]\n", elapsed_time, m);
5330 }
5331 }
5332
5333 if (result->GetType() == MJSON_ARRAYBUFFER) {
5334 return result;
5335 }
5336
5337 const MJsonNode *nerror = result->FindObjectNode("error");
5338 const MJsonNode *nresult = result->FindObjectNode("result");
5339
5340 if (nerror) {
5341 result->DeleteObjectNode("result");
5342 } else if (nresult) {
5343 result->DeleteObjectNode("error");
5344 } else {
5345 delete result;
5346 result = mjsonrpc_make_error(-32603, "Internal error", "bad dispatcher reply: no result and no error");
5347 }
5348
5349 result->AddToObject("jsonrpc", MJsonNode::MakeString("2.0"));
5350
5351 if (id) {
5352 result->AddToObject("id", id->Copy());
5353 } else {
5354 result->AddToObject("id", MJsonNode::MakeNull());
5355 }
5356
5357 if (mjsonrpc_time) {
5358 result->AddToObject("elapsed_time", MJsonNode::MakeNumber(elapsed_time));
5359 }
5360
5361 assert(result != NULL);
5362
5363 return result;
5364}
5365
5366MJsonNode* mjsonrpc_decode_post_data(const char* post_data)
5367{
5368 //printf("mjsonrpc call, data [%s]\n", post_data);
5369 MJsonNode *request = MJsonNode::Parse(post_data);
5370
5371 assert(request != NULL); // Parse never returns NULL - either parsed data or an MJSON_ERROR node
5372
5373 if (mjsonrpc_debug) {
5374 printf("mjsonrpc: request:\n");
5375 request->Dump();
5376 printf("\n");
5377 }
5378
5379 if (mjsonrpc_sleep) {
5380 if (mjsonrpc_debug) {
5381 printf("mjsonrpc: sleep %d\n", mjsonrpc_sleep);
5382 }
5383 for (int i=0; i<mjsonrpc_sleep; i++) {
5384 sleep(1);
5385 }
5386 }
5387
5388 if (request->GetType() == MJSON_ERROR) {
5389 MJsonNode* reply = mjsonrpc_make_error(-32700, "Parse error", request->GetError().c_str());
5390 reply->AddToObject("jsonrpc", MJsonNode::MakeString("2.0"));
5391 reply->AddToObject("id", MJsonNode::MakeNull());
5392
5393 if (mjsonrpc_debug) {
5394 printf("mjsonrpc: invalid json: reply:\n");
5395 printf("%s\n", reply->Stringify().c_str());
5396 printf("\n");
5397 }
5398
5399 delete request;
5400 return reply;
5401 } else if (request->GetType() == MJSON_OBJECT) {
5402 MJsonNode* reply = mjsonrpc_handle_request(request);
5403 delete request;
5404 return reply;
5405 } else if (request->GetType() == MJSON_ARRAY) {
5406 const MJsonNodeVector* a = request->GetArray();
5407
5408 if (a->size() < 1) {
5409 MJsonNode* reply = mjsonrpc_make_error(-32600, "Invalid request", "batch request array has less than 1 element");
5410 reply->AddToObject("jsonrpc", MJsonNode::MakeString("2.0"));
5411 reply->AddToObject("id", MJsonNode::MakeNull());
5412
5413 if (mjsonrpc_debug) {
5414 printf("mjsonrpc: invalid json: reply:\n");
5415 printf("%s\n", reply->Stringify().c_str());
5416 printf("\n");
5417 }
5418
5419 delete request;
5420 return reply;
5421 }
5422
5423 MJsonNode* reply = MJsonNode::MakeArray();
5424
5425 for (unsigned i=0; i<a->size(); i++) {
5426 MJsonNode* r = mjsonrpc_handle_request(a->at(i));
5427 reply->AddToArray(r);
5428 if (r->GetType() == MJSON_ARRAYBUFFER) {
5429 delete request;
5430 delete reply;
5431 reply = mjsonrpc_make_error(-32600, "Invalid request", "MJSON_ARRAYBUFFER return is not permitted for batch requests");
5432 reply->AddToObject("jsonrpc", MJsonNode::MakeString("2.0"));
5433 reply->AddToObject("id", MJsonNode::MakeNull());
5434 return reply;
5435 }
5436 }
5437
5438 delete request;
5439 return reply;
5440 } else {
5441 MJsonNode* reply = mjsonrpc_make_error(-32600, "Invalid request", "request is not a JSON object or JSON array");
5442 reply->AddToObject("jsonrpc", MJsonNode::MakeString("2.0"));
5443 reply->AddToObject("id", MJsonNode::MakeNull());
5444
5445 if (mjsonrpc_debug) {
5446 printf("mjsonrpc: invalid json: reply:\n");
5447 printf("%s\n", reply->Stringify().c_str());
5448 printf("\n");
5449 }
5450
5451 delete request;
5452 return reply;
5453 }
5454}
5455
5456/* emacs
5457 * Local Variables:
5458 * tab-width: 8
5459 * c-basic-offset: 3
5460 * indent-tabs-mode: nil
5461 * End:
5462 */
#define FALSE
Definition cfortran.h:309
void Add(time_t t, double v)
std::vector< double > fValues
std::vector< double > fTimes
void Add(time_t t, double v)
std::string fValueJson
std::string fTimeJson
virtual int hs_get_events(time_t time_from, std::vector< std::string > *pevents)=0
get list of events that exist(ed) at given time and later (value 0 means "return all events from begi...
virtual int hs_get_tags(const char *event_name, time_t time_from, std::vector< TAG > *ptags)=0
get list of history variables for given event (use event names returned by hs_get_events()) that exis...
char name[NAME_LENGTH]
Definition history.h:111
virtual int hs_read_buffer(time_t start_time, time_t end_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], MidasHistoryBufferInterface *buffer[], int status[])=0
returns HS_SUCCESS
virtual int hs_get_last_written(time_t start_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], time_t last_written[])=0
virtual int hs_clear_cache()=0
clear internal cache, returns HS_SUCCESS
virtual int hs_read_binned(time_t start_time, time_t end_time, int num_bins, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], int *count_bins[], double *mean_bins[], double *rms_bins[], double *min_bins[], double *max_bins[], time_t *bins_first_time[], double *bins_first_value[], time_t *bins_last_time[], double *bins_last_value[], time_t last_time[], double last_value[], int status[])=0
returns HS_SUCCESS
void Output(int nest, bool span, std::string text)
std::vector< NestedLine > fLines
std::string Print()
INT transition(INT run_number, char *error)
Definition consume.cxx:35
INT al_trigger_class(const char *alarm_class, const char *alarm_message, BOOL first)
Definition alarm.cxx:413
BOOL al_evaluate_condition(const char *alarm_name, const char *condition, std::string *pvalue)
Definition alarm.cxx:41
INT al_reset_alarm(const char *alarm_name)
Definition alarm.cxx:525
INT al_trigger_alarm(const char *alarm_name, const char *alarm_message, const char *default_class, const char *cond_str, INT type)
Definition alarm.cxx:283
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6728
INT bm_request_event(HNDLE buffer_handle, short int event_id, short int trigger_mask, INT sampling_type, HNDLE *request_id, EVENT_HANDLER *func)
Definition midas.cxx:8476
INT bm_set_cache_size(INT buffer_handle, size_t read_size, size_t write_size)
Definition midas.cxx:8151
INT bm_match_event(short int event_id, short int trigger_mask, const EVENT_HEADER *pevent)
Definition midas.cxx:6033
INT bm_get_buffer_handle(const char *buffer_name, INT *buffer_handle)
Definition midas.cxx:7086
INT bm_receive_event_alloc(INT buffer_handle, EVENT_HEADER **ppevent, int timeout_msec)
Definition midas.cxx:10870
INT cm_shutdown(const char *name, BOOL bUnique)
Definition midas.cxx:7411
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3027
INT cm_connect_client(const char *client_name, HNDLE *hConn)
Definition midas.cxx:2782
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5304
std::string cm_expand_env(const char *str)
Definition midas.cxx:7721
int cm_exec_script(const char *odb_path_to_script)
Definition midas.cxx:5479
std::string cm_get_path()
Definition midas.cxx:1553
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7531
INT el_search_run(int run, char *return_tag)
Definition elog.cxx:954
INT el_retrieve(char *tag, char *date, int *run, char *author, char *type, char *syst, char *subject, char *text, int *textsize, char *orig_tag, char *reply_tag, char *attachment1, char *attachment2, char *attachment3, char *encoding)
Definition elog.cxx:774
INT el_delete_message(const char *tag)
Definition elog.cxx:1018
#define CM_SUCCESS
Definition midas.h:582
#define BM_ASYNC_RETURN
Definition midas.h:613
#define BM_SUCCESS
Definition midas.h:605
#define BM_CREATED
Definition midas.h:606
#define DB_OUT_OF_RANGE
Definition midas.h:652
#define DB_INVALID_PARAM
Definition midas.h:640
#define DB_SUCCESS
Definition midas.h:632
#define DB_TYPE_MISMATCH
Definition midas.h:646
#define DB_NO_MORE_SUBKEYS
Definition midas.h:647
#define SS_FILE_ERROR
Definition midas.h:670
#define RPC_SUCCESS
Definition midas.h:699
#define HS_SUCCESS
Definition midas.h:728
#define HS_FILE_ERROR
Definition midas.h:729
#define EL_SUCCESS
Definition midas.h:746
unsigned int DWORD
Definition mcstd.h:51
#define SUCCESS
Definition mcstd.h:54
#define TR_RESUME
Definition midas.h:408
#define GET_NONBLOCKING
Definition midas.h:322
#define TR_PAUSE
Definition midas.h:407
#define TID_BOOL
Definition midas.h:340
#define TRIGGER_ALL
Definition midas.h:538
#define TR_START
Definition midas.h:405
#define BM_NO_WAIT
Definition midas.h:366
#define TR_MTHREAD
Definition midas.h:361
#define MT_INFO
Definition midas.h:543
#define TID_STRING
Definition midas.h:346
#define EVENTID_ALL
Definition midas.h:537
#define MERROR
Definition midas.h:559
#define TID_INT
Definition midas.h:338
#define TR_STOP
Definition midas.h:406
#define TID_DWORD
Definition midas.h:336
MJSO * AddArray(const char *name, const char *description)
Definition mjsonrpc.cxx:394
void mjsonrpc_init()
MJsonNode * properties
Definition mjsonrpc.h:61
void D(const char *description)
Definition mjsonrpc.cxx:303
MJsonNode * mjsonrpc_decode_post_data(const char *post_data)
void P(const char *name, int mjson_type, const char *description)
Definition mjsonrpc.cxx:340
MJsonNode * mjsonrpc_make_result(MJsonNode *node)
Definition mjsonrpc.cxx:135
MJSO * AddObject(const char *name, const char *description)
Definition mjsonrpc.cxx:385
static MJSO * MakeArraySchema(const char *description)
Definition mjsonrpc.cxx:243
MJSO * RA(const char *description)
Definition mjsonrpc.cxx:333
void mjsonrpc_exit()
MJSO * Params()
Definition mjsonrpc.cxx:308
MJsonNode *() mjsonrpc_handler_t(const MJsonNode *params)
Definition mjsonrpc.h:18
static MJSO * I()
Definition mjsonrpc.cxx:298
void Add(const char *name, int mjson_type, const char *description)
Definition mjsonrpc.cxx:356
void mjsonrpc_user_init()
void AddToSchema(MJsonNode *s, const char *name)
Definition mjsonrpc.cxx:262
MJsonNode * mjsonrpc_make_error(int code, const char *message, const char *data)
Definition mjsonrpc.cxx:123
MJsonNode * mjsonrpc_get_schema()
MJsonNode * required
Definition mjsonrpc.h:62
int mjsonrpc_debug
Definition mjsonrpc.cxx:112
static MJSO * MakeObjectSchema(const char *description)
Definition mjsonrpc.cxx:230
MJSO * Result()
Definition mjsonrpc.cxx:317
void mjsonrpc_set_std_mutex(void *mutex)
const MJsonNode * mjsonrpc_get_param(const MJsonNode *params, const char *name, MJsonNode **error)
Definition mjsonrpc.cxx:178
MJSO * result
Definition mjsonrpc.h:66
MJsonNode * items
Definition mjsonrpc.h:63
std::string mjsonrpc_schema_to_text(const MJsonNode *schema)
MJSO * params
Definition mjsonrpc.h:65
void mjsonrpc_add_handler(const char *method, mjsonrpc_handler_t *handler, bool needs_locking)
void R(const char *name, int mjson_type, const char *description)
Definition mjsonrpc.cxx:348
MJSO * PA(const char *description)
Definition mjsonrpc.cxx:326
#define MAX_STRING_LENGTH
Definition msystem.h:113
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3437
DWORD ss_millitime()
Definition system.cxx:3465
INT ss_dirlink_find(const char *path, const char *pattern, char **plist)
Definition system.cxx:6950
time_t ss_file_time(const char *path)
Definition system.cxx:7088
double ss_file_size(const char *path)
Definition system.cxx:7050
void ss_tzset()
Definition system.cxx:3427
DWORD ss_time()
Definition system.cxx:3534
double ss_time_sec()
Definition system.cxx:3539
INT ss_sleep(INT millisec)
Definition system.cxx:3700
bool ss_repair_utf8(char *string)
Definition system.cxx:8229
INT ss_system(const char *command)
Definition system.cxx:2188
INT ss_file_find(const char *path, const char *pattern, char **plist)
Definition system.cxx:6791
INT cm_msg1(INT message_type, const char *filename, INT line, const char *facility, const char *routine, const char *format,...)
Definition midas.cxx:989
INT EXPRT cm_msg_facilities(STRING_LIST *list)
Definition midas.cxx:518
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:931
INT cm_msg_retrieve2(const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
Definition midas.cxx:1280
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3285
INT db_find_link(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4293
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5185
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
Definition odb.cxx:6385
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3392
INT db_copy_json_save(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end)
Definition odb.cxx:10496
MJsonNode * db_scl(HNDLE hDB)
Definition odb.cxx:14144
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6043
INT db_copy_json_index(HNDLE hDB, HNDLE hKey, int index, char **buffer, int *buffer_size, int *buffer_end)
Definition odb.cxx:10242
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7239
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5495
INT db_copy_json_ls(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end)
Definition odb.cxx:10442
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
Definition odb.cxx:3999
INT db_copy_json_values(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end, int omit_names, int omit_last_written, time_t omit_old_timestamp, int preserve_case)
Definition odb.cxx:10464
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5028
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4256
MJsonNode * db_sor(HNDLE hDB, const char *root_path)
Definition odb.cxx:14194
INT db_rename_key(HNDLE hDB, HNDLE hKey, const char *name)
Definition odb.cxx:6285
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5357
INT EXPRT db_resize_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int num_values, int max_string_length)
Definition odb.cxx:14058
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7523
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3688
INT EXPRT db_paste_json_node(HNDLE hDB, HNDLE hKeyRoot, int index, const MJsonNode *node)
#define RPC_BRPC
Definition mrpc.h:135
INT rpc_client_call(HNDLE hConn, DWORD routine_id,...)
Definition midas.cxx:13926
#define RPC_JRPC_CXX
Definition mrpc.h:136
#define RPC_JRPC
Definition mrpc.h:134
#define RPC_BRPC_CXX
Definition mrpc.h:137
double get_time()
Definition feslow.cxx:245
#define HS_GET_INACTIVE
Definition history.h:37
#define HS_GET_READER
Definition history.h:35
int hs_read_event_list(std::vector< std::string > *pevents)
int hs_find_reader_channel(HNDLE hDB, HNDLE *hKeyOut, int debug_flag)
int hs_get_history(HNDLE hDB, HNDLE hKey, int flags, int debug_flag, MidasHistoryInterface **mh)
int hs_image_retrieve(std::string image_name, time_t start_time, time_t stop_time, std::vector< time_t > &vtime, std::vector< std::string > &vfilename)
INT channel
HNDLE hKey
INT run_number[2]
Definition mana.cxx:246
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
DWORD last_time
Definition mana.cxx:3070
void * data
Definition mana.cxx:268
INT type
Definition mana.cxx:269
HNDLE hDB
main ODB handle
Definition mana.cxx:207
char description[1000]
Definition mana.cxx:267
BOOL verbose
Definition mana.cxx:255
double count
Definition mdump.cxx:33
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
char content[600000]
Definition melog.cxx:90
char response[10000]
Definition melog.cxx:90
char request[600000]
Definition melog.cxx:90
char buffer_name[NAME_LENGTH]
Definition mevb.cxx:45
static int offset
Definition mgd.cxx:1500
std::string msprintf(const char *format,...)
Definition midas.cxx:419
const char * mname[]
Definition midas.cxx:144
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
DWORD BOOL
Definition midas.h:105
#define DIR_SEPARATOR_STR
Definition midas.h:194
int INT
Definition midas.h:129
#define AT_PERIODIC
Definition midas.h:1444
#define TRUE
Definition midas.h:182
#define AT_EVALUATED
Definition midas.h:1443
std::vector< std::string > STRING_LIST
Definition midas.h:246
#define NAME_LENGTH
Definition midas.h:272
MidasHistoryInterface * mh
#define trigger_mask
#define end
#define message(type, str)
#define sleep(ms)
#define event_id
#define name(x)
Definition midas_macro.h:24
static MJsonNode * js_cm_transition(const MJsonNode *params)
static MJsonNode * set_sleep(const MJsonNode *params)
const MJsonNodeVector * mjsonrpc_get_param_array(const MJsonNode *params, const char *name, MJsonNode **error)
Definition mjsonrpc.cxx:201
static MJsonNode * js_cm_msg1(const MJsonNode *params)
static MJsonNode * get_sleep(const MJsonNode *params)
static MJsonNode * js_al_trigger_class(const MJsonNode *params)
std::map< std::string, MethodsTableEntry > MethodsTable
static MJsonNode * js_el_delete(const MJsonNode *params)
static MJsonNode * js_hs_read_arraybuffer(const MJsonNode *params)
static MJsonNode * js_db_paste(const MJsonNode *params)
Definition mjsonrpc.cxx:915
static MhiMap gHistoryChannels
static MJsonNode * js_ext_save_file(const MJsonNode *params)
static std::string mjsonrpc_schema_to_html_array(const MJsonNode *schema, int nest_level, NestedOutput *o)
static MJsonNode * js_get_timezone(const MJsonNode *params)
static MJsonNode * jrpc_old(const MJsonNode *params)
static MJsonNode * js_ext_list_files(const MJsonNode *params)
static void StashEvent(const std::string buffer_name, int event_id, int trigger_mask, const EVENT_HEADER *pevent)
static int parse_array_index_list(const char *method, const char *path, std::vector< unsigned > *list)
Definition mjsonrpc.cxx:560
static MJsonNode * js_hs_read_binned(const MJsonNode *params)
static MJsonNode * js_ext_read_file(const MJsonNode *params)
static MJsonNode * start_program(const MJsonNode *params)
Definition mjsonrpc.cxx:486
static MJsonNode * js_hs_get_last_written(const MJsonNode *params)
static MJsonNode * jrpc_cxx(const MJsonNode *params)
static MJsonNode * js_bm_receive_event(const MJsonNode *params)
static MJsonNode * js_hs_get_active_events(const MJsonNode *params)
static std::string mjsonrpc_schema_to_html_anything(const MJsonNode *schema, int nest_level, NestedOutput *o)
static MJsonNode * js_db_ls(const MJsonNode *params)
Definition mjsonrpc.cxx:805
static MJsonNode * js_db_sor(const MJsonNode *params)
static std::string remove(const std::string s, char c)
Definition mjsonrpc.cxx:253
static MJsonNode * js_db_copy(const MJsonNode *params)
Definition mjsonrpc.cxx:860
static MJsonNode * js_db_scl(const MJsonNode *params)
static MJsonNode * js_cm_msg_retrieve(const MJsonNode *params)
static void DeleteEventStash()
static MJsonNode * xnull(const MJsonNode *params)
Definition mjsonrpc.cxx:413
static MJsonNode * js_ss_millitime(const MJsonNode *params)
static MJsonNode * js_db_delete(const MJsonNode *params)
static const EVENT_HEADER * CopyEvent(const EVENT_HEADER *pevent)
MethodsTable::iterator MethodsTableIterator
static int mjsonrpc_time
Definition mjsonrpc.cxx:114
static MJsonNode * js_read_binary_file(const MJsonNode *params)
static MJsonNode * js_db_rename(const MJsonNode *params)
static MJsonNode * js_cm_msg_facilities(const MJsonNode *params)
static int mjsonrpc_sleep
Definition mjsonrpc.cxx:113
static MJsonNode * js_db_key(const MJsonNode *params)
static MJsonNode * js_cm_exist(const MJsonNode *params)
Definition mjsonrpc.cxx:432
static MJsonNode * js_db_reorder(const MJsonNode *params)
static MidasHistoryInterface * GetHistory(const char *name)
std::map< std::string, MidasHistoryInterface * > MhiMap
static MJsonNode * js_db_resize_string(const MJsonNode *params)
static MJsonNode * mjsonrpc_handle_request(const MJsonNode *request)
static MJsonNode * js_hs_get_tags(const MJsonNode *params)
static std::string mjsonrpc_schema_to_html_object(const MJsonNode *schema, int nest_level, NestedOutput *o)
static std::mutex * gMutex
static MJsonNode * js_el_retrieve(const MJsonNode *params)
static MJsonNode * get_alarms(const MJsonNode *params)
static MJsonNode * js_el_query(const MJsonNode *params)
static MJsonNode * js_db_link(const MJsonNode *params)
static MJsonNode * exec_script(const MJsonNode *params)
Definition mjsonrpc.cxx:519
static void js_hs_exit()
static MJsonNode * get_schema(const MJsonNode *params)
static std::vector< EventStashEntry * > gEventStash
static std::string indent(int x, const char *p=" ")
static MJsonNode * js_al_reset_alarm(const MJsonNode *params)
static MJsonNode * brpc_cxx(const MJsonNode *params)
static double GetTimeSec()
Definition mjsonrpc.cxx:116
static MJsonNode * set_time(const MJsonNode *params)
static MJsonNode * set_debug(const MJsonNode *params)
static MJsonNode * js_db_resize(const MJsonNode *params)
static MJsonNode * js_hs_get_events(const MJsonNode *params)
static MJsonNode * gNullNode
Definition mjsonrpc.cxx:176
static MJsonNode * js_hs_read(const MJsonNode *params)
static MJsonNode * js_make_subdir(const MJsonNode *params)
static std::mutex gEventStashMutex
static MJsonNode * js_hs_image_retrieve(const MJsonNode *params)
static const EVENT_HEADER * FindEvent(const std::string buffer_name, int event_id, int trigger_mask, int last_event_id, int last_trigger_mask, DWORD last_serial_number, DWORD last_time_stamp)
static MJsonNode * get_debug(const MJsonNode *params)
static MJsonNode * js_cm_shutdown(const MJsonNode *params)
Definition mjsonrpc.cxx:459
static MethodsTable gMethodsTable
static MJsonNode * js_db_get_values(const MJsonNode *params)
Definition mjsonrpc.cxx:640
static MJsonNode * js_al_trigger_alarm(const MJsonNode *params)
static MJsonNode * js_db_create(const MJsonNode *params)
static MJsonNode * mjsonrpc_make_schema(MethodsTable *h)
static MJsonNode * js_hs_read_binned_arraybuffer(const MJsonNode *params)
static MJsonNode * js_hs_get_channels(const MJsonNode *params)
static void MatchEvent(const std::string buffer_name, const EVENT_HEADER *pevent)
static MJsonNode * js_hs_reopen(const MJsonNode *params)
static MJsonNode * brpc_old(const MJsonNode *params)
static FILE * fp
int gettimeofday(struct timeval *tp, void *tzp)
INT rn
Definition mstat.cxx:30
timeval tv
Definition msysmon.cxx:1095
int event_size
Definition msysmon.cxx:527
MUTEX_T * tm
Definition odbedit.cxx:39
INT j
Definition odbhist.cxx:40
DWORD run
Definition odbhist.cxx:39
double value[100]
Definition odbhist.cxx:42
char str[256]
Definition odbhist.cxx:33
INT add
Definition odbhist.cxx:40
DWORD status
Definition odbhist.cxx:39
short int event_id
Definition midas.h:853
DWORD data_size
Definition midas.h:857
DWORD serial_number
Definition midas.h:855
DWORD time_stamp
Definition midas.h:856
short int trigger_mask
Definition midas.h:854
void Print() const
std::string buffer_name
~EventStashEntry()
int event_id
const EVENT_HEADER * pevent
void ReplaceEvent(const EVENT_HEADER *xpevent)
int trigger_mask
Definition midas.h:1027
INT num_values
Definition midas.h:1029
DWORD type
Definition midas.h:1028
WORD notify_count
Definition midas.h:1035
INT total_size
Definition midas.h:1032
WORD access_mode
Definition midas.h:1034
INT last_written
Definition midas.h:1038
char name[NAME_LENGTH]
Definition midas.h:1030
INT item_size
Definition midas.h:1033
bool fNeedsLocking
mjsonrpc_handler_t * fHandler
std::string text
double d
Definition system.cxx:1313
char c
Definition system.cxx:1312
static double e(void)
Definition tinyexpr.c:136
static te_expr * list(state *s)
Definition tinyexpr.c:567