6ee363ef4160c08e50b91e30144cc3ed2d757bb6
[profile/ivi/automotive-message-broker.git] / plugins / bluemonkey / bluemonkey.cpp
1 /*
2     Copyright (C) 2012  Intel Corporation
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Lesser General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Lesser General Public License for more details.
13
14     You should have received a copy of the GNU Lesser General Public
15     License along with this library; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19
20 #include "bluemonkey.h"
21 #include "abstractroutingengine.h"
22 #include "debugout.h"
23 #include "irccoms.h"
24
25 #include <QJsonDocument>
26 #include <QScriptEngine>
27 #include <QDateTime>
28 #include <QString>
29 #include <QFile>
30 #include <QTimer>
31
32 Q_SCRIPT_DECLARE_QMETAOBJECT(QTimer, QObject*)
33
34 #define foreach Q_FOREACH
35
36 extern "C" AbstractSinkManager * create(AbstractRoutingEngine* routingengine, map<string, string> config)
37 {
38         return new BluemonkeySinkManager(routingengine, config);
39 }
40
41 QVariant gvariantToQVariant(GVariant *value)
42 {
43         GVariantClass c = g_variant_classify(value);
44         if(c == G_VARIANT_CLASS_BOOLEAN)
45                 return QVariant((bool) g_variant_get_boolean(value));
46
47         else if(c == G_VARIANT_CLASS_BYTE)
48                 return QVariant((char) g_variant_get_byte(value));
49
50         else if(c == G_VARIANT_CLASS_INT16)
51                 return QVariant((int) g_variant_get_int16(value));
52
53         else if(c == G_VARIANT_CLASS_UINT16)
54                 return QVariant((unsigned int) g_variant_get_uint16(value));
55
56         else if(c == G_VARIANT_CLASS_INT32)
57                 return QVariant((int) g_variant_get_int32(value));
58
59         else if(c ==  G_VARIANT_CLASS_UINT32)
60                 return QVariant((unsigned int) g_variant_get_uint32(value));
61
62         else if(c == G_VARIANT_CLASS_INT64)
63                 return QVariant((long long) g_variant_get_int64(value));
64
65         else if(c == G_VARIANT_CLASS_UINT64)
66                 return QVariant((unsigned long long) g_variant_get_uint64(value));
67
68         else if(c == G_VARIANT_CLASS_DOUBLE)
69                 return QVariant(g_variant_get_double(value));
70
71         else if(c == G_VARIANT_CLASS_STRING)
72                 return QVariant(g_variant_get_string(value, NULL));
73
74         else if(c == G_VARIANT_CLASS_ARRAY)
75         {
76                 gsize dictsize = g_variant_n_children(value);
77                 QVariantList list;
78                 for (int i=0;i<dictsize;i++)
79                 {
80                         GVariant *childvariant = g_variant_get_child_value(value,i);
81                         GVariant *innervariant = g_variant_get_variant(childvariant);
82                         list.append(gvariantToQVariant(innervariant));
83                 }
84                 return list;
85         }
86
87         else
88                 return QVariant::Invalid;
89
90 }
91
92 BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config): QObject(0), AbstractSink(e, config), agent(nullptr), engine(nullptr), mSilentMode(false)
93 {
94         irc = new IrcCommunication(config, this);
95
96         reloadEngine();
97
98         auth = new Authenticate(config, this);
99
100         connect(irc, &IrcCommunication::message, [&](QString sender, QString prefix, QString codes ) {
101
102                 if(codes.contains("authenticate"))
103                 {
104
105                         int i = codes.indexOf("authenticate");
106                         QString pin = codes.mid(i+13);
107                         pin = pin.trimmed();
108
109
110                         if(!auth->authorize(prefix, pin))
111                                 irc->respond(sender,"failed");
112                         qDebug()<<sender;
113
114                 }
115                 else if(codes.startsWith("bluemonkey"))
116                 {
117                         if(!auth->isAuthorized(prefix))
118                         {
119                                 if(!mSilentMode)
120                                         irc->respond(sender, "denied");
121                                 return;
122                         }
123
124                         QString bm("bluemonkey");
125
126                         codes = codes.mid(bm.length()+1);
127
128                         QString response = engine->evaluate(codes).toString();
129
130                         if(!mSilentMode || response != "undefined" )
131                                 irc->respond(sender, response);
132                 }
133         });
134
135 }
136
137
138 PropertyList BluemonkeySink::subscriptions()
139 {
140
141 }
142
143 void BluemonkeySink::supportedChanged(PropertyList supportedProperties)
144 {
145         DebugOut()<<"supported changed"<<endl;
146 }
147
148 void BluemonkeySink::propertyChanged(VehicleProperty::Property property, AbstractPropertyType* value, std::string uuid)
149 {
150
151 }
152
153 const string BluemonkeySink::uuid()
154 {
155         return "bluemonkey";
156 }
157
158 QObject *BluemonkeySink::subscribeTo(QString str)
159 {
160         return new Property(str.toStdString(), "", routingEngine, this);
161 }
162
163 QObject *BluemonkeySink::subscribeTo(QString str, QString srcFilter)
164 {
165         return new Property(str.toStdString(), srcFilter, routingEngine, this);
166 }
167
168 QStringList BluemonkeySink::sourcesForProperty(QString property)
169 {
170         std::list<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
171         QStringList strList;
172         for(auto itr = list.begin(); itr != list.end(); itr++)
173         {
174                 strList<<(*itr).c_str();
175         }
176
177         return strList;
178 }
179
180
181 bool BluemonkeySink::authenticate(QString pass)
182 {
183
184 }
185
186 void BluemonkeySink::loadConfig(QString str)
187 {
188         configsToLoad.append(str);
189         QTimer::singleShot(1,this,SLOT(loadConfigPriv()));
190 }
191
192 void BluemonkeySink::loadConfigPriv()
193 {
194         if(!configsToLoad.count()) return;
195
196         QString str = configsToLoad.first();
197         configsToLoad.pop_front();
198
199         QFile file(str);
200         if(!file.open(QIODevice::ReadOnly))
201         {
202                 DebugOut()<<"failed to open config file: "<<str.toStdString()<<endl;
203                 return;
204         }
205
206         QString script = file.readAll();
207
208         file.close();
209
210         DebugOut()<<"evaluating script: "<<script.toStdString();
211
212         QScriptValue val = engine->evaluate(script);
213
214         DebugOut()<<val.toString().toStdString()<<endl;
215 }
216
217 void BluemonkeySink::reloadEngine()
218 {
219         if(engine)
220                 engine->deleteLater();
221
222         engine = new QScriptEngine(this);
223
224         if(agent) delete agent;
225
226         agent = new BluemonkeyAgent(engine);
227
228         engine->setAgent(agent);
229
230         QScriptValue value = engine->newQObject(this);
231         engine->globalObject().setProperty("bluemonkey", value);
232
233         QScriptValue qtimerClass = engine->scriptValueFromQMetaObject<QTimer>();
234         engine->globalObject().setProperty("QTimer", qtimerClass);
235
236         QScriptValue ircValue = engine->newQObject(irc);
237         engine->globalObject().setProperty("irc", ircValue);
238
239         loadConfig(configuration["config"].c_str());
240 }
241
242 void BluemonkeySink::writeProgram(QString program)
243 {
244         QFile file(configuration["customPrograms"].c_str());
245
246         if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
247         {
248                 DebugOut(DebugOut::Error)<<"failed to open file: "<<file.fileName().toStdString()<<endl;
249                 return;
250         }
251
252         file.write(program.toUtf8());
253         file.write("\n");
254
255         file.close();
256 }
257
258 void BluemonkeySink::log(QString str)
259 {
260         DebugOut()<<str.toStdString()<<endl;
261 }
262
263 void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QScriptValue cbFunction)
264 {
265         double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
266         double e = (double)end.toMSecsSinceEpoch() / 1000.0;
267         AsyncRangePropertyRequest request;
268         request.timeBegin = b;
269         request.timeEnd = e;
270
271         PropertyList reqlist;
272
273         foreach(QString prop, properties)
274         {
275                 reqlist.push_back(prop.toStdString());
276         }
277
278         request.properties = reqlist;
279         request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
280         {
281                 if(!reply->success)
282                 {
283                         DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
284                         return;
285                 }
286
287                 if(cbFunction.isFunction())
288                 {
289                         QVariantList list;
290
291                         for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
292                         {
293                                 AbstractPropertyType *val = *itr;
294
295                                 list.append(gvariantToQVariant(val->toVariant()));
296                         }
297
298                         cbFunction.call(QScriptValue(),cbFunction.engine()->newVariant(list));
299
300                 }
301
302                 delete reply;
303         };
304
305         routingEngine->getRangePropertyAsync(request);
306 }
307
308
309 QVariant Property::value()
310 {
311         return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
312 }
313
314 void Property::setValue(QVariant v)
315 {
316         if(v.type() == QVariant::List || v.type() == QVariant::Map)
317         {
318
319                 QJsonDocument doc = QJsonDocument::fromVariant(v);
320
321                 QString json = doc.toJson();
322
323                 mValue->fromString(json.toStdString());
324         }
325         else
326         {
327                 QString tempVal = v.toString();
328                 mValue->fromString(tempVal.toStdString());
329         }
330
331         AsyncSetPropertyRequest request;
332         request.property = mValue->name;
333         request.value = mValue->copy();
334         request.completed = [&](AsyncPropertyReply* reply)
335         {
336                 if(reply->success)
337                 {
338                         propertyChanged(reply->property,reply->value,reply->value->sourceUuid);
339                 }
340                 delete reply;
341         };
342         routingEngine->setProperty(request);
343 }
344
345 void Property::getHistory(QDateTime begin, QDateTime end, QScriptValue cbFunction)
346 {
347         double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
348         double e = (double)end.toMSecsSinceEpoch() / 1000.0;
349         AsyncRangePropertyRequest request;
350         request.timeBegin = b;
351         request.timeEnd = e;
352
353         PropertyList reqlist;
354         reqlist.push_back(mValue->name);
355
356         request.properties = reqlist;
357         request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
358         {
359                 if(!reply->success)
360                 {
361                         DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
362                         return;
363                 }
364
365                 if(cbFunction.isFunction())
366                 {
367                         QVariantList list;
368
369                         for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
370                         {
371                                 AbstractPropertyType *val = *itr;
372
373                                 list.append(gvariantToQVariant(val->toVariant()));
374                         }
375
376                         cbFunction.call(QScriptValue(),cbFunction.engine()->newVariant(list));
377
378                 }
379
380                 delete reply;
381         };
382
383         routingEngine->getRangePropertyAsync(request);
384 }
385
386 Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, QObject *parent)
387         :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid())
388 {
389         setType(prop.c_str());
390 }
391
392 QString Property::type()
393 {
394         return mValue->name.c_str();
395 }
396
397 void Property::setType(QString t)
398 {
399         if(mValue && type() != "")
400                 routingEngine->unsubscribeToProperty(type().toStdString(),this);
401
402         routingEngine->subscribeToProperty(t.toStdString(),this);
403
404         mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
405
406         if(!mValue)
407                 return;
408
409         AsyncPropertyRequest request;
410         request.property = mValue->name;
411         request.completed = [this](AsyncPropertyReply* reply)
412         {
413                 if(reply->success)
414                         propertyChanged(reply->property, reply->value,uuid());
415
416                 delete reply;
417         };
418
419         routingEngine->getPropertyAsync(request);
420 }
421
422 void Property::propertyChanged(VehicleProperty::Property property, AbstractPropertyType *value, string uuid)
423 {
424         if(mValue)
425         {
426                 delete mValue;
427         }
428         mValue = value->copy();
429
430         changed(gvariantToQVariant(mValue->toVariant()));
431 }