Subversion Repositories HomeAutomation

Rev

Rev 1608 | Rev 1620 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 1608 Rev 1609
1
/*
1
/*
2
 *
2
 *
3
 *  Copyright (C) 2010  Mattias Runge
3
 *  Copyright (C) 2010  Mattias Runge
4
 *
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
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
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
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
8
 *  (at your option) any later version.
9
 *
9
 *
10
 *  This program is distributed in the hope that it will be useful,
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
13
 *  GNU General Public License for more details.
14
 *
14
 *
15
 *  You should have received a copy of the GNU General Public License along
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.,
16
 *  with this program; if not, write to the Free Software Foundation, Inc.,
17
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
18
 *
19
 */
19
 */
20
 
20
 
21
#include <string>
21
#include <string>
22
#include <vector>
22
#include <vector>
23
 
23
 
24
#include <signal.h>
24
#include <signal.h>
25
#include <stdio.h>
25
#include <stdio.h>
26
#include <stdlib.h>
26
#include <stdlib.h>
-
 
27
#include <pwd.h>
27
 
28
 
28
#include <boost/lexical_cast.hpp>
29
#include <boost/lexical_cast.hpp>
29
#include <boost/thread/mutex.hpp>
30
#include <boost/thread/mutex.hpp>
30
#include <boost/thread/condition.hpp>
31
#include <boost/thread/condition.hpp>
31
#include <boost/thread/locks.hpp>
32
#include <boost/thread/locks.hpp>
32
#include <boost/algorithm/string.hpp>
33
#include <boost/algorithm/string.hpp>
33
 
34
 
34
#include "net/Manager.h"
35
#include "net/Manager.h"
35
#include "net/Subscriber.h"
36
#include "net/Subscriber.h"
36
#include "net/types.h"
37
#include "net/types.h"
37
 
38
 
38
#include "type/common.h"
39
#include "type/common.h"
39
 
40
 
40
#include <readline/readline.h>
41
#include <readline/readline.h>
41
#include <readline/history.h>
42
#include <readline/history.h>
42
 
43
 
43
using namespace atom;
44
using namespace atom;
44
 
45
 
45
 
46
 
46
void Handler(int status);
47
void Handler(int status);
47
void CleanUp();
48
void CleanUp();
48
 
49
 
49
char* AutoCompleteGet(const char* text, int state);
50
char* AutoCompleteGet(const char* text, int state);
50
static char** AutoComplete(const char* text, int start, int end);
51
static char** AutoComplete(const char* text, int start, int end);
51
 
52
 
52
type::StringList autocomplete_list;
53
type::StringList autocomplete_list;
53
char* buffer = NULL;
54
char* buffer = NULL;
54
bool waiting_for_autocomplete = false;
55
bool waiting_for_autocomplete = false;
55
boost::condition on_message_condition;
56
boost::condition on_message_condition;
56
boost::mutex guard_mutex;
57
boost::mutex guard_mutex;
57
 
58
 
58
class ConsoleClient : public net::Subscriber
59
class ConsoleClient : public net::Subscriber
59
{
60
{
60
public:
61
public:
61
    typedef boost::shared_ptr<ConsoleClient> Pointer;
62
    typedef boost::shared_ptr<ConsoleClient> Pointer;
62
   
63
   
63
    ConsoleClient(std::string address, unsigned int port)
64
    ConsoleClient(std::string address, unsigned int port)
64
    {
65
    {
65
        this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
66
        this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
66
    }
67
    }
67
   
68
   
68
    virtual ~ConsoleClient()
69
    virtual ~ConsoleClient()
69
    {
70
    {
70
        net::Manager::Instance()->Disconnect(this->client_id_);
71
        net::Manager::Instance()->Disconnect(this->client_id_);
71
 
72
 
72
        this->io_service_.stop();
73
        this->io_service_.stop();
73
    }
74
    }
74
   
75
   
75
    void Send(std::string data)
76
    void Send(std::string data)
76
    {
77
    {
77
        net::Manager::Instance()->SendTo(this->client_id_, data);
78
        net::Manager::Instance()->SendTo(this->client_id_, data);
78
    }
79
    }
79
   
80
   
80
    bool IsConnected()
81
    bool IsConnected()
81
    {
82
    {
82
        return this->client_id_ != 0;
83
        return this->client_id_ != 0;
83
    }
84
    }
84
   
85
   
85
private:
86
private:
86
    net::ClientId client_id_;
87
    net::ClientId client_id_;
87
   
88
   
88
    void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
89
    void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
89
    {
90
    {
90
        if (client_state == net::CLIENT_STATE_CONNECTED)
91
        if (client_state == net::CLIENT_STATE_CONNECTED)
91
        {
92
        {
92
            printf("Connected to Atom Daemon!\n");
93
            printf("Connected to Atom Daemon!\n");
93
        }
94
        }
94
        else
95
        else
95
        {
96
        {
96
            printf("\nDisconnected!\n");
97
            printf("\nDisconnected!\n");
97
            this->client_id_ = 0;
98
            this->client_id_ = 0;
98
           
99
           
99
            kill(getpid(), SIGABRT);
100
            kill(getpid(), SIGTERM);
100
        }
101
        }
101
    }
102
    }
102
   
103
   
103
    void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, type::Byteset data)
104
    void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, type::Byteset data)
