-
Notifications
You must be signed in to change notification settings - Fork 0
/
service.h
156 lines (125 loc) · 4.3 KB
/
service.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* COPYRIGHT 2014 (C) Jason Volk
* COPYRIGHT 2014 (C) Svetlana Tkachenko
*
* DISTRIBUTED UNDER THE GNU GENERAL PUBLIC LICENSE (GPL) (see: LICENSE)
*/
class Service : public Stream
{
std::string name;
std::list<std::string> capture; // State of the current capture
std::deque<std::forward_list<std::string>> queue; // Queue of terminators
void next(); // Discard capture, move to next in queue
public:
auto get_name() const { return name; }
auto queue_size() const { return queue.size(); }
auto capture_size() const { return capture.size(); }
virtual bool enabled() const { return get_opts().get<bool>("services"); }
protected:
using Capture = decltype(capture);
auto &get_terminator() const { return queue.front(); }
// Passes a complete multipart message to subclass
// once the handler here receives a terminator
virtual void captured(const Capture &capture) = 0;
public:
void clear_capture() { capture.clear(); }
void clear_queue() { queue.clear(); }
// [SEND] Add expected terminator every send
void terminator_next(const std::string &str) { queue.push_back({tolower(str)}); }
void terminator_also(const std::string &str) { queue.back().emplace_front(tolower(str)); }
void terminator_errors() { queue.push_back({"",""}); }
void terminator_any() { queue.push_back({""}); }
// [RECV] Called by Bot handlers
void handle(const Msg &msg);
Service(const std::string &name);
friend std::ostream &operator<<(std::ostream &s, const Service &srv);
};
inline
Service::Service(const std::string &name):
name(name)
{
}
inline
void Service::handle(const Msg &msg)
try
{
using namespace fmt::NOTICE;
static const auto errors =
{
"you are not authorized",
"invalid parameters",
"is not registered",
"is not online",
"unchanged",
"no bans found",
};
static const auto ignores =
{
"this nickname is registered",
"you have been",
};
if(queue.empty())
return;
if(msg.get_name() != "NOTICE")
throw Exception("Service handler only reads NOTICE.");
const auto &term = queue.front();
const auto &text = tolower(decolor(msg[TEXT]));
const size_t terms = std::distance(term.begin(),term.end());
const bool any_term = terms == 1 && term.begin()->empty();
const bool err_term = terms == 2 && std::all_of(term.begin(),term.end(),[](auto&& t) { return t.empty(); });
const bool match = std::any_of(term.begin(),term.end(),[&](auto&& t) { return text.find(t) != std::string::npos; });
const bool error = std::any_of(errors.begin(),errors.end(),[&](auto&& t) { return text.find(t) != std::string::npos; });
const bool ignore = std::any_of(ignores.begin(),ignores.end(),[&](auto&& t) { return text.find(t) != std::string::npos; });
/*
printf("text[%s] terms[%zu] at[%u] et[%u] m[%u] e[%u] i[%u]\n",text.c_str(),terms,any_term,err_term,match,error,ignore);
for(const auto &t : term)
printf("-term[%s]\n",t.c_str());
*/
if(!err_term && match)
{
/*
printf("CAPTURE: %zu\n",capture.size());
for(const auto &m : capture)
printf("[%s]\n",m.c_str());
*/
const scope r([&] { next(); });
if(capture.empty())
capture.emplace_back(decolor(msg[TEXT]));
captured(capture);
return;
}
if(ignore)
return;
if(err_term && !error)
{
queue.pop_front();
handle(msg);
return;
}
if(any_term || error)
{
next();
return;
}
capture.emplace_back(decolor(msg[TEXT]));
}
catch(const std::out_of_range &e)
{
throw Exception("Range error in Service::handle");
}
inline
void Service::next()
{
queue.pop_front();
capture.clear();
}
inline
std::ostream &operator<<(std::ostream &s,
const Service &srv)
{
s << "[Service]: " << std::endl;
s << "Name: " << srv.get_name() << std::endl;
s << "Queue size: " << srv.queue_size() << std::endl;
s << "Capture size: " << srv.capture_size() << std::endl;
return s;
}