Subversion Repositories HomeAutomation

Rev

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

Rev Author Line No. Line
1608 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 "Console.h"
22
 
23
#include <boost/lexical_cast.hpp>
24
#include <boost/algorithm/string/trim.hpp>
25
#include <boost/algorithm/string/split.hpp>
26
 
27
#include "net/Manager.h"
1625 runge 28
#include "vm/Manager.h"
1647 runge 29
#include "common/common.h"
1608 runge 30
 
31
namespace atom {
32
namespace vm {
33
namespace plugin {
34
 
35
logging::Logger Console::LOG("vm::plugin::Console");
1647 runge 36
net::ClientId Console::current_client_id_;
1608 runge 37
 
1625 runge 38
Console::Console(boost::asio::io_service& io_service, unsigned int port) : Plugin(io_service)
1608 runge 39
{
40
    this->name_ = "console";
1647 runge 41
    Console::current_client_id_ = 0;
1608 runge 42
 
43
    net::Manager::Instance()->ConnectSlots(net::Manager::SignalOnNewState::slot_type(&Console::SlotOnNewState, this, _1, _2, _3).track(this->tracker_),
44
                                           net::Manager::SignalOnNewData::slot_type(&Console::SlotOnNewData, this, _1, _2, _3).track(this->tracker_));
45
 
1657 runge 46
    this->ExportFunction("ConsoleExport_PromptRequest",        Console::Export_PromptRequest);
1647 runge 47
    this->ExportFunction("ConsoleExport_AutoCompleteResponse", Console::Export_AutoCompleteResponse);
1657 runge 48
    this->ExportFunction("ConsoleExport_LogToClient",          Console::Export_LogToClient);
1664 runge 49
    this->ExportFunction("ConsoleExport_DisconnectClient",     Console::Export_DisconnectClient);
1608 runge 50
 
51
    try
52
    {
53
        this->server_id_ = net::Manager::Instance()->StartServer(net::PROTOCOL_TCP, port);
54
        LOG.Info("Started TCP server on port " + boost::lexical_cast<std::string>(port) + ".");
55
        LOG.Debug("Server id is " + boost::lexical_cast<std::string>(this->server_id_) + ".");
56
    }
57
    catch (std::runtime_error& e)
58
    {
59
        LOG.Error(e.what());
60
    }
61
}
62
 
63
Console::~Console()
64
{
65
    net::Manager::Instance()->StopServer(this->server_id_);
66
    this->server_id_ = 0;
67
}
68
 
69
void Console::InitializeDone()
70
{
71
    Plugin::InitializeDone();
1609 runge 72
 
1647 runge 73
    this->ImportFunction("Console_AutocompleteRequest");
1620 runge 74
    this->ImportFunction("Console_PromptResponse");
1647 runge 75
    this->ImportFunction("Console_NewConnection");
1608 runge 76
}
77
 
1647 runge 78
void Console::CallOutput(unsigned int request_id, std::string output)
79
{
80
    std::string packet = "TEXT";
81
    packet += common::PadNumber(output.length() + 1, 4);
82
    packet += output;
83
 
84
    net::Manager::Instance()->SendTo(request_id, packet);
85
}
86
 
1642 runge 87
void Console::SlotOnNewData(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
1608 runge 88
{
89
    if (server_id != this->server_id_)
90
    {
91
        return;
92
    }
93
 
1625 runge 94
    this->io_service_.post(boost::bind(&Console::SlotOnNewDataHandler, this, client_id, server_id, data));
95
}
96
 
97
void Console::SlotOnNewState(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
98
{
99
    if (server_id != this->server_id_)
100
    {
101
        return;
102
    }
103
 
104
    this->io_service_.post(boost::bind(&Console::SlotOnNewStateHandler, this, client_id, server_id, client_state));
105
}
106
 
1642 runge 107
void Console::SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
1625 runge 108
{
1740 runge 109
    v8::Locker lock;
1625 runge 110
    v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
1741 runge 111
    v8::HandleScope handle_scope;
1625 runge 112
 
1647 runge 113
    //LOG.Debug(std::string(__FUNCTION__) + " called!");
1625 runge 114
 
1741 runge 115
    if (data.GetSize() == 0)
116
    {
117
        LOG.Error(std::string(__FUNCTION__) + " got empty data!");
118
        return;
119
    }
120
 
1647 runge 121
    std::string s(data.ToCharString());
1608 runge 122
 
1741 runge 123
    if (s.length() < 8)
124
    {
125
        LOG.Error(std::string(__FUNCTION__) + " got a packet which is to short, less then 8 bytes: \"" + s + "\"");
126
        return;
127
    }
128
 
1647 runge 129
    std::string command = s.substr(0, 4);
1741 runge 130
 
131
    LOG.Debug(std::string(__FUNCTION__) + " parsed command: \"" + command + "\"");
132
 
133
    // TODO: Check cast exception!
1647 runge 134
    unsigned int payload_length = boost::lexical_cast<unsigned int>(s.substr(4, 4));
135
 
1741 runge 136
    LOG.Debug(std::string(__FUNCTION__) + " parsed payload_length: \"" + boost::lexical_cast<std::string>(payload_length) + "\"");
137
 
138
 
1647 runge 139
    Console::current_client_id_ = client_id;
1608 runge 140
 
1647 runge 141
    if (command == "COMP")
1608 runge 142
    {
1647 runge 143
        ArgumentListPointer call_arguments = ArgumentListPointer(new ArgumentList);
1608 runge 144
 
1647 runge 145
        call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(client_id)));
146
        call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(s.substr(8, 4))));
147
        call_arguments->push_back(v8::String::New(s.substr(12).data()));
1608 runge 148
 
1647 runge 149
        if (!this->Call(client_id, "Console_AutocompleteRequest", call_arguments))
1608 runge 150
        {
1647 runge 151
            LOG.Error("Console_AutocompleteRequest failed, we are now in an undefined state!");
1608 runge 152
        }
153
    }
1647 runge 154
    else if (command == "RESP")
1608 runge 155
    {
1741 runge 156
        LOG.Debug(std::string(__FUNCTION__) + " parsed data: \"" + s.substr(8).data() + "\"");
157
 
1608 runge 158
        ArgumentListPointer call_arguments = ArgumentListPointer(new ArgumentList);
159
 
1647 runge 160
        call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(client_id)));
161
        call_arguments->push_back(v8::String::New(s.substr(8).data()));
1608 runge 162
 
1647 runge 163
        if (!this->Call(client_id, "Console_PromptResponse", call_arguments))
1608 runge 164
        {
1647 runge 165
            LOG.Error("Console_PromptResponse failed, we are now in an undefined state!");
1608 runge 166
        }
167
    }
