01b7375a57605048e782f13dff305977989ca4ef
[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
22 #include <QJsonDocument>
23 #include <QJSEngine>
24 #include <QDateTime>
25 #include <QString>
26 #include <QFile>
27 #include <QTimer>
28 #include <QtQml>
29
30 #include <dlfcn.h>
31
32 #define foreach Q_FOREACH
33
34 typedef void create_bluemonkey_module_t(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &javascript, QObject* parent);
35
36 QString bmJS = (""
37                                 "console = { };"
38                                 "console.log = function(msg)"
39                                 "{"
40                                 "  bluemonkey.log(msg);"
41                                 "}"
42                                 "");
43
44
45 Bluemonkey::Bluemonkey(std::map<std::string, std::string> config, QObject *parent)
46         :QObject(parent), engine(nullptr), configuration(config)
47 {
48         QTimer::singleShot(1,this,SLOT(reloadEngine()));
49 }
50
51 Bluemonkey::~Bluemonkey()
52 {
53         Q_FOREACH(void* module, modules)
54         {
55                 dlclose(module);
56         }
57
58         engine->deleteLater();
59 }
60
61 void Bluemonkey::loadConfig(QString str)
62 {
63         QFile file(str);
64         if(!file.open(QIODevice::ReadOnly))
65         {
66                 qDebug()<< "failed to open config file: "<< str;
67                 return;
68         }
69
70         QString script = file.readAll();
71
72         file.close();
73
74         qDebug() << "evaluating script: "<< script;
75
76         QJSValue val = engine->evaluate(script);
77
78         qDebug()<< val.toString();
79
80         if(val.isError())
81         {
82                 qDebug() <<  val.property("name").toString() <<  endl;
83                 qDebug() <<  val.property("message").toString() <<  endl;
84                 qDebug() <<  str <<  ":" << val.property("lineNumber").toString() <<  endl;
85         }
86 }
87
88 bool Bluemonkey::loadModule(QString path)
89 {
90         void* handle = dlopen(path.toUtf8().data(), RTLD_LAZY);
91
92         if(!handle)
93         {
94                 qDebug() <<  "bluemonkey load module failed: " <<  dlerror() <<  endl;
95                 return false;
96         }
97
98         if(modules.contains(handle))
99                 return false;
100
101         modules.push_back(handle);
102
103         void* c = dlsym(handle, "create");
104
105         if(!c)
106         {
107                 qDebug() <<  "bluemonkey load module failed: " <<  path <<  " " <<  dlerror() <<  endl;
108                 return false;
109         }
110
111         create_bluemonkey_module_t* create = reinterpret_cast<create_bluemonkey_module_t*>(c);
112
113         if(!create)
114         {
115                 qCritical() << "Failed to call create() on module "<< path << ". Check signature.";
116         }
117
118         std::map<std::string, QObject*> exports;
119         QString js;
120         create(configuration, exports, js, nullptr);
121
122         for(auto i : exports)
123         {
124                 QObject* obj = i.second;
125                 loadModule(i.first.c_str(), obj);
126         }
127
128         QJSValue val = engine->evaluate(js);
129
130         qDebug() << "evalutating module js result: " << val.toString();
131
132         if(val.isError())
133         {
134                 qDebug() << "Script: " << js;
135                 qCritical() << "Error in module javascript: " << val.toString();
136         }
137
138         return true;
139 }
140
141 void Bluemonkey::reloadEngine()
142 {
143         if(engine)
144                 engine->deleteLater();
145
146         engine = new QJSEngine();
147
148         QJSValue value = engine->newQObject(this);
149         engine->globalObject().setProperty("bluemonkey", value);
150
151         if(engine->evaluate(bmJS).isError())
152         {
153                 qCritical() << "Failed to load bluemonkey javascript extensions";
154                 return;
155         }
156
157         ready();
158
159         loadConfig(configuration["config"].c_str());
160
161 }
162
163 void Bluemonkey::writeProgram(QString program)
164 {
165
166         QJSEngine temp;
167         QJSValue result = temp.evaluate(program);
168         if(result.isError())
169         {
170                 qDebug()<< "Syntax error in program: "<< result.toString();
171                 return;
172         }
173
174         QFile file(configuration["customPrograms"].c_str());
175
176         if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
177         {
178                 qDebug() <<  "failed to open file: " <<  file.fileName() <<  endl;
179                 return;
180         }
181
182         file.write(program.toUtf8());
183         file.write("\n");
184
185         file.close();
186 }
187
188 void Bluemonkey::log(QJSValue str)
189 {
190         qDebug()<< str.toString();
191 }
192
193 QObject *Bluemonkey::createTimer()
194 {
195         return new QTimer(this);
196 }
197
198 QObject *Bluemonkey::createQObject()
199 {
200         return new QObject(this);
201 }
202
203
204 bool Bluemonkey::loadModule(const QString &name, QObject *module)
205 {
206         if(!engine->globalObject().hasProperty(name))
207         {
208                 QJSValue val = engine->newQObject(module);
209                 engine->globalObject().setProperty(name, val);
210         }
211 }
212
213
214 void Bluemonkey::assertIsTrue(bool isTrue, const QString & msg)
215 {
216         if(!isTrue)
217                 log(msg);
218
219         Q_ASSERT(isTrue);
220 }