-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmessage.h
120 lines (96 loc) · 3.44 KB
/
message.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
#ifndef SSERVER_MESSAGE_H_INCLUDED
#define SSERVER_MESSAGE_H_INCLUDED
#include "io.h"
#include "code.h"
#include "log.h"
#include "storage.h"
class Pipe;
class MessageBase {
public:
virtual ~MessageBase() {}
virtual bool is_ready() const = 0;
virtual bool is_eof() const = 0;
virtual bool is_fail() const = 0;
void read() { do_notify(&MessageBase::do_read); }
void write() { do_notify(&MessageBase::do_write); }
void hangup() { do_notify(&MessageBase::do_hangup); }
void error() { do_notify(&MessageBase::do_error); }
virtual int fd() const = 0;
virtual int events() const = 0;
virtual void notify() = 0;
private:
void do_notify(void (MessageBase::*op)()) {
(this->*op)();
notify();
}
virtual void do_read() = 0;
virtual void do_write() = 0;
virtual void do_hangup() = 0;
virtual void do_error() = 0;
};
template<typename T>
struct NotifyHelper {
template<typename U>
static void notify(T* notify, U* data) { notify->notify(data); }
};
template<>
struct NotifyHelper<Pipe> {
template<typename U>
static void notify(Pipe* notify, U*) { ::notify(notify); }
};
template<typename H, typename F>
bool try_do(H& handler, F fd) {
try {
return handler.perform(fd);
} catch(std::runtime_error& ex) {
ERROR("IO error: " << ex.what());
handler.fail();
}
return true;
}
template<typename Type,
typename Read = NOP<typename Storage<Type>::base>,
typename Write = NOP<typename Storage<Type>::base>,
typename Notify = Pipe>
class Message : public MessageBase {
typedef Storage<Type> Store;
typedef typename Store::base FDType;
public:
enum { Event = Read::Event | Write::Event | POLLHUP | POLLERR };
explicit Message(FDType* fd, Notify* notify = 0,
const typename Write::type& data = typename Write::type()) :
fd_(fd), notify_(notify), writer_(data), ready_(false) {}
Message(FDType* fd, const Read& reader, Notify* notify = 0) :
fd_(fd), notify_(notify), reader_(reader), ready_(false) {}
Message(FDType* fd, const Write& writer, Notify* notify = 0) :
fd_(fd), notify_(notify), writer_(writer), ready_(false) {}
// in C++11 move data from reader
// getting data from reader may not be constant
typename Read::type data() { return reader_.data(); }
// const typename Read<FDType>::type& data() const { return reader_.data(); }
bool is_ready() const { return ready_ || is_eof() || is_fail(); }
bool is_eof() const { return reader_.is_eof() || writer_.is_eof(); }
bool is_fail() const { return reader_.is_fail() || writer_.is_fail(); }
FDType* get() { return Store::get(fd_); }
const FDType* get() const { return Store::get(fd_); }
int fd() const { return GetFD<FDType, Read, Write>::get(this->get()); }
int events() const { return Event; }
private:
void notify() { if(notify_) NotifyHelper<Notify>::notify(notify_, this); }
void do_read() { ready_ = try_do(reader_, Store::get(fd_)); }
void do_write() { ready_ = try_do(writer_, Store::get(fd_)); }
void do_hangup() {
reader_.hangup(Store::get(fd_));
writer_.hangup(Store::get(fd_));
}
void do_error() {
reader_.fail(Store::get(fd_));
writer_.fail(Store::get(fd_));
}
typename Store::type fd_;
Notify* notify_;
Read reader_;
Write writer_;
bool ready_;
};
#endif // SSERVER_MESSAGE_H_INCLUDED