Subversion Repositories HomeAutomation

Rev

Rev 1642 | Rev 1649 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 1642 Rev 1647
Line 18... Line 18...
18
 *
18
 *
19
 */
19
 */
20
 
20
 
21
#include <string>
21
#include <string>
22
#include <vector>
22
#include <vector>
-
 
23
#include <iostream>
23
 
24
 
24
#include <signal.h>
25
#include <signal.h>
25
#include <stdio.h>
26
#include <stdio.h>
26
#include <stdlib.h>
27
#include <stdlib.h>
27
#include <pwd.h>
28
#include <pwd.h>
Line 29... Line 30...
29
#include <boost/lexical_cast.hpp>
30
#include <boost/lexical_cast.hpp>
30
#include <boost/thread/mutex.hpp>
31
#include <boost/thread/mutex.hpp>
31
#include <boost/thread/condition.hpp>
32
#include <boost/thread/condition.hpp>
32
#include <boost/thread/locks.hpp>
33
#include <boost/thread/locks.hpp>
33
#include <boost/algorithm/string.hpp>
34
#include <boost/algorithm/string.hpp>
-
 
35
#include <boost/program_options.hpp>
34
 
36
 
35
#include "net/Manager.h"
37
#include "net/Manager.h"
36
#include "net/Subscriber.h"
38
#include "net/Subscriber.h"
37
#include "net/types.h"
39
#include "net/types.h"
38
 
40
 
Line 41... Line 43...
41
#include <readline/readline.h>
43
#include <readline/readline.h>
42
#include <readline/history.h>
44
#include <readline/history.h>
43
 
45
 
44
using namespace atom;
46
using namespace atom;
45
 
47
 
-
 
48
bool finish = false;
-
 
49
common::StringList autocomplete_list;
-
 
50
char* buffer = NULL;
-
 
51
boost::condition on_message_condition;
-
 
52
struct termios original_flags;
-
 
53
std::string history_filename;
46
 
54
 
47
void Handler(int status);
55
void Handler(int status);
48
void CleanUp();
56
void CleanUp();
49
 
57
 
50
char* AutoCompleteGet(const char* text, int state);
58
char* AutoCompleteGet(const char* text, int state);
51
static char** AutoComplete(const char* text, int start, int end);
59
static char** AutoComplete(const char* text, int start, int end);
52
 
60
 
53
common::StringList autocomplete_list;
-
 
54
char* buffer = NULL;
-
 
55
bool waiting_for_autocomplete = false;
-
 
56
boost::condition on_message_condition;
-
 
57
boost::mutex guard_mutex;
-
 
58
std::string prompt;
61
std::string GetCwd()
-
 
62
{
59
int prompt_id = -1;
63
    return std::string(getpwuid(getuid())->pw_dir);
-
 
64
}
60
 
65
 
