Subversion Repositories HomeAutomation

Rev

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