2 Copyright (C) 2012 Intel Corporation
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.
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.
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
20 #include "bluemonkey.h"
21 #include "abstractroutingengine.h"
22 #include "ambplugin.h"
26 #include <QJsonDocument>
27 #include <QScriptEngine>
33 Q_SCRIPT_DECLARE_QMETAOBJECT(QTimer, QObject*)
35 #define foreach Q_FOREACH
37 extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config)
39 auto plugin = new AmbPlugin<BluemonkeySink>(routingengine, config);
45 QVariant gvariantToQVariant(GVariant *value)
47 GVariantClass c = g_variant_classify(value);
48 if(c == G_VARIANT_CLASS_BOOLEAN)
49 return QVariant((bool) g_variant_get_boolean(value));
51 else if(c == G_VARIANT_CLASS_BYTE)
52 return QVariant((char) g_variant_get_byte(value));
54 else if(c == G_VARIANT_CLASS_INT16)
55 return QVariant((int) g_variant_get_int16(value));
57 else if(c == G_VARIANT_CLASS_UINT16)
58 return QVariant((unsigned int) g_variant_get_uint16(value));
60 else if(c == G_VARIANT_CLASS_INT32)
61 return QVariant((int) g_variant_get_int32(value));
63 else if(c == G_VARIANT_CLASS_UINT32)
64 return QVariant((unsigned int) g_variant_get_uint32(value));
66 else if(c == G_VARIANT_CLASS_INT64)
67 return QVariant((long long) g_variant_get_int64(value));
69 else if(c == G_VARIANT_CLASS_UINT64)
70 return QVariant((unsigned long long) g_variant_get_uint64(value));
72 else if(c == G_VARIANT_CLASS_DOUBLE)
73 return QVariant(g_variant_get_double(value));
75 else if(c == G_VARIANT_CLASS_STRING)
76 return QVariant(g_variant_get_string(value, NULL));
78 else if(c == G_VARIANT_CLASS_ARRAY)
80 gsize dictsize = g_variant_n_children(value);
82 for (int i=0;i<dictsize;i++)
84 GVariant *childvariant = g_variant_get_child_value(value,i);
85 GVariant *innervariant = g_variant_get_variant(childvariant);
86 list.append(gvariantToQVariant(innervariant));
92 return QVariant::Invalid;
96 BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent): QObject(0), AmbPluginImpl(e, config, parent), agent(nullptr), engine(nullptr), mSilentMode(false)
98 irc = new IrcCommunication(config, this);
100 QTimer::singleShot(1,this,SLOT(reloadEngine()));
102 auth = new Authenticate(config, this);
104 connect(irc, &IrcCommunication::message, [&](QString sender, QString prefix, QString codes ) {
106 if(codes.startsWith("authenticate"))
109 int i = codes.indexOf("authenticate");
110 QString pin = codes.mid(i+13);
114 if(!auth->authorize(prefix, pin))
115 irc->respond(sender,"failed");
119 else if(codes.startsWith("bluemonkey"))
121 if(!auth->isAuthorized(prefix))
124 irc->respond(sender, "denied");
128 QString bm("bluemonkey");
130 codes = codes.mid(bm.length()+1);
132 QString response = engine->evaluate(codes).toString();
134 if(!mSilentMode || response != "undefined" )
135 irc->respond(sender, response);
142 PropertyList BluemonkeySink::subscriptions()
147 void BluemonkeySink::supportedChanged(const PropertyList & supportedProperties)
149 DebugOut()<<"supported changed"<<endl;
152 void BluemonkeySink::propertyChanged(AbstractPropertyType * value)
157 const string BluemonkeySink::uuid() const
162 int BluemonkeySink::supportedOperations()
164 return AbstractSource::Get | AbstractSource::Set;
167 QObject *BluemonkeySink::subscribeTo(QString str)
169 return new Property(str.toStdString(), "", routingEngine, this);
172 QObject *BluemonkeySink::subscribeTo(QString str, QString srcFilter)
174 return new Property(str.toStdString(), srcFilter, routingEngine, this);
177 QStringList BluemonkeySink::sourcesForProperty(QString property)
179 std::list<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
181 for(auto itr = list.begin(); itr != list.end(); itr++)
183 strList<<(*itr).c_str();
189 QStringList BluemonkeySink::supportedProperties()
191 PropertyList props = routingEngine->supported();
202 bool BluemonkeySink::authenticate(QString pass)
207 void BluemonkeySink::loadConfig(QString str)
210 if(!file.open(QIODevice::ReadOnly))
212 DebugOut()<<"failed to open config file: "<<str.toStdString()<<endl;
216 QString script = file.readAll();
220 DebugOut()<<"evaluating script: "<<script.toStdString()<<endl;
222 QScriptValue val = engine->evaluate(script);
224 DebugOut()<<val.toString().toStdString()<<endl;
227 void BluemonkeySink::reloadEngine()
230 engine->deleteLater();
232 engine = new QScriptEngine(this);
234 if(agent) delete agent;
236 agent = new BluemonkeyAgent(engine);
238 //engine->setAgent(agent);
240 QScriptValue value = engine->newQObject(this);
241 engine->globalObject().setProperty("bluemonkey", value);
243 QScriptValue qtimerClass = engine->scriptValueFromQMetaObject<QTimer>();
244 engine->globalObject().setProperty("QTimer", qtimerClass);
246 QScriptValue ircValue = engine->newQObject(irc);
247 engine->globalObject().setProperty("irc", ircValue);
249 loadConfig(configuration["config"].c_str());
252 void BluemonkeySink::writeProgram(QString program)
254 QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(program);
255 if(result.state() != QScriptSyntaxCheckResult::Valid)
257 DebugOut(DebugOut::Error)<<"Syntax error in program: "<<result.errorMessage().toStdString()<<endl;
261 QFile file(configuration["customPrograms"].c_str());
263 if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
265 DebugOut(DebugOut::Error)<<"failed to open file: "<<file.fileName().toStdString()<<endl;
269 file.write(program.toUtf8());
275 void BluemonkeySink::log(QString str)
277 DebugOut()<<str.toStdString()<<endl;
280 void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QScriptValue cbFunction)
282 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
283 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
284 AsyncRangePropertyRequest request;
285 request.timeBegin = b;
288 PropertyList reqlist;
290 foreach(QString prop, properties)
292 reqlist.push_back(prop.toStdString());
295 request.properties = reqlist;
296 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
300 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
304 if(cbFunction.isFunction())
308 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
310 AbstractPropertyType *val = *itr;
312 list.append(gvariantToQVariant(val->toVariant()));
315 cbFunction.call(QScriptValue(),cbFunction.engine()->newVariant(list));
322 routingEngine->getRangePropertyAsync(request);
325 void BluemonkeySink::createCustomProperty(QString name, QScriptValue defaultValue)
328 auto create = [defaultValue, name]() -> AbstractPropertyType*
330 QVariant var = defaultValue.toVariant();
335 if(var.type() == QVariant::UInt)
336 return new BasicPropertyType<uint>(name.toStdString(), var.toUInt());
337 else if(var.type() == QVariant::Double)
338 return new BasicPropertyType<double>(name.toStdString(), var.toDouble());
339 else if(var.type() == QVariant::Bool)
340 return new BasicPropertyType<bool>(name.toStdString(), var.toBool());
341 else if(var.type() == QVariant::Int)
342 return new BasicPropertyType<int>(name.toStdString(), var.toInt());
343 else if(var.type() == QVariant::String)
344 return new StringPropertyType(name.toStdString(), var.toString().toStdString());
350 addPropertySupport(Zone::None, create);
352 routingEngine->updateSupported(supported(), PropertyList(), &source);
356 QVariant Property::value()
358 return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
361 void Property::setValue(QVariant v)
363 if(v.type() == QVariant::List || v.type() == QVariant::Map)
366 QJsonDocument doc = QJsonDocument::fromVariant(v);
368 QString json = doc.toJson();
370 mValue->fromString(json.toStdString());
374 QString tempVal = v.toString();
375 mValue->fromString(tempVal.toStdString());
378 AsyncSetPropertyRequest request;
379 request.property = mValue->name;
380 request.value = mValue->copy();
381 request.completed = [&](AsyncPropertyReply* reply)
385 propertyChanged(reply->value);
389 routingEngine->setProperty(request);
392 void Property::getHistory(QDateTime begin, QDateTime end, QScriptValue cbFunction)
394 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
395 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
396 AsyncRangePropertyRequest request;
397 request.timeBegin = b;
400 PropertyList reqlist;
401 reqlist.push_back(mValue->name);
403 request.properties = reqlist;
404 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
408 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
412 if(cbFunction.isFunction())
416 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
418 AbstractPropertyType *val = *itr;
420 list.append(gvariantToQVariant(val->toVariant()));
423 cbFunction.call(QScriptValue(),cbFunction.engine()->newVariant(list));
430 routingEngine->getRangePropertyAsync(request);
433 Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, QObject *parent)
434 :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid())
436 setType(prop.c_str());
439 QString Property::type()
441 return mValue->name.c_str();
444 void Property::setType(QString t)
446 if(mValue && type() != "")
447 routingEngine->unsubscribeToProperty(type().toStdString(), this);
449 routingEngine->subscribeToProperty(t.toStdString(), this);
451 mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
456 AsyncPropertyRequest request;
457 request.property = mValue->name;
458 request.completed = [this](AsyncPropertyReply* reply)
461 propertyChanged(reply->value);
466 routingEngine->getPropertyAsync(request);
469 void Property::propertyChanged(AbstractPropertyType *value)
475 mValue = value->copy();
477 changed(gvariantToQVariant(mValue->toVariant()));