61
class ConsoleClient : public net::Subscriber
66
class ConsoleClient : public net::Subscriber
62
{
67
{
63
public:
68
public:
64
    typedef boost::shared_ptr<ConsoleClient> Pointer;
69
    typedef boost::shared_ptr<ConsoleClient> Pointer;
65
   
70
   
66
    ConsoleClient(std::string address, unsigned int port)
71
    ConsoleClient(std::string address, unsigned int port)
67
    {
72
    {
68
        this->identifier_ = address + ":" + boost::lexical_cast<std::string>(port);
-
 
69
        this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
73
        this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
70
    }
74
    }
71
   
75
   
72
    virtual ~ConsoleClient()
76
    virtual ~ConsoleClient()
73
    {
77
    {
74
        net::Manager::Instance()->Disconnect(this->client_id_);
78
        net::Manager::Instance()->Disconnect(this->client_id_);
75
 
79
 
76
        this->io_service_.stop();
80
        this->io_service_.stop();
77
    }
81
    }
78
   
82
   
79
    void Send(std::string data)
83
    std::string GetPrompt()
80
    {
84
    {
81
        net::Manager::Instance()->SendTo(this->client_id_, data);
85
        return this->prompt_;
82
    }
86
    }
83
   
87
   
84
    bool IsConnected()
88
    void SendResponse(std::string payload)
85
    {
89
    {
86
        return this->client_id_ != 0;
90
        std::string packet = "RESP";
-
 
91
        packet += common::PadNumber(payload.length() + 1, 4);
87
    }
92
        packet += payload;
88
   
93
       
89
    std::string GetIdentifier()
-
 
90
    {
-
 
91
        return this->identifier_;
94
        net::Manager::Instance()->SendTo(this->client_id_, packet);
92
    }
95
    }
93
   
96
   
-
 
97
    void AutoCompleteRequest(unsigned int arg_index, std::string commandline)
94
private:
98
    {
95
    net::ClientId client_id_;
99
        std::string payload = common::PadNumber(arg_index, 4);
96
    std::string identifier_;
100
        payload += commandline;
97
   
101
       
-
 
102
        std::string packet = "COMP";
-
 
103
        packet += common::PadNumber(payload.length() + 1, 4);
-
 
104
        packet += payload;
98
   
105
       
99
    void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
-
 
100
    {
-
 
101
        if (client_state == net::CLIENT_STATE_CONNECTED)
106
        net::Manager::Instance()->SendTo(this->client_id_, packet);
102
        {
-
 
103
            printf("Connected to Atom Daemon!\n");
-
 
104
        }
107
    }
-
 
108
   
-
 
109
private:
-
 
110
    net::ClientId client_id_;
-
 
111
    std::string prompt_;
-
 
112
   
-
 
113
   
-
 
114
    void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
105
        else
115
    {
-
 
116
        if (client_state != net::CLIENT_STATE_CONNECTED)
106
        {
117
        {
107
            printf("\nDisconnected!\n");
118
            std::cout << "Disconnected from server" << std::endl;
-
 
119
           
108
            this->client_id_ = 0;
120
            this->client_id_ = 0;
-
 
121
            finish = true;
109
           
122
           
110
            kill(getpid(), SIGTERM);
123
            kill(getpid(), SIGTERM);
111
        }
124
        }
112
    }
125
    }
113
   
-
 
114
    void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
-
 
115
    {
-
 
116
        prompt_id = -1;
-
 
117
       
126
   
-
 
127
    void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
-
 
128
    {
118
        std::string s(data.ToCharString());
129
        std::string s(data.ToCharString());
-
 
130
 
-
 
131
        while (s.length() > 0)
119
       
132
        {
-
 
133
            std::string command = s.substr(0, 4);
-
 
134
            unsigned int payload_length = boost::lexical_cast<unsigned int>(s.substr(4, 4));
-
 
135
           
-
 
136
            if (command == "TEXT")
-
 
137
            {
-
 
138
                std::cout << s.substr(8, payload_length - 1) << std::flush;
-
 
139
            }
-
 
140
            else if (command == "PROM")
-
 
141
            {
-
 
142
                this->prompt_ = s.substr(8, payload_length - 1);
-
 
143
                on_message_condition.notify_all();
-
 
144
            }
120
        if (waiting_for_autocomplete)
145
            else if (command == "COMP")
121
        {
146
            {
122
            autocomplete_list.clear();
147
                autocomplete_list.clear();
123
           
148
               
124
            boost::algorithm::trim_if(s, boost::is_any_of("\n"));
149
                if (payload_length > 0)
-
 
150
                {
125
            boost::algorithm::trim_if(s, boost::is_any_of(" "));
151
                    std::string payload = s.substr(8, payload_length - 1);
126
           
152
                   
127
            if (s != "")
153
                    if (payload.length() > 0)
128
            {
154
                    {
129
                boost::algorithm::split(autocomplete_list, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
155
                        boost::algorithm::split(autocomplete_list, payload, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
130
            }
156
                    }
131
        }
157
                }
132
        else
-
 
133
        {
-
 
134
            common::StringList lines;
-
 
135
           
158
               
136
            boost::algorithm::split(lines, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
-
 
137
           
-
 
138
            for (unsigned int n = 0; n < lines.size(); n++)
159
                on_message_condition.notify_all();
139
            {
160
            }
140
                common::StringList parts;
-
 
141
               
-
 
142
                boost::algorithm::split(parts, lines[n], boost::is_any_of(";"), boost::algorithm::token_compress_off);
-
 
143
               
161
            else
144
                if (parts[0].length() == 1 && parts[0] == "P")
-
 
145
                {
-
 
146
                    prompt_id = boost::lexical_cast<unsigned int>(parts[1]);
-
 
147
                   
-
 
148
                    prompt = "";
-
 
149
                   
-
 
150
                    for (unsigned int c = 2; c < parts.size(); c++)
-
 
151
                    {
-
 
152
                        prompt += parts[c] + " ";
-
 
153
                    }
-
 
154
                }
-
 
155
                else
-
 
156
                {
-
 
157
                    boost::algorithm::trim_if(lines[n], boost::is_any_of(" "));
-
 
158
                   
-
 
159
                    if (lines[n] != "")
-
 
160
                    {
162
            {
161
                        printf("%s\n", lines[n].data());
163
                std::cerr << "Unknown data received: " << s << std::endl;
162
                    }
164
                finish = true;
163
                }
-
 
164
            }
-
 
165
        }
-
 
166
         
-
 
167
        on_message_condition.notify_all();
165
                on_message_condition.notify_all();
-
 
166
                break;
-
 
167
            }
-
 
168
           
-
 
169
            if (8 + payload_length >= s.length())
-
 
170
            {
-
 
171
                break;
-
 
172
            }
-
 
173
           
-
 
174
            s = s.substr(8 + payload_length);
-
 
175
        }
168
    }
176
    }
169
};
177
};
170
 
178
 
171
ConsoleClient::Pointer cc;
179
ConsoleClient::Pointer cc;
172
struct termios original_flags;
-
 
173
std::string history_filename;
-
 
-
 
180
 
174
 
181
 
175
int main(int argc, char **argv)
182
int main(int argc, char **argv)
176
{
183
{
-
 
184
    // Signal handlers
177
    signal(SIGTERM, Handler);
185
    signal(SIGTERM, Handler);
178
    signal(SIGINT, Handler);
186
    signal(SIGINT, Handler);
179
    signal(SIGQUIT, Handler);
187
    signal(SIGQUIT, Handler);
180
    signal(SIGABRT, Handler);
188
    signal(SIGABRT, Handler);
181
    signal(SIGPIPE, Handler);
189
    signal(SIGPIPE, Handler);
182
   
190
   
-
 
191
    boost::mutex guard_mutex;
-
 
192
   
-
 
193
    // Setup readline
-
 
194
    history_filename = GetCwd() + "/.atomic_history";
-
 
195
    read_history(history_filename.data());
-
 
196
   
-
 
197
    rl_attempted_completion_function = AutoComplete;
-
 
198
   
-
 
199
    // Save command line state
183
    tcgetattr(fileno(stdin), &original_flags);
200
    tcgetattr(fileno(stdin), &original_flags);
184
       
201
   
-
 
202
    // Parse commandline
185
    printf("Atom Interactive Console, version 1.5.0 starting...\n");
203
    boost::program_options::options_description command_line;
186
    printf("Written by Mattias Runge 2010.\n");
204
    boost::program_options::variables_map variable_map;
-
 
205
   
-
 
206
    command_line.add_options()
187
    printf("Released under GPL version 2.\n");
207
    ("help,h",    "produce help message")
-
 
208
    ("server,s",  boost::program_options::value<std::string>()->default_value("localhost"), "server address")
-
 
209
    ("port,p",    boost::program_options::value<unsigned int>()->default_value(1202), "server port");
188
   
210
   
-
 
211
    try
-
 
212
    {
-
 
213
        boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(command_line).run(), variable_map);
-
 
214
    }
-
 
215
    catch (boost::program_options::unknown_option e)
-
 
216
    {
-
 
217
        std::cerr << e.what() << std::endl;
-
 
218
        std::cout << command_line << std::endl;
-
 
219
        CleanUp();
-
 
220
        return EXIT_FAILURE;
-
 
221
    }
-
 
222
    catch (boost::program_options::invalid_syntax e)
-
 
223
    {
-
 
224
        std::cerr << e.what() << std::endl;
-
 
225
        std::cout << command_line << std::endl;
189
    net::Manager::Create();
226
        CleanUp();
-
 
227
        return EXIT_FAILURE;
-
 
228
    }
190
   
229
   
-
 
230
    if (variable_map.count("help") != 0)
-
 
231
    {
191
    std::string address = "localhost";
232
        std::cout << command_line << std::endl;
-
 
233
        CleanUp();
192
    unsigned int port = 1202;
234
        return EXIT_SUCCESS;
-
 
235
    }
-
 
236
   
-
 
237
   
-
 
238
    std::cout << "Atom Interactive Console, version 1.5.0 starting..." << std::endl;
-
 
239
    std::cout << "Written by Mattias Runge 2010." << std::endl;
-
 
240
    std::cout << "Released under GPL version 2." << std::endl;
-
 
241
   
-
 
242
    net::Manager::Create();
193
   
243
       
194
    printf("Connecting to %s:%d...", address.data(), port);
244
    std::cout << "Connecting to " << variable_map["server"].as<std::string>().data() << ":" << variable_map["port"].as<unsigned int>() << "..." << std::endl;
195
   
245
   
196
    try
246
    try
197
    {
247
    {
198
        cc = ConsoleClient::Pointer(new ConsoleClient(address, port));
248
        cc = ConsoleClient::Pointer(new ConsoleClient(variable_map["server"].as<std::string>(), variable_map["port"].as<unsigned int>()));
199
    }
249
    }
200
    catch (std::runtime_error& e)
250
    catch (std::runtime_error& e)
201
    {
251
    {
-
 
252
        std::cout << "error!" << std::endl;
202
        printf("%s\n", e.what());
253
        std::cerr << e.what() << std::endl;
203
        CleanUp();
254
        CleanUp();
204
       
-
 
205
        return EXIT_FAILURE;
255
        return EXIT_FAILURE;
206
    }
256
    }
207
   
257
   
208
    printf("success!\n");
258
    while (true)
209
   
259
    {
210
    prompt = cc->GetIdentifier() + "] ";
260
        boost::mutex::scoped_lock guard(guard_mutex);
211
   
-
 
212
    passwd* user_struct = getpwuid(getuid());
261
        on_message_condition.wait(guard);
213
   
262
       
214
    history_filename = std::string(user_struct->pw_dir) + "/.atomic_history";
263
        if (finish)
215
   
264
        {
216
    read_history(history_filename.data());
265
            break;
217
   
266
        }
218
    rl_attempted_completion_function = AutoComplete;
-
 
219
   
267
       
220
    while ((buffer = readline(prompt.data())) != NULL)
268
        while ((buffer = readline(cc->GetPrompt().data())) != NULL)
221
    {
269
        {
222
        if (strlen(buffer) == 0)
270
            if (strlen(buffer) == 0)
223
        {
271
            {
224
            continue;
272
                continue;
225
        }
273
            }
226
       
-
 
227
        if (strcmp(buffer, "quit") == 0)
-
 
228
        {
274
           
229
            break;
275
            break;
230
        }
276
        }
231
       
277
       
232
        waiting_for_autocomplete = false;
-
 
233
        prompt = cc->GetIdentifier() + "] ";
-
 
234
       
-
 
235
        if (prompt_id == -1)
-
 
236
        {
-
 
237
            cc->Send("E;" + std::string(buffer));
278
        cc->SendResponse(buffer);
238
            add_history(buffer);
279
        add_history(buffer);
239
        }
-
 
240
        else
-
 
241
        {
-
 
242
            cc->Send("R;" + boost::lexical_cast<std::string>(prompt_id) + ";" + std::string(buffer));
-
 
243
            prompt_id = -1;
-
 
244
        }
-
 
245
       
-
 
246
        boost::mutex::scoped_lock guard(guard_mutex);
-
 
247
        on_message_condition.wait(guard);    
-
 
248
    }
280
    }
249
   
281
   
250
    CleanUp();
282
    CleanUp();
251
   
283
   
252
    return EXIT_SUCCESS;
284
    return EXIT_SUCCESS;
253
}
285
}
254
 
286
 
255
static char** AutoComplete(const char* text, int start, int end)
287
static char** AutoComplete(const char* text, int start, int end)
256
{
288
{
257
    unsigned int count = 0;
289
    unsigned int count = 0;
258
   
-
 
259
    //printf("\nAutoComplete:start=%d, end=%d\n", start, end);
290
    boost::mutex guard_mutex;
260
   
291
 
261
    for (unsigned int n = 0; n < start; n++)
292
    for (unsigned int n = 0; n < start; n++)
262
    {
293
    {
263
        if (rl_line_buffer[n] == ' ')
294
        if (rl_line_buffer[n] == ' ')
264
        {
295
        {
265
            count++;
296
            count++;
266
        }
297
        }
267
    }
298
    }
268
   
299
   
269
    waiting_for_autocomplete = true;
-
 
270
   
-
 
271
 
-
 
272
    std::string request = "A;"+ boost::lexical_cast<std::string>(count) + ";" + std::string(rl_line_buffer);
-
 
273
    //printf("\nSending request:%s\n", request.data());
300
    cc->AutoCompleteRequest(count, rl_line_buffer);
274
   
-
 
275
    cc->Send(request);
-
 
276
   
301
   
277
    boost::mutex::scoped_lock guard(guard_mutex);
302
    boost::mutex::scoped_lock guard(guard_mutex);
278
    on_message_condition.wait(guard);    
303
    on_message_condition.wait(guard);
279
   
304
   
280
    if (autocomplete_list.size() == 0)
305
    /*if (autocomplete_list.size() == 0)
281
    {
306
    {
282
        return NULL;
307
        return NULL;
283
    }
308
    }*/
284
   
-
 
285
    //printf("processing response\n");
-
 
286
   
309
   
287
    return rl_completion_matches(text, &AutoCompleteGet);
310
    return rl_completion_matches(text, &AutoCompleteGet);
288
}
311
}
289
 
312
 
290
char* AutoCompleteGet(const char* text, int state)
313
char* AutoCompleteGet(const char* text, int state)
291
{
314
{
292
    static int index = 0;
315
    static int index = 0;
293
    int length = strlen(text);
316
    int length = strlen(text);
294
    std::string name;
317
    std::string name;
295
   
-
 
296
    //printf("run, %s, %d, %d\n", text, state, autocomplete_list.size());
-
 
297
   
318
   
298
    if (!state) // First run
319
    if (!state) // First run
299
    {
320
    {
300
        index = 0;
321
        index = 0;
301
    }
322
    }
302
   
323
   
303
    while (autocomplete_list.size() > index)
324
    while (autocomplete_list.size() > index)
304
    {
325
    {
305
        name = autocomplete_list[index];
326
        name = autocomplete_list[index];
306
        //printf("testing name = %s\n", name.data());
-
 
307
       
327
       
308
        index++;
328
        index++;
309
       
329
       
310
        if (strncmp(name.data(), text, length) == 0)
330
        if (strncmp(name.data(), text, length) == 0)
311
        {
331
        {
Line 319... Line 339...
319
    return NULL;
339
    return NULL;
320
}
340
}
321
 
341
 
322
void CleanUp()
342
void CleanUp()
323
{
343
{
324
    printf("Cleaning up...\n");
344
    std::cout << "Cleaning up..." << std::endl;
325
 
345
 
326
    write_history(history_filename.data());
346
    write_history(history_filename.data());
327
   
347
   
328
    cc.reset();
348
    cc.reset();
329
   
349
   
Line 332... Line 352...
332
    if (buffer != NULL)
352
    if (buffer != NULL)
333
    {
353
    {
334
        free(buffer);
354
        free(buffer);
335
    }
355
    }
336
   
356
   
337
    printf("Thank you for using Atom. Goodbye!\n");
357
    std::cout << "Thank you for using Atom. Goodbye!" << std::endl;
338
   
358
   
339
    tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
359
    tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
340
}
360
}
341
 
361
 
342
void Handler(int status)
362
void Handler(int status)
Line 380... Line 400...
380
   
400
   
381
    if (status != SIGPIPE)
401
    if (status != SIGPIPE)
382
    {
402
    {
383
        CleanUp();
403
        CleanUp();
384
        exit(0);
404
        exit(0);
385
        //on_message_condition.notify_all();
-
 
386
    }
405
    }
387
}
406
}