protohack-3.cpp (2883B)
1 #include "inet.hpp" 2 3 #include <poll.h> 4 5 #include <iostream> 6 #include <sstream> 7 #include <map> 8 #include <vector> 9 10 #include "fd.hpp" 11 12 using namespace std; 13 14 struct client 15 { 16 descriptor d; 17 std::string name, buf; 18 stringstream stream; 19 20 bool do_read() 21 { 22 string data = read(d); 23 if (data.empty()) 24 return false; 25 26 buf.append(data); 27 return true; 28 } 29 string getline() 30 { 31 auto s = buf.find_first_not_of('\n'); 32 auto n = buf.find('\n', s); 33 if (n == string::npos) 34 return {}; 35 36 string line = buf.substr(s, n); 37 buf.erase(0, s+n+1); 38 return line; 39 } 40 }; 41 42 std::map<int, client> unnamed, clients; 43 44 void broadcast(string msg, int exclude) 45 { 46 msg.push_back('\n'); 47 std::cout << msg; 48 for (auto& c : clients) 49 if (c.second.d != exclude) 50 write(c.second.d, msg); 51 } 52 53 int main() 54 { 55 auto incoming = inet::listen(SOCK_STREAM); 56 57 for (;;) 58 { 59 std::vector<pollfd> awaitables; 60 awaitables.push_back({incoming, POLLIN, 0}); 61 for (auto const& c : unnamed) 62 awaitables.push_back({c.second.d, POLLIN, 0}); 63 for (auto const& c : clients) 64 awaitables.push_back({c.second.d, POLLIN, 0}); 65 66 ::poll(awaitables.data(), awaitables.size(), INFTIM); 67 68 for (auto& ev : awaitables) 69 { 70 if (~ev.revents & POLLIN) 71 continue; 72 73 if (ev.fd == incoming) 74 { 75 auto conn = inet::accept(incoming); 76 77 write(conn, "Welcome to H&L-chat, what is your name?\n"); 78 auto& x = unnamed[conn]; 79 x.d = move(conn); 80 continue; 81 } 82 83 auto it = unnamed.find(ev.fd); 84 if (it != unnamed.end()) 85 { 86 auto& c = it->second; 87 // c.stream << read(c.d); 88 if (not c.do_read()) 89 { 90 unnamed.erase(it); 91 continue; 92 } 93 string line = c.getline(); 94 if (line.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz") != string::npos) 95 { 96 unnamed.erase(it); 97 continue; 98 } 99 // getline(c.stream, line); 100 { 101 ostringstream msg; 102 msg << "* " << line << " joined."; 103 broadcast(msg.str(), c.d); 104 c.name = line; 105 } 106 { 107 ostringstream msg; 108 msg << "* " << clients.size() << " users in chat:"; 109 for (auto const& o : clients) 110 msg << ' ' << o.second.name; 111 msg << '\n'; 112 write(c.d, msg.str()); 113 } 114 clients.insert(unnamed.extract(it)); 115 continue; 116 } 117 118 it = clients.find(ev.fd); 119 if (it != clients.end()) 120 { 121 auto& c = it->second; 122 // string line = read(c.d); 123 // if (line.empty()) 124 if (not c.do_read()) 125 { 126 ostringstream msg; 127 msg << "* " << c.name << " has left the room"; 128 broadcast(msg.str(), c.d); 129 clients.erase(it); 130 continue; 131 } 132 133 // c.stream << line; 134 135 // getline(c.stream, line); 136 string line = c.getline(); 137 if (line.empty()) 138 continue; 139 ostringstream msg; 140 msg << "[" << c.name << "] " << line; 141 broadcast(msg.str(), c.d); 142 continue; 143 } 144 145 cerr << "Unknown fd " << ev.fd << endl; 146 return 1; 147 } 148 } 149 }