Subversion Repositories HomeAutomation

Rev

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