104
    {
105
    {
105
        std::string s(data.ToCharString());
106
        std::string s(data.ToCharString());
106
       
107
       
107
        if (waiting_for_autocomplete)
108
        if (waiting_for_autocomplete)
108
        {
109
        {
109
            autocomplete_list.clear();
110
            autocomplete_list.clear();
-
 
111
           
-
 
112
            boost::algorithm::trim_if(s, boost::is_any_of("\n"));
-
 
113
            boost::algorithm::trim_if(s, boost::is_any_of(" "));
-
 
114
           
-
 
115
            if (s != "")
-
 
116
            {
110
            boost::algorithm::split(autocomplete_list, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
117
                boost::algorithm::split(autocomplete_list, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
-
 
118
            }
111
        }
119
        }
112
        else
120
        else
113
        {
121
        {
114
            if (s[s.length()-1] != '\n')
122
            if (s[s.length()-1] != '\n')
115
            {
123
            {
116
                s += "\n";
124
                s += "\n";
117
            }
125
            }
118
           
126
           
119
            printf("%s", s.data());
127
            printf("%s", s.data());
120
        }
128
        }
121
         
129
         
122
        on_message_condition.notify_all();
130
        on_message_condition.notify_all();
123
    }
131
    }
124
};
132
};
125
 
133
 
126
ConsoleClient::Pointer cc;
134
ConsoleClient::Pointer cc;
127
struct termios original_flags;
135
struct termios original_flags;
-
 
136
std::string history_filename;
128
 
137
 