1647 runge 168
    else
1620 runge 169
    {
1647 runge 170
        LOG.Error("Unknown packat received, we are now in an undefined state!");
1620 runge 171
    }
1647 runge 172
 
173
    Console::current_client_id_ = 0;
1608 runge 174
}
175
 
1625 runge 176
void Console::SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
1608 runge 177
{
1740 runge 178
    v8::Locker lock;
1625 runge 179
    v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
1741 runge 180
    v8::HandleScope handle_scope;
1625 runge 181
 
1647 runge 182
    //LOG.Debug(std::string(__FUNCTION__) + " called!");
1608 runge 183
 
184
    if (client_state == net::CLIENT_STATE_DISCONNECTED)
185
    {
186
        LOG.Info("Client " + boost::lexical_cast<std::string>(client_id) + " has disconnected.");
187
    }
188
    else if (client_state == net::CLIENT_STATE_CONNECTED)
189
    {
190
        LOG.Info("Client " + boost::lexical_cast<std::string>(client_id) + " has connected.");
1647 runge 191
 
192
        Console::current_client_id_ = client_id;
193
 
194
        ArgumentListPointer call_arguments = ArgumentListPointer(new ArgumentList);
195
 
196
        call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(client_id)));
197
 
198
        if (!this->Call(client_id, "Console_NewConnection", call_arguments))
199
        {
200
            LOG.Error("Console_NewConnection failed, we are now in an undefined state!");
201
        }
202
 
203
        Console::current_client_id_ = 0;
