|
@@ -0,0 +1,165 @@
|
|
|
+#include <iostream>
|
|
|
+#include <fstream>
|
|
|
+#include <sstream>
|
|
|
+#include <vector>
|
|
|
+#include <thread>
|
|
|
+#include <tuple>
|
|
|
+
|
|
|
+#include <grpc++/grpc++.h>
|
|
|
+#include <simplechat.pb.h>
|
|
|
+#include <simplechat.grpc.pb.h>
|
|
|
+using namespace ::qtprotobuf::examples;
|
|
|
+
|
|
|
+class MessageListHandler;
|
|
|
+class UserListHandler;
|
|
|
+
|
|
|
+class SimpleChatService final : public SimpleChat::WithAsyncMethod_messageList<SimpleChat::WithAsyncMethod_usersOnline<SimpleChat::Service>> {
|
|
|
+public:
|
|
|
+ Users m_usersOnline;
|
|
|
+ Users m_usersDatabase;
|
|
|
+ ChatMessages m_messages;
|
|
|
+
|
|
|
+ SimpleChatService() {
|
|
|
+ User *newUser = m_usersDatabase.add_users();
|
|
|
+ newUser->set_name("user1");
|
|
|
+ newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4");
|
|
|
+ newUser = m_usersDatabase.add_users();
|
|
|
+ newUser->set_name("user2");
|
|
|
+ newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4");
|
|
|
+ newUser = m_usersDatabase.add_users();
|
|
|
+ newUser->set_name("user3");
|
|
|
+ newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4");
|
|
|
+ newUser = m_usersDatabase.add_users();
|
|
|
+ newUser->set_name("user4");
|
|
|
+ newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4");
|
|
|
+ newUser = m_usersDatabase.add_users();
|
|
|
+ newUser->set_name("user5");
|
|
|
+ newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4");
|
|
|
+ }
|
|
|
+
|
|
|
+ void loginUser(MessageListHandler *userHandler);
|
|
|
+
|
|
|
+ void updateActiveUsers() {
|
|
|
+ for(unsigned int i = 0; i < (m_activeUserListClients.size() - 1); i++) {
|
|
|
+ m_activeUserListClients[i]->Write(m_usersOnline, nullptr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void updateMessages() {
|
|
|
+ for(unsigned int i = 0; i < (m_activeClients.size() - 1); i++) {
|
|
|
+ m_activeClients[i]->Write(m_messages, nullptr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool checkUserCredentials(const std::string &name, const std::string &password) {
|
|
|
+ for(int i = 0; i < m_usersDatabase.users_size(); i++) {
|
|
|
+ if (m_usersDatabase.users(i).name() == name && m_usersDatabase.users(i).password() == password) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::tuple<std::string, std::string> extractCredentials(grpc::ServerContext *context) {
|
|
|
+ std::string name{};
|
|
|
+ std::string password{};
|
|
|
+ for (auto it = context->client_metadata().begin(); it != context->client_metadata().end(); ++it) {
|
|
|
+ if ((*it).first == std::string("user-name")) {
|
|
|
+ name = std::string((*it).second.data());
|
|
|
+ }
|
|
|
+ if ((*it).first == std::string("user-password")) {
|
|
|
+ password = std::string((*it).second.data());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return std::make_tuple(name, password);
|
|
|
+ }
|
|
|
+
|
|
|
+ ::grpc::Status sendMessage(grpc::ServerContext *context, const ChatMessage *request, None *) override
|
|
|
+ {
|
|
|
+ std::string name{};
|
|
|
+ std::string password{};
|
|
|
+ std::tie(name, password) = extractCredentials(context);
|
|
|
+ if (!checkUserCredentials(name, password)) {
|
|
|
+ return ::grpc::Status(::grpc::StatusCode::UNAUTHENTICATED, "User or login are invalid");
|
|
|
+ }
|
|
|
+
|
|
|
+ ChatMessage *msg = m_messages.add_messages();
|
|
|
+ *msg = *request;
|
|
|
+ msg->set_from(name);
|
|
|
+ updateMessages();
|
|
|
+ return ::grpc::Status();
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<::grpc::ServerAsyncWriter<ChatMessages> *> m_activeClients;
|
|
|
+ std::vector<::grpc::ServerAsyncWriter<Users> *> m_activeUserListClients;
|
|
|
+};
|
|
|
+
|
|
|
+class MessageListHandler {
|
|
|
+public:
|
|
|
+ MessageListHandler(SimpleChatService* service, ::grpc::ServerCompletionQueue* cq) : tag_(0xdeadbeef)
|
|
|
+ , writer_(&ctx_)
|
|
|
+ , cq_(cq)
|
|
|
+ {
|
|
|
+ service->RequestmessageList(&ctx_, &request_, &writer_, cq_, cq_, &tag_);
|
|
|
+ service->loginUser(this);
|
|
|
+ }
|
|
|
+ int tag_;
|
|
|
+ grpc::ServerContext ctx_;
|
|
|
+ None request_;
|
|
|
+ ::grpc::ServerAsyncWriter< ::qtprotobuf::examples::ChatMessages> writer_;
|
|
|
+ ::grpc::ServerCompletionQueue* cq_;
|
|
|
+};
|
|
|
+
|
|
|
+void SimpleChatService::loginUser(MessageListHandler *handler) {
|
|
|
+ m_activeClients.push_back(&(handler->writer_));
|
|
|
+ //TODO: update online if required here
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+ std::string server_address("localhost:65002");
|
|
|
+ SimpleChatService service;
|
|
|
+
|
|
|
+ std::ifstream tfile("cert.pem");
|
|
|
+ std::stringstream cert;
|
|
|
+ cert << tfile.rdbuf();
|
|
|
+ tfile.close();
|
|
|
+
|
|
|
+ tfile.open("key.pem");
|
|
|
+ std::stringstream key;
|
|
|
+ key << tfile.rdbuf();
|
|
|
+ tfile.close();
|
|
|
+
|
|
|
+ grpc::ServerBuilder builder;
|
|
|
+ grpc::SslServerCredentialsOptions opts(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
|
|
|
+ opts.pem_key_cert_pairs.push_back({key.str(), cert.str()});
|
|
|
+ builder.AddListeningPort(server_address, grpc::SslServerCredentials(opts));
|
|
|
+ builder.RegisterService(&service);
|
|
|
+ std::unique_ptr<grpc::ServerCompletionQueue> cq = builder.AddCompletionQueue();
|
|
|
+ std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
|
|
|
+ std::cout << "Server listening on " << server_address << std::endl;
|
|
|
+ MessageListHandler *last = new MessageListHandler(&service, cq.get());
|
|
|
+ while (true) {
|
|
|
+ unsigned int *tag;
|
|
|
+ bool ok;
|
|
|
+ cq->Next((void**)&tag, &ok);
|
|
|
+ if (tag == nullptr) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ((*tag) == 0xdeadbeef) {
|
|
|
+ std::string name{};
|
|
|
+ std::string password{};
|
|
|
+ std::tie(name, password) = service.extractCredentials(&(last->ctx_));
|
|
|
+ if (!service.checkUserCredentials(name, password)) {
|
|
|
+ std::cout << "Authentication failed" << std::endl;
|
|
|
+ last->writer_.Finish(::grpc::Status(::grpc::StatusCode::UNAUTHENTICATED, "User or login are invalid"), nullptr);
|
|
|
+ last = new MessageListHandler(&service, cq.get());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ std::cout << "Authentication ok update user chat" << std::endl;
|
|
|
+ last->writer_.Write(service.m_messages, nullptr);
|
|
|
+ last = new MessageListHandler(&service, cq.get());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|