129
int main(int argc, char **argv)
138
int main(int argc, char **argv)
130
{
139
{
131
    signal(SIGTERM, Handler);
140
    signal(SIGTERM, Handler);
132
    signal(SIGINT, Handler);
141
    signal(SIGINT, Handler);
133
    signal(SIGQUIT, Handler);
142
    signal(SIGQUIT, Handler);
134
    signal(SIGABRT, Handler);
143
    signal(SIGABRT, Handler);
135
    signal(SIGPIPE, Handler);
144
    signal(SIGPIPE, Handler);
136
   
145
   
137
    tcgetattr(fileno(stdin), &original_flags);
146
    tcgetattr(fileno(stdin), &original_flags);
138
       
147
       
139
    printf("Atom Interactive Console, version 1.5.0 starting...\n");
148
    printf("Atom Interactive Console, version 1.5.0 starting...\n");
140
    printf("Written by Mattias Runge 2010.\n");
149
    printf("Written by Mattias Runge 2010.\n");
141
    printf("Released under GPL version 2.\n");
150
    printf("Released under GPL version 2.\n");
142
   
151
   
143
    net::Manager::Create();
152
    net::Manager::Create();
144
   
153
   
145
    std::string address = "localhost";
154
    std::string address = "localhost";
146
    unsigned int port = 1202;
155
    unsigned int port = 1202;
147
   
156
   
148
    printf("Connecting to %s:%d...", address.data(), port);
157
    printf("Connecting to %s:%d...", address.data(), port);
149
   
158
   
150
    try
159
    try
151
    {
160
    {
152
        cc = ConsoleClient::Pointer(new ConsoleClient(address, port));
161
        cc = ConsoleClient::Pointer(new ConsoleClient(address, port));
153
    }
162
    }
154
    catch (std::runtime_error& e)
163
    catch (std::runtime_error& e)
155
    {
164
    {
156
        printf("%s\n", e.what());
165
        printf("%s\n", e.what());
157
        CleanUp();
166
        CleanUp();
158
       
167
       
159
        return EXIT_FAILURE;
168
        return EXIT_FAILURE;
160
    }
169
    }
161
   
170
   
162
    printf("success!\n");
171
    printf("success!\n");
163
   
172
   
164
    std::string prompt = address + ":" + boost::lexical_cast<std::string>(port) + "] ";
173
    std::string prompt = address + ":" + boost::lexical_cast<std::string>(port) + "] ";
165
   
174
   
166
   
175
   
-
 
176
    passwd* user_struct = getpwuid(getuid());
-
 
177
   
-
 
178
    history_filename = std::string(user_struct->pw_dir) + "/.atomic_history";
-
 
179
   
-
 
180
    read_history(history_filename.data());
167
   
181
   
168
    rl_attempted_completion_function = AutoComplete;
182
    rl_attempted_completion_function = AutoComplete;
169
   
183
   
170
    while ((buffer = readline(prompt.data())) != NULL)
184
    while ((buffer = readline(prompt.data())) != NULL)
171
    {
185
    {
172
        if (strlen(buffer) == 0)
186
        if (strlen(buffer) == 0)
173
        {
187
        {
174
            continue;
188
            continue;
175
        }
189
        }
176
       
190
       
177
        if (strcmp(buffer, "quit") == 0)
191
        if (strcmp(buffer, "quit") == 0)
178
        {
192
        {
179
            break;
193
            break;
180
        }
194
        }
181
       
195
       
182
        waiting_for_autocomplete = false;
196
        waiting_for_autocomplete = false;
183
       
197
       
184
        cc->Send("E;" + std::string(buffer));
198
        cc->Send("E;" + std::string(buffer));
185
       
199
       
186
        boost::mutex::scoped_lock guard(guard_mutex);
200
        boost::mutex::scoped_lock guard(guard_mutex);
187
        on_message_condition.wait(guard);    
201
        on_message_condition.wait(guard);    
188
       
202
       
189
        add_history(buffer);
203
        add_history(buffer);
190
    }
204
    }
191
   
205
   
192
    CleanUp();
206
    CleanUp();
193
   
207
   
194
    return EXIT_SUCCESS;
208
    return EXIT_SUCCESS;
195
}
209
}
196
 
210
 
197
static char** AutoComplete(const char* text, int start, int end)
211
static char** AutoComplete(const char* text, int start, int end)
198
{
212
{
199
    unsigned int count = 0;
213
    unsigned int count = 0;
200
   
214
   
-
 
215
    //printf("\nAutoComplete:start=%d, end=%d\n", start, end);
-
 
216
   
201
    for (unsigned int n = 0; n < start; n++)
217
    for (unsigned int n = 0; n < start; n++)
202
    {
218
    {
203
        if (text[n] == ' ')
219
        if (rl_line_buffer[n] == ' ')
204
        {
220
        {
205
            count++;
221
            count++;
206
        }
222
        }
207
    }
223
    }
208
   
-
 
209
    waiting_for_autocomplete = true;
-
 
210
   
224
   
211
    //printf("Sending request\n");
225
    waiting_for_autocomplete = true;
212
   
226
   
-
 
227
 
213
    cc->Send("A;"+ boost::lexical_cast<std::string>(count) + ";" + std::string(text));
228
    std::string request = "A;"+ boost::lexical_cast<std::string>(count) + ";" + std::string(rl_line_buffer);
-
 
229
    //printf("\nSending request:%s\n", request.data());
-
 
230
   
-
 
231
    cc->Send(request);
214
   
232
   
215
    boost::mutex::scoped_lock guard(guard_mutex);
233
    boost::mutex::scoped_lock guard(guard_mutex);
216
    on_message_condition.wait(guard);    
234
    on_message_condition.wait(guard);    
217
   
235
   
-
 
236
    if (autocomplete_list.size() == 0)
-
 
237
    {
-
 
238
        return NULL;
-
 
239
    }
-
 
240
   
218
    //printf("processing response\n");
241
    //printf("processing response\n");
219
   
242
   
220
    return rl_completion_matches(text, &AutoCompleteGet);
243
    return rl_completion_matches(text, &AutoCompleteGet);
221
}
244
}
222
 
245
 
223
char* AutoCompleteGet(const char* text, int state)
246
char* AutoCompleteGet(const char* text, int state)
224
{
247
{
225
    static int index = 0;
248
    static int index = 0;
226
    int length = strlen(text);
249
    int length = strlen(text);
227
    std::string name;
250
    std::string name;
228
   
251
   
229
    //printf("run, %s, %d, %d\n", text, state, autocomplete_list.size());
252
    //printf("run, %s, %d, %d\n", text, state, autocomplete_list.size());
230
   
253
   
231
    if (!state) // First run
254
    if (!state) // First run
232
    {
255
    {
233
        index = 0;
256
        index = 0;
234
    }
257
    }
235
   
258
   
236
    while (autocomplete_list.size() > index)
259
    while (autocomplete_list.size() > index)
237
    {
260
    {
238
        name = autocomplete_list[index];
261
        name = autocomplete_list[index];
239
        //printf("testing name = %s\n", name.data());
262
        //printf("testing name = %s\n", name.data());
240
       
263
       
241
        index++;
264
        index++;
242
       
265
       
243
        if (strncmp(name.data(), text, length) == 0)
266
        if (strncmp(name.data(), text, length) == 0)
244
        {
267
        {
245
            char *result = (char*)malloc(name.size() + 1);
268
            char *result = (char*)malloc(name.size() + 1);
246
            strcpy(result, name.data());
269
            strcpy(result, name.data());
247
           
270
           
248
            return result;
271
            return result;
249
        }
272
        }
250
    }
273
    }
251
   
274
   
252
    return NULL;
275
    return NULL;
253
}
276
}
254
 
277
 
255
void CleanUp()
278
void CleanUp()
256
{
279
{
257
    printf("Cleaning up...\n");
280
    printf("Cleaning up...\n");
-
 
281
 
-
 
282
    write_history(history_filename.data());
258
   
283
   
259
    cc.reset();
284
    cc.reset();
260
   
285
   
261
    net::Manager::Delete();
286
    net::Manager::Delete();
262
   
287
   
263
    if (buffer != NULL)
288
    if (buffer != NULL)
264
    {
289
    {
265
        free(buffer);
290
        free(buffer);
266
    }
291
    }
267
   
292
   
268
    printf("Thank you for using Atom. Goodbye!\n");
293
    printf("Thank you for using Atom. Goodbye!\n");
269
   
294
   
270
    tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
295
    tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
271
}
296
}
272
 
297
 
273
void Handler(int status)
298
void Handler(int status)
274
{
299
{
275
    std::string signal_name = "Unknown";
300
    std::string signal_name = "Unknown";
276
   
301
   
277
    switch (status)
302
    switch (status)
278
    {
303
    {
279
        case SIGTERM:
304
        case SIGTERM:
280
        {
305
        {
281
            signal_name = "Terminate";
306
            signal_name = "Terminate";
282
            break;
307
            break;
283
        }  
308
        }  
284
        case SIGINT:
309
        case SIGINT:
285
        {
310
        {
286
            signal_name = "Interupt";
311
            signal_name = "Interupt";
287
            break;
312
            break;
288
        }  
313
        }  
289
        case SIGQUIT:
314
        case SIGQUIT:
290
        {
315
        {
291
            signal_name = "Quit";
316
            signal_name = "Quit";
292
            break;
317
            break;
293
        }  
318
        }  
294
        case SIGABRT:
319
        case SIGABRT:
295
        {
320
        {
296
            signal_name = "Abort";
321
            signal_name = "Abort";
297
            break;
322
            break;
298
        }  
323
        }  
299
        case SIGIO:
324
        case SIGIO:
300
        {
325
        {
301
            signal_name = "I/O";
326
            signal_name = "I/O";
302
            break;
327
            break;
303
        }  
328
        }  
304
        case SIGPIPE:
329
        case SIGPIPE:
305
        {
330
        {
306
            signal_name = "Pipe";
331
            signal_name = "Pipe";
307
            break;
332
            break;
308
        }
333
        }
309
    }
334
    }
310
   
335
   
311
   
336
   
312
    if (status != SIGPIPE)
337
    if (status != SIGPIPE)
313
    {
338
    {
314
        CleanUp();
339
        CleanUp();
315
        exit(0);
340
        exit(0);
316
        //on_message_condition.notify_all();
341
        //on_message_condition.notify_all();
317
    }
342
    }
318
}
343
}