1608 runge 204
    }
205
    else
206
    {
207
        LOG.Debug("Got state: " + boost::lexical_cast<std::string>((int)client_state));
208
    }
209
}
210
 
1647 runge 211
Value Console::Export_PromptRequest(const v8::Arguments& args)
1608 runge 212
{
1740 runge 213
    v8::Locker lock;
1625 runge 214
    v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
1741 runge 215
    v8::HandleScope handle_scope;
1625 runge 216
 
1648 runge 217
    //LOG.Debug(std::string(__FUNCTION__) + " called!");
1625 runge 218
 
1647 runge 219
    if (args.Length() < 2)
220
    {
221
        LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
1741 runge 222
        return handle_scope.Close(v8::Boolean::New(false));
1647 runge 223
    }
224
 
225
    v8::String::AsciiValue prompt(args[1]);
226
 
227
    std::string packet = "PROM";
228
    packet += common::PadNumber(prompt.length() + 1, 4);
229
    packet += *prompt;
230
 
231
    net::Manager::Instance()->SendTo(args[0]->Uint32Value(), packet);
1741 runge 232
    return handle_scope.Close(v8::Boolean::New(true));
1608 runge 233
}
234
 
1647 runge 235
Value Console::Export_AutoCompleteResponse(const v8::Arguments& args)
1608 runge 236
{
1740 runge 237
    v8::Locker lock;
1625 runge 238
    v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
1741 runge 239
    v8::HandleScope handle_scope;
1625 runge 240
 
1648 runge 241
    //LOG.Debug(std::string(__FUNCTION__) + " called!");
1625 runge 242
 
1647 runge 243
    if (args.Length() < 2)
1608 runge 244
    {
1647 runge 245
        LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
1741 runge 246
        return handle_scope.Close(v8::Boolean::New(false));
1608 runge 247
    }
248
 
1647 runge 249
    v8::String::AsciiValue result(args[1]);
1608 runge 250
 
1647 runge 251
    std::string packet = "COMP";
252
    packet += common::PadNumber(result.length() + 1, 4);
253
    packet += *result;
1608 runge 254
 
1647 runge 255
    net::Manager::Instance()->SendTo(args[0]->Uint32Value(), packet);
1741 runge 256
    return handle_scope.Close(v8::Boolean::New(true));
1657 runge 257
}
258
 
259
Value Console::Export_LogToClient(const v8::Arguments& args)
260
{
1740 runge 261
    v8::Locker lock;
1657 runge 262
    v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
1741 runge 263
    v8::HandleScope handle_scope;
1608 runge 264
 
1657 runge 265
    //LOG.Debug(std::string(__FUNCTION__) + " called!");
266
 
267
    if (args.Length() < 2)
268
    {
269
        LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
1741 runge 270
        return handle_scope.Close(v8::Boolean::New(false));
1657 runge 271
    }
272
 
273
    v8::String::AsciiValue text(args[1]);
274
 
275
    std::string line = *text;
276
 
277
    std::string packet = "TEXT";
278
    packet += common::PadNumber(line.length() + 1, 4);
279
    packet += line;
280
 
281
    net::Manager::Instance()->SendTo(args[0]->Uint32Value(), packet);
1741 runge 282
    return handle_scope.Close(v8::Boolean::New(true));
1608 runge 283
}
284
 
1664 runge 285
Value Console::Export_DisconnectClient(const v8::Arguments& args)
286
{
1740 runge 287
    v8::Locker lock;
1664 runge 288
    v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
1741 runge 289
    v8::HandleScope handle_scope;
1664 runge 290
 
291
    //LOG.Debug(std::string(__FUNCTION__) + " called!");
292
 
293
    if (args.Length() < 1)
294
    {
295
        LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
1741 runge 296
        return handle_scope.Close(v8::Boolean::New(false));
1664 runge 297
    }
298
    net::Manager::Instance()->Disconnect(args[0]->Uint32Value());
1741 runge 299
    return handle_scope.Close(v8::Boolean::New(true));
1664 runge 300
}
301
 
1608 runge 302
}; // namespace plugin
303
}; // namespace vm
304
}; // namespace atom