Subversion Repositories HomeAutomation

Rev

Rev 1604 | Rev 1619 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
1601 runge 1
/*
2
 *
3
 *  Copyright (C) 2010  Mattias Runge
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License along
16
 *  with this program; if not, write to the Free Software Foundation, Inc.,
17
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 */
20
 
21
#include "Manager.h"
22
 
23
#include <fstream>
24
 
25
#include <boost/lexical_cast.hpp>
26
#include <boost/bind.hpp>
27
 
28
namespace atom {
29
namespace vm {
30
 
31
Manager::Pointer Manager::instance_;
32
 
33
Manager::Manager() : LOG("vm::Manager")
34
{
35
}
36
 
37
Manager::~Manager()
38
{
39
    this->io_service_.stop();
40
 
41
    this->plugins_.clear();
42
    this->context_.Dispose();
43
 
44
    for (ImportFunctionList::iterator it = this->functions_.begin(); it != this->functions_.end(); it++)
45
    {
46
        it->second.Dispose();
47
    }
48
}
49
 
50
void Manager::Create()
51
{
52
    Manager::instance_ = Manager::Pointer(new Manager());
53
}
54
 
55
Manager::Pointer Manager::Instance()
56
{
57
    return Manager::instance_;
58
}
59
 
60
void Manager::Delete()
61
{
62
    Manager::instance_.reset();
63
}
64
 
65
void Manager::AddPlugin(Plugin::Pointer plugin)
66
{
1603 runge 67
    this->plugins_.push_back(plugin);
1601 runge 68
}
69
 
70
void Manager::Start(std::string script_path)
71
{
72
    this->script_path_ = script_path;
73
    this->io_service_.post(boost::bind(&Manager::StartHandler, this));
74
}
75
 
1608 runge 76
void Manager::SendResponse(std::string plugin_name, unsigned int request_id, std::string response)
1601 runge 77
{
1608 runge 78
    for (unsigned int n = 0; n < this->plugins_.size(); n++)
79
    {
80
        if (this->plugins_[n]->GetName() == plugin_name)
81
        {
82
            this->plugins_[n]->ExecutionResult(response, request_id);
83
            return;
84
        }
85
    }
1601 runge 86
}
87
 
1608 runge 88
void Manager::Call(std::string plugin_name, unsigned int request_id, std::string name, ArgumentListPointer arguments)
1601 runge 89
{
1608 runge 90
    this->io_service_.post(boost::bind(&Manager::CallHandler, this, plugin_name, request_id, name, arguments));
1601 runge 91
}
92
 
1608 runge 93
void Manager::Execute(std::string plugin_name, unsigned int request_id, std::string code)
1601 runge 94
{
1608 runge 95
    this->io_service_.post(boost::bind(&Manager::ExecuteHandler, this, plugin_name, request_id, code));
96
}
97
 
98
void Manager::CallHandler(std::string plugin_name, unsigned int request_id, std::string name, ArgumentListPointer arguments)
99
{
1601 runge 100
    v8::Context::Scope context_scope(this->context_);
101
    v8::TryCatch try_catch;
102
 
103
    if (this->functions_.find(name) == this->functions_.end())
104
    {
1608 runge 105
        this->SendResponse(plugin_name, request_id, "No such function found, " + name);
1601 runge 106
        return;
107
    }
1604 runge 108
 
1601 runge 109
    Value result = this->functions_[name]->Call(this->context_->Global(), arguments->size(), arguments->data());
110
 
111
    if (result.IsEmpty())
112
    {
1608 runge 113
        this->SendResponse(plugin_name, request_id, this->FormatException(try_catch));
114
        return;
1601 runge 115
    }
1608 runge 116
 
117
    v8::String::AsciiValue response(result->ToString());
118
 
119
    this->SendResponse(plugin_name, request_id, std::string(*response));
1601 runge 120
}
121
 
122
void Manager::StartHandler()
123
{
124
    v8::Handle<v8::ObjectTemplate> raw_template = v8::ObjectTemplate::New();
125
 
1603 runge 126
    for (unsigned int c = 0; c < this->plugins_.size(); c++)
1601 runge 127
    {
1603 runge 128
        ExportFunctionList export_functions = this->plugins_[c]->GetExportFunctions();
1601 runge 129
 
130
        for (ExportFunctionList::iterator it = export_functions.begin(); it != export_functions.end(); it++)
131
        {
132
            raw_template->Set(v8::String::New(it->first.data()), v8::FunctionTemplate::New(it->second));
133
        }
134
    }
135
 
136
    this->context_ = v8::Context::New(NULL, raw_template);
137
 
138
    v8::Context::Scope context_scope(this->context_);
139
 
1603 runge 140
    for (unsigned int c = 0; c < this->plugins_.size(); c++)
1601 runge 141
    {
1608 runge 142
        this->LoadScript("plugin/" + this->plugins_[c]->GetName() + ".js");
1601 runge 143
    }
144
 
145
    this->object_template_ = v8::Persistent<v8::ObjectTemplate>::New(raw_template);
146
 
1603 runge 147
    for (unsigned int c = 0; c < this->plugins_.size(); c++)
1601 runge 148
    {
1603 runge 149
        this->plugins_[c]->InitializeDone();
1601 runge 150
    }
1608 runge 151
 
152
    LOG.Info("VM initialized.");
1601 runge 153
}
154
 
1608 runge 155
bool Manager::ImportFunction(std::string functionname)
1601 runge 156
{
1608 runge 157
    v8::Context::Scope context_scope(this->context_);
158
 
159
    v8::TryCatch try_catch;
160
 
161
    v8::Handle<v8::String> process_name = v8::String::New(functionname.data());
162
    v8::Handle<v8::Value> process_val = this->context_->Global()->Get(process_name);
163
 
164
    if (!process_val->IsFunction())
165
    {
166
        LOG.Error(functionname + " was not found to be a function!");
167
        return false;
168
    }
169
 
170
    v8::Handle<v8::Function> process_fun = v8::Handle<v8::Function>::Cast(process_val);
171
 
172
    this->functions_[functionname] = v8::Persistent<v8::Function>::New(process_fun);
173
 
174
    return true;
175
}
176
 
177
bool Manager::LoadScript(std::string scriptname)
178
{
1601 runge 179
    std::string path = this->script_path_ + scriptname;
180
    std::ifstream file(path.data());
181
 
182
    if (!file.is_open())
183
    {
184
        file.close();
185
        LOG.Warning("Could not load " + scriptname + ".");
186
        return false;
187
    }
188
 
189
    std::string code = "";
190
    std::string line;
191
 
192
    while (!file.eof())
193
    {
194
        std::getline(file, line);
195
 
196
        if (file.eof())
197
        {
198
            break;
199
        }
200
 
201
        code += line + "\n";
202
    }
203
 
1602 runge 204
    code += "\n";
205
 
1601 runge 206
    file.close();
207
 
208
    v8::Context::Scope context_scope(this->context_);
209
 
210
    v8::TryCatch try_catch;
211
 
212
    v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(code.data(), code.length()),
213
                                                        v8::String::New(scriptname.data(), scriptname.length()));
214
 
215
    if (script.IsEmpty())
216
    {
217
        LOG.Error(this->FormatException(try_catch));
1608 runge 218
        return false;
1601 runge 219
    }
220
    else
221
    {
222
        Value result = script->Run();
223
 
224
        if (result.IsEmpty())
225
        {
226
            LOG.Error(this->FormatException(try_catch));
1608 runge 227
            return false;
1601 runge 228
        }
229
    }
230
 
1603 runge 231
    LOG.Info("Loaded " + scriptname + " successfully.");
1601 runge 232
    return true;
233
}
234
 
1608 runge 235
void Manager::ExecuteHandler(std::string plugin_name, unsigned int request_id, std::string code)
236
{
237
    std::string scriptname = "execute_" + plugin_name + ".js";
238
 
239
    v8::Context::Scope context_scope(this->context_);
240
 
241
    v8::TryCatch try_catch;
242
 
243
    v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(code.data(), code.length()),
244
                                                        v8::String::New(scriptname.data(), scriptname.length()));
245
 
246
    if (script.IsEmpty())
247
    {
248
        this->SendResponse(plugin_name, request_id, this->FormatException(try_catch));
249
    }
250
    else
251
    {
252
        Value result = script->Run();
253
 
254
        if (result.IsEmpty())
255
        {
256
            this->SendResponse(plugin_name, request_id, this->FormatException(try_catch));
257
        }
258
        else
259
        {
260
            v8::String::AsciiValue response(result->ToString());
261
 
262
            this->SendResponse(plugin_name, request_id, std::string(*response));
263
        }
264
    }
265
}
266
 
1601 runge 267
std::string Manager::FormatException(v8::TryCatch& try_catch)
268
{
269
    std::string result;
270
 
271
    v8::HandleScope handle_scope;
272
    v8::String::Utf8Value exception(try_catch.Exception());
273
    v8::Handle<v8::Message> message = try_catch.Message();
274
 
275
    if (message.IsEmpty())
276
    {
277
        result = *exception;
278
    }
279
    else
280
    {
281
        v8::String::Utf8Value filename(message->GetScriptResourceName());
282
 
283
        result = std::string(*filename) + ":" + boost::lexical_cast<std::string>(message->GetLineNumber()) + ": " + std::string(*exception);
284
 
285
        /*v8::String::Utf8Value sourceline(message->GetSourceLine());
286
        string strSourceline = *sourceline;
287
 
288
        result += strSourceline + "\n";
289
 
290
        string underline = rpad("", message->GetStartColumn(), ' ');
291
        underline = rpad(underline, message->GetEndColumn(), '^');
292
 
293
        result += underline + "\n";*/
294
    }
295
 
296
    return result;
297
}
298
 
299
}; // namespace vm
300
}; // namespace atom