LCOV - code coverage report
Current view: top level - src/UserService - UserHandler.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 174 626 27.8 %
Date: 2025-11-04 01:11:49 Functions: 7 13 53.8 %

          Line data    Source code
       1             : #ifndef SOCIAL_NETWORK_MICROSERVICES_USERHANDLER_H
       2             : #define SOCIAL_NETWORK_MICROSERVICES_USERHANDLER_H
       3             : 
       4             : #include <bson/bson.h>
       5             : #include <libmemcached/memcached.h>
       6             : #include <libmemcached/util.h>
       7             : #include <mongoc.h>
       8             : 
       9             : #include <iomanip>
      10             : #include <iostream>
      11             : #include <jwt/jwt.hpp>
      12             : #include <nlohmann/json.hpp>
      13             : #include <random>
      14             : #include <string>
      15             : 
      16             : #include "../../gen-cpp/SocialGraphService.h"
      17             : #include "../../gen-cpp/UserService.h"
      18             : #include "../../gen-cpp/social_network_types.h"
      19             : #include "../../third_party/PicoSHA2/picosha2.h"
      20             : #include "../ClientPool.h"
      21             : #include "../ThriftClient.h"
      22             : #include "../logger.h"
      23             : #include "../tracing.h"
      24             : 
      25             : // Custom Epoch (January 1, 2018 Midnight GMT = 2018-01-01T00:00:00Z)
      26             : #define CUSTOM_EPOCH 1514764800000
      27             : #define MONGODB_TIMEOUT_MS 100
      28             : 
      29             : namespace social_network {
      30             : 
      31             : using std::chrono::duration_cast;
      32             : using std::chrono::milliseconds;
      33             : using std::chrono::seconds;
      34             : using std::chrono::system_clock;
      35             : using namespace jwt::params;
      36             : 
      37             : static int64_t current_timestamp = -1;
      38             : static int counter = 0;
      39             : 
      40           0 : static int GetCounter(int64_t timestamp) {
      41           0 :   if (current_timestamp > timestamp) {
      42           0 :     LOG(fatal) << "Timestamps are not incremental.";
      43           0 :     exit(EXIT_FAILURE);
      44             :   }
      45           0 :   if (current_timestamp == timestamp) {
      46           0 :     return counter++;
      47             :   } else {
      48           0 :     current_timestamp = timestamp;
      49           0 :     counter = 0;
      50           0 :     return counter++;
      51             :   }
      52             : }
      53             : 
      54        1162 : std::string GenRandomString(const int len) {
      55             :   static const std::string alphanum =
      56             :       "0123456789"
      57             :       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      58        1162 :       "abcdefghijklmnopqrstuvwxyz";
      59        2323 :   std::random_device rd;
      60        1162 :   std::mt19937 gen(rd());
      61             :   std::uniform_int_distribution<int> dist(
      62        1162 :       0, static_cast<int>(alphanum.length() - 1));
      63        1162 :   std::string s;
      64       38316 :   for (int i = 0; i < len; ++i) {
      65       37155 :     s += alphanum[dist(gen)];
      66             :   }
      67        2322 :   return s;
      68             : }
      69             : 
      70             : class UserHandler : public UserServiceIf {
      71             :  public:
      72             :   UserHandler(std::mutex *, const std::string &, const std::string &,
      73             :               memcached_pool_st *, mongoc_client_pool_t *,
      74             :               ClientPool<ThriftClient<SocialGraphServiceClient>> *);
      75           0 :   ~UserHandler() override = default;
      76             :   void RegisterUser(int64_t, const std::string &, const std::string &,
      77             :                     const std::string &, const std::string &,
      78             :                     const std::map<std::string, std::string> &) override;
      79             :   void RegisterUserWithId(int64_t, const std::string &, const std::string &,
      80             :                           const std::string &, const std::string &, int64_t,
      81             :                           const std::map<std::string, std::string> &) override;
      82             : 
      83             :   void ComposeCreatorWithUserId(
      84             :       Creator &, int64_t, int64_t, const std::string &,
      85             :       const std::map<std::string, std::string> &) override;
      86             :   void ComposeCreatorWithUsername(
      87             :       Creator &, int64_t, const std::string &,
      88             :       const std::map<std::string, std::string> &) override;
      89             :   void Login(std::string &, int64_t, const std::string &, const std::string &,
      90             :              const std::map<std::string, std::string> &) override;
      91             :   int64_t GetUserId(int64_t, const std::string &,
      92             :                     const std::map<std::string, std::string> &) override;
      93             : 
      94             :  private:
      95             :   std::string _machine_id;
      96             :   std::string _secret;
      97             :   std::mutex *_thread_lock;
      98             :   memcached_pool_st *_memcached_client_pool;
      99             :   mongoc_client_pool_t *_mongodb_client_pool;
     100             :   ClientPool<ThriftClient<SocialGraphServiceClient>> *_social_graph_client_pool;
     101             : };
     102             : 
     103           1 : UserHandler::UserHandler(std::mutex *thread_lock, const std::string &machine_id,
     104             :                          const std::string &secret,
     105             :                          memcached_pool_st *memcached_client_pool,
     106             :                          mongoc_client_pool_t *mongodb_client_pool,
     107             :                          ClientPool<ThriftClient<SocialGraphServiceClient>>
     108           1 :                              *social_graph_client_pool) {
     109           1 :   _thread_lock = thread_lock;
     110           1 :   _machine_id = machine_id;
     111           1 :   _memcached_client_pool = memcached_client_pool;
     112           1 :   _mongodb_client_pool = mongodb_client_pool;
     113           1 :   _secret = secret;
     114           1 :   _social_graph_client_pool = social_graph_client_pool;
     115           1 : }
     116             : 
     117        1160 : void UserHandler::RegisterUserWithId(
     118             :     const int64_t req_id, const std::string &first_name,
     119             :     const std::string &last_name, const std::string &username,
     120             :     const std::string &password, const int64_t user_id,
     121             :     const std::map<std::string, std::string> &carrier) {
     122             :   // 记录收到注册请求
     123        2322 :   LOG(info) << "Received RegisterUserWithId request [req_id=" << req_id << ", username=" << username << ", user_id=" << user_id << "]";
     124             :   // Initialize a span
     125        2324 :   TextMapReader reader(carrier);
     126        2324 :   std::map<std::string, std::string> writer_text_map;
     127        2324 :   TextMapWriter writer(writer_text_map);
     128        2324 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
     129        2321 :   auto span = opentracing::Tracer::Global()->StartSpan(
     130             :       "register_user_withid_server",
     131        4645 :       {opentracing::ChildOf(parent_span->get())});
     132        1161 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
     133             : 
     134             :   // Store user info into mongodb
     135             :   mongoc_client_t *mongodb_client =
     136        1162 :       mongoc_client_pool_pop(_mongodb_client_pool);
     137        1162 :   if (!mongodb_client) {
     138           0 :     ServiceException se;
     139           0 :     se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     140           0 :     se.message = "Failed to pop a client from MongoDB pool";
     141           0 :     throw se;
     142             :   }
     143             :   auto collection =
     144        1162 :       mongoc_client_get_collection(mongodb_client, "user", "user");
     145             : 
     146             :   // Check if the username has existed in the database
     147        1162 :   bson_t *query = bson_new();
     148        1162 :   BSON_APPEND_UTF8(query, "username", username.c_str());
     149             :   mongoc_cursor_t *cursor =
     150        1162 :       mongoc_collection_find_with_opts(collection, query, nullptr, nullptr);
     151             :   const bson_t *doc;
     152             :   bson_error_t error;
     153        1162 :   bool found = mongoc_cursor_next(cursor, &doc);
     154        1160 :   if (mongoc_cursor_error(cursor, &error)) {
     155           0 :     LOG(warning) << error.message;
     156           0 :     bson_destroy(query);
     157           0 :     mongoc_cursor_destroy(cursor);
     158           0 :     mongoc_collection_destroy(collection);
     159           0 :     mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     160           0 :     ServiceException se;
     161           0 :     se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     162           0 :     se.message = error.message;
     163           0 :     throw se;
     164        1162 :   } else if (found) {
     165           0 :     LOG(warning) << "User " << username << " already existed.";
     166           0 :     ServiceException se;
     167           0 :     se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     168           0 :     se.message = "User " + username + " already existed";
     169           0 :     bson_destroy(query);
     170           0 :     mongoc_cursor_destroy(cursor);
     171           0 :     mongoc_collection_destroy(collection);
     172           0 :     mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     173           0 :     throw se;
     174             :   } else {
     175        1162 :     bson_t *new_doc = bson_new();
     176        1161 :     BSON_APPEND_INT64(new_doc, "user_id", user_id);
     177        1162 :     BSON_APPEND_UTF8(new_doc, "first_name", first_name.c_str());
     178        1162 :     BSON_APPEND_UTF8(new_doc, "last_name", last_name.c_str());
     179        1162 :     BSON_APPEND_UTF8(new_doc, "username", username.c_str());
     180        2324 :     std::string salt = GenRandomString(32);
     181        1161 :     BSON_APPEND_UTF8(new_doc, "salt", salt.c_str());
     182        2323 :     std::string password_hashed = picosha2::hash256_hex_string(password + salt);
     183        1162 :     BSON_APPEND_UTF8(new_doc, "password", password_hashed.c_str());
     184             : 
     185             :     bson_error_t error;
     186        2323 :     auto user_insert_span = opentracing::Tracer::Global()->StartSpan(
     187        4647 :         "user_mongo_insert_cilent", {opentracing::ChildOf(&span->context())});
     188        1162 :     if (!mongoc_collection_insert_one(collection, new_doc, nullptr, nullptr,
     189             :                                       &error)) {
     190         600 :       LOG(error) << "Failed to insert user " << username
     191         200 :                  << " to MongoDB: " << error.message;
     192         400 :       ServiceException se;
     193         200 :       se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     194             :       se.message =
     195         200 :           "Failed to insert user " + username + " to MongoDB: " + error.message;
     196         200 :       bson_destroy(query);
     197         200 :       mongoc_cursor_destroy(cursor);
     198         200 :       mongoc_collection_destroy(collection);
     199         200 :       mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     200         200 :       throw se;
     201             :     } else {
     202         962 :       LOG(debug) << "User: " << username << " registered";
     203             :     }
     204         962 :     user_insert_span->Finish();
     205         960 :     bson_destroy(new_doc);
     206             :   }
     207         962 :   bson_destroy(query);
     208         962 :   mongoc_cursor_destroy(cursor);
     209         962 :   mongoc_collection_destroy(collection);
     210         962 :   mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     211             : 
     212         962 :   if (!found) {
     213         962 :     auto social_graph_client_wrapper = _social_graph_client_pool->Pop();
     214         962 :     if (!social_graph_client_wrapper) {
     215           0 :       ServiceException se;
     216           0 :       se.errorCode = ErrorCode::SE_THRIFT_CONN_ERROR;
     217           0 :       se.message = "Failed to connect to social-graph-service";
     218           0 :       throw se;
     219             :     }
     220         962 :     auto social_graph_client = social_graph_client_wrapper->GetClient();
     221             :     try {
     222         962 :       social_graph_client->InsertUser(req_id, user_id, writer_text_map);
     223           0 :     } catch (...) {
     224           0 :       _social_graph_client_pool->Remove(social_graph_client_wrapper);
     225           0 :       LOG(error) << "Failed to insert user to social-graph-client";
     226           0 :       throw;
     227             :     }
     228         962 :     _social_graph_client_pool->Keepalive(social_graph_client_wrapper);
     229             :   }
     230             : 
     231         962 :   span->Finish();
     232             :   // 注册成功后
     233        1924 :   LOG(info) << "RegisterUserWithId completed [req_id=" << req_id << ", username=" << username << ", user_id=" << user_id << "]";
     234         962 : }
     235             : 
     236           0 : void UserHandler::RegisterUser(
     237             :     const int64_t req_id, const std::string &first_name,
     238             :     const std::string &last_name, const std::string &username,
     239             :     const std::string &password,
     240             :     const std::map<std::string, std::string> &carrier) {
     241             :   // Initialize a span
     242           0 :   TextMapReader reader(carrier);
     243           0 :   std::map<std::string, std::string> writer_text_map;
     244           0 :   TextMapWriter writer(writer_text_map);
     245           0 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
     246           0 :   auto span = opentracing::Tracer::Global()->StartSpan(
     247           0 :       "register_user_server", {opentracing::ChildOf(parent_span->get())});
     248           0 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
     249             : 
     250             :   // Compose user_id
     251           0 :   _thread_lock->lock();
     252             :   int64_t timestamp =
     253           0 :       duration_cast<milliseconds>(system_clock::now().time_since_epoch())
     254           0 :           .count() -
     255           0 :       CUSTOM_EPOCH;
     256           0 :   int idx = GetCounter(timestamp);
     257           0 :   _thread_lock->unlock();
     258             : 
     259           0 :   std::stringstream sstream;
     260           0 :   sstream << std::hex << timestamp;
     261           0 :   std::string timestamp_hex(sstream.str());
     262           0 :   if (timestamp_hex.size() > 10) {
     263           0 :     timestamp_hex.erase(0, timestamp_hex.size() - 10);
     264           0 :   } else if (timestamp_hex.size() < 10) {
     265           0 :     timestamp_hex = std::string(10 - timestamp_hex.size(), '0') + timestamp_hex;
     266             :   }
     267             :   // Empty the sstream buffer.
     268           0 :   sstream.clear();
     269           0 :   sstream.str(std::string());
     270             : 
     271           0 :   sstream << std::hex << idx;
     272           0 :   std::string counter_hex(sstream.str());
     273             : 
     274           0 :   if (counter_hex.size() > 3) {
     275           0 :     counter_hex.erase(0, counter_hex.size() - 3);
     276           0 :   } else if (counter_hex.size() < 3) {
     277           0 :     counter_hex = std::string(3 - counter_hex.size(), '0') + counter_hex;
     278             :   }
     279           0 :   std::string user_id_str = _machine_id + timestamp_hex + counter_hex;
     280           0 :   int64_t user_id = stoul(user_id_str, nullptr, 16) & 0x7FFFFFFFFFFFFFFF;
     281             :   ;
     282           0 :   LOG(debug) << "The user_id of the request " << req_id << " is " << user_id;
     283             : 
     284             :   // Store user info into mongodb
     285             :   mongoc_client_t *mongodb_client =
     286           0 :       mongoc_client_pool_pop(_mongodb_client_pool);
     287           0 :   if (!mongodb_client) {
     288           0 :     ServiceException se;
     289           0 :     se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     290           0 :     se.message = "Failed to pop a client from MongoDB pool";
     291           0 :     throw se;
     292             :   }
     293             :   auto collection =
     294           0 :       mongoc_client_get_collection(mongodb_client, "user", "user");
     295             : 
     296             :   // Check if the username has existed in the database
     297           0 :   bson_t *query = bson_new();
     298           0 :   BSON_APPEND_UTF8(query, "username", username.c_str());
     299             :   mongoc_cursor_t *cursor =
     300           0 :       mongoc_collection_find_with_opts(collection, query, nullptr, nullptr);
     301             :   const bson_t *doc;
     302             :   bson_error_t error;
     303           0 :   bool found = mongoc_cursor_next(cursor, &doc);
     304           0 :   if (mongoc_cursor_error(cursor, &error)) {
     305           0 :     LOG(error) << error.message;
     306           0 :     bson_destroy(query);
     307           0 :     mongoc_cursor_destroy(cursor);
     308           0 :     mongoc_collection_destroy(collection);
     309           0 :     mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     310           0 :     ServiceException se;
     311           0 :     se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     312           0 :     se.message = error.message;
     313           0 :     throw se;
     314           0 :   } else if (found) {
     315           0 :     LOG(warning) << "User " << username << " already existed.";
     316           0 :     ServiceException se;
     317           0 :     se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     318           0 :     se.message = "User " + username + " already existed";
     319           0 :     bson_destroy(query);
     320           0 :     mongoc_cursor_destroy(cursor);
     321           0 :     mongoc_collection_destroy(collection);
     322           0 :     mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     323           0 :     throw se;
     324             :   } else {
     325           0 :     bson_t *new_doc = bson_new();
     326           0 :     BSON_APPEND_INT64(new_doc, "user_id", user_id);
     327           0 :     BSON_APPEND_UTF8(new_doc, "first_name", first_name.c_str());
     328           0 :     BSON_APPEND_UTF8(new_doc, "last_name", last_name.c_str());
     329           0 :     BSON_APPEND_UTF8(new_doc, "username", username.c_str());
     330           0 :     std::string salt = GenRandomString(32);
     331           0 :     BSON_APPEND_UTF8(new_doc, "salt", salt.c_str());
     332           0 :     std::string password_hashed = picosha2::hash256_hex_string(password + salt);
     333           0 :     BSON_APPEND_UTF8(new_doc, "password", password_hashed.c_str());
     334             : 
     335           0 :     auto user_insert_span = opentracing::Tracer::Global()->StartSpan(
     336           0 :         "user_mongo_insert_client", {opentracing::ChildOf(&span->context())});
     337           0 :     if (!mongoc_collection_insert_one(collection, new_doc, nullptr, nullptr,
     338             :                                       &error)) {
     339           0 :       LOG(error) << "Failed to insert user " << username
     340           0 :                  << " to MongoDB: " << error.message;
     341           0 :       ServiceException se;
     342           0 :       se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     343             :       se.message =
     344           0 :           "Failed to insert user " + username + " to MongoDB: " + error.message;
     345           0 :       bson_destroy(query);
     346           0 :       mongoc_cursor_destroy(cursor);
     347           0 :       mongoc_collection_destroy(collection);
     348           0 :       mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     349           0 :       throw se;
     350             :     } else {
     351           0 :       LOG(debug) << "User: " << username << " registered";
     352             :     }
     353           0 :     user_insert_span->Finish();
     354           0 :     bson_destroy(new_doc);
     355             :   }
     356           0 :   bson_destroy(query);
     357           0 :   mongoc_cursor_destroy(cursor);
     358           0 :   mongoc_collection_destroy(collection);
     359           0 :   mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     360             : 
     361           0 :   if (!found) {
     362           0 :     auto social_graph_client_wrapper = _social_graph_client_pool->Pop();
     363           0 :     if (!social_graph_client_wrapper) {
     364           0 :       ServiceException se;
     365           0 :       se.errorCode = ErrorCode::SE_THRIFT_CONN_ERROR;
     366           0 :       se.message = "Failed to connect to social-graph-service";
     367           0 :       throw se;
     368             :     }
     369           0 :     auto social_graph_client = social_graph_client_wrapper->GetClient();
     370             :     try {
     371           0 :       social_graph_client->InsertUser(req_id, user_id, writer_text_map);
     372           0 :     } catch (...) {
     373           0 :       _social_graph_client_pool->Remove(social_graph_client_wrapper);
     374           0 :       LOG(error) << "Failed to insert user to social-graph-service";
     375           0 :       throw;
     376             :     }
     377             : 
     378           0 :     _social_graph_client_pool->Keepalive(social_graph_client_wrapper);
     379             :   }
     380             : 
     381           0 :   span->Finish();
     382           0 : }
     383             : 
     384           0 : void UserHandler::ComposeCreatorWithUsername(
     385             :     Creator &_return, const int64_t req_id, const std::string &username,
     386             :     const std::map<std::string, std::string> &carrier) {
     387           0 :   LOG(info) << "Received ComposeCreatorWithUsername request [req_id=" << req_id << ", username=" << username << "]";
     388           0 :   TextMapReader reader(carrier);
     389           0 :   std::map<std::string, std::string> writer_text_map;
     390           0 :   TextMapWriter writer(writer_text_map);
     391           0 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
     392           0 :   auto span = opentracing::Tracer::Global()->StartSpan(
     393           0 :       "compose_creator_server", {opentracing::ChildOf(parent_span->get())});
     394           0 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
     395             : 
     396             :   size_t user_id_size;
     397             :   uint32_t memcached_flags;
     398             : 
     399             :   memcached_return_t memcached_rc;
     400             :   memcached_st *memcached_client =
     401           0 :       memcached_pool_pop(_memcached_client_pool, true, &memcached_rc);
     402             :   char *user_id_mmc;
     403           0 :   if (memcached_client) {
     404           0 :     auto id_get_span = opentracing::Tracer::Global()->StartSpan(
     405           0 :         "user_mmc_get_client", {opentracing::ChildOf(&span->context())});
     406             :     user_id_mmc =
     407           0 :         memcached_get(memcached_client, (username + ":user_id").c_str(),
     408           0 :                       (username + ":user_id").length(), &user_id_size,
     409           0 :                       &memcached_flags, &memcached_rc);
     410           0 :     id_get_span->Finish();
     411           0 :     if (!user_id_mmc && memcached_rc != MEMCACHED_NOTFOUND) {
     412           0 :       ServiceException se;
     413           0 :       se.errorCode = ErrorCode::SE_MEMCACHED_ERROR;
     414           0 :       se.message = memcached_strerror(memcached_client, memcached_rc);
     415           0 :       memcached_pool_push(_memcached_client_pool, memcached_client);
     416           0 :       throw se;
     417             :     }
     418           0 :     memcached_pool_push(_memcached_client_pool, memcached_client);
     419             :   } else {
     420           0 :     LOG(warning) << "Failed to pop a client from memcached pool";
     421             :   }
     422             : 
     423           0 :   int64_t user_id = -1;
     424           0 :   bool cached = false;
     425           0 :   if (user_id_mmc) {
     426           0 :     cached = true;
     427           0 :     LOG(debug) << "Found user_id of username :" << username << " in Memcached";
     428           0 :     user_id = std::stoul(user_id_mmc);
     429           0 :     free(user_id_mmc);
     430             :   }
     431             : 
     432             :   // If not cached in memcached
     433             :   else {
     434           0 :     LOG(debug) << "user_id not cached in Memcached";
     435             :     mongoc_client_t *mongodb_client =
     436           0 :         mongoc_client_pool_pop(_mongodb_client_pool);
     437           0 :     if (!mongodb_client) {
     438           0 :       ServiceException se;
     439           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     440           0 :       se.message = "Failed to pop a client from MongoDB pool";
     441           0 :       throw se;
     442             :     }
     443             :     auto collection =
     444           0 :         mongoc_client_get_collection(mongodb_client, "user", "user");
     445           0 :     if (!collection) {
     446           0 :       ServiceException se;
     447           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     448           0 :       se.message = "Failed to create collection user from DB user";
     449           0 :       throw se;
     450             :     }
     451           0 :     bson_t *query = bson_new();
     452           0 :     BSON_APPEND_UTF8(query, "username", username.c_str());
     453             : 
     454           0 :     auto find_span = opentracing::Tracer::Global()->StartSpan(
     455           0 :         "user_mongo_find_client", {opentracing::ChildOf(&span->context())});
     456             :     mongoc_cursor_t *cursor =
     457           0 :         mongoc_collection_find_with_opts(collection, query, nullptr, nullptr);
     458             :     const bson_t *doc;
     459           0 :     bool found = mongoc_cursor_next(cursor, &doc);
     460           0 :     find_span->Finish();
     461           0 :     if (!found) {
     462             :       bson_error_t error;
     463           0 :       if (mongoc_cursor_error(cursor, &error)) {
     464           0 :         LOG(error) << error.message;
     465           0 :         bson_destroy(query);
     466           0 :         mongoc_cursor_destroy(cursor);
     467           0 :         mongoc_collection_destroy(collection);
     468           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     469           0 :         ServiceException se;
     470           0 :         se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     471           0 :         se.message = error.message;
     472           0 :         throw se;
     473             :       } else {
     474           0 :         LOG(warning) << "User: " << username << " doesn't exist in MongoDB";
     475           0 :         bson_destroy(query);
     476           0 :         mongoc_cursor_destroy(cursor);
     477           0 :         mongoc_collection_destroy(collection);
     478           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     479           0 :         ServiceException se;
     480           0 :         se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     481           0 :         se.message = "User: " + username + " is not registered";
     482           0 :         throw se;
     483             :       }
     484             :     } else {
     485           0 :       LOG(debug) << "User: " << username << " found in MongoDB";
     486             :       bson_iter_t iter;
     487           0 :       if (bson_iter_init_find(&iter, doc, "user_id")) {
     488           0 :         user_id = bson_iter_value(&iter)->value.v_int64;
     489             :       } else {
     490           0 :         LOG(error) << "user_id attribute of user " << username
     491           0 :                    << " was not found in the User object";
     492           0 :         bson_destroy(query);
     493           0 :         mongoc_cursor_destroy(cursor);
     494           0 :         mongoc_collection_destroy(collection);
     495           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     496           0 :         ServiceException se;
     497           0 :         se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     498           0 :         se.message = "user_id attribute of user: " + username +
     499           0 :                      " was not found in the User object";
     500           0 :         throw se;
     501             :       }
     502             :     }
     503           0 :     bson_destroy(query);
     504           0 :     mongoc_cursor_destroy(cursor);
     505           0 :     mongoc_collection_destroy(collection);
     506           0 :     mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     507             :   }
     508             : 
     509           0 :   Creator creator;
     510           0 :   creator.username = username;
     511           0 :   creator.user_id = user_id;
     512             : 
     513           0 :   if (user_id != -1) {
     514           0 :     _return = creator;
     515             :   }
     516             : 
     517             :   memcached_client =
     518           0 :       memcached_pool_pop(_memcached_client_pool, true, &memcached_rc);
     519           0 :   if (memcached_client) {
     520           0 :     if (user_id != -1 && !cached) {
     521           0 :       auto id_set_span = opentracing::Tracer::Global()->StartSpan(
     522           0 :           "user_mmc_set_cilent", {opentracing::ChildOf(&span->context())});
     523           0 :       std::string user_id_str = std::to_string(user_id);
     524             :       memcached_rc =
     525           0 :           memcached_set(memcached_client, (username + ":user_id").c_str(),
     526           0 :                         (username + ":user_id").length(), user_id_str.c_str(),
     527             :                         user_id_str.length(), static_cast<time_t>(0),
     528           0 :                         static_cast<uint32_t>(0));
     529           0 :       id_set_span->Finish();
     530           0 :       if (memcached_rc != MEMCACHED_SUCCESS) {
     531           0 :         LOG(warning) << "Failed to set the user_id of user " << username
     532           0 :                      << " to Memcached: "
     533           0 :                      << memcached_strerror(memcached_client, memcached_rc);
     534             :       }
     535             :     }
     536           0 :     memcached_pool_push(_memcached_client_pool, memcached_client);
     537             :   } else {
     538           0 :     LOG(warning) << "Failed to pop a client from memcached pool";
     539             :   }
     540           0 :   span->Finish();
     541           0 :   LOG(info) << "ComposeCreatorWithUsername completed [req_id=" << req_id << ", username=" << username << "]";
     542           0 : }
     543             : 
     544         200 : void UserHandler::ComposeCreatorWithUserId(
     545             :     Creator &_return, int64_t req_id, int64_t user_id,
     546             :     const std::string &username,
     547             :     const std::map<std::string, std::string> &carrier) {
     548         400 :   LOG(info) << "Received ComposeCreatorWithUserId request [req_id=" << req_id << ", username=" << username << ", user_id=" << user_id << "]";
     549         400 :   TextMapReader reader(carrier);
     550         400 :   std::map<std::string, std::string> writer_text_map;
     551         400 :   TextMapWriter writer(writer_text_map);
     552         400 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
     553         400 :   auto span = opentracing::Tracer::Global()->StartSpan(
     554         800 :       "compose_creator_server", {opentracing::ChildOf(parent_span->get())});
     555         200 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
     556             : 
     557         400 :   Creator creator;
     558         200 :   creator.username = username;
     559         200 :   creator.user_id = user_id;
     560             : 
     561         200 :   _return = creator;
     562             : 
     563         200 :   span->Finish();
     564         400 :   LOG(info) << "ComposeCreatorWithUserId completed [req_id=" << req_id << ", username=" << username << ", user_id=" << user_id << "]";
     565         200 : }
     566             : 
     567           0 : void UserHandler::Login(std::string &_return, int64_t req_id,
     568             :                         const std::string &username,
     569             :                         const std::string &password,
     570             :                         const std::map<std::string, std::string> &carrier) {
     571           0 :   LOG(info) << "Received Login request [req_id=" << req_id << ", username=" << username << "]";
     572           0 :   TextMapReader reader(carrier);
     573           0 :   std::map<std::string, std::string> writer_text_map;
     574           0 :   TextMapWriter writer(writer_text_map);
     575           0 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
     576           0 :   auto span = opentracing::Tracer::Global()->StartSpan(
     577           0 :       "login_server", {opentracing::ChildOf(parent_span->get())});
     578           0 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
     579             : 
     580             :   size_t login_size;
     581             :   uint32_t memcached_flags;
     582             : 
     583             :   memcached_return_t memcached_rc;
     584             :   memcached_st *memcached_client =
     585           0 :       memcached_pool_pop(_memcached_client_pool, true, &memcached_rc);
     586             :   char *login_mmc;
     587           0 :   if (!memcached_client) {
     588           0 :     LOG(warning) << "Failed to pop a client from memcached pool";
     589             :   } else {
     590           0 :     auto get_login_span = opentracing::Tracer::Global()->StartSpan(
     591           0 :         "user_mmc_get_client", {opentracing::ChildOf(&span->context())});
     592           0 :     login_mmc = memcached_get(memcached_client, (username + ":login").c_str(),
     593           0 :                               (username + ":login").length(), &login_size,
     594           0 :                               &memcached_flags, &memcached_rc);
     595           0 :     get_login_span->Finish();
     596           0 :     if (!login_mmc && memcached_rc != MEMCACHED_NOTFOUND) {
     597           0 :       LOG(warning) << "Memcached error: "
     598           0 :                    << memcached_strerror(memcached_client, memcached_rc);
     599             :     }
     600           0 :     memcached_pool_push(_memcached_client_pool, memcached_client);
     601             :   }
     602             : 
     603           0 :   std::string password_stored;
     604           0 :   std::string salt_stored;
     605           0 :   int64_t user_id_stored = -1;
     606           0 :   bool cached = false;
     607           0 :   json login_json;
     608             : 
     609           0 :   if (login_mmc) {
     610             :     // If not cached in memcached
     611           0 :     LOG(debug) << "Found username: " << username << " in Memcached";
     612           0 :     login_json = json::parse(std::string(login_mmc, login_size));
     613           0 :     password_stored = login_json["password"];
     614           0 :     salt_stored = login_json["salt"];
     615           0 :     user_id_stored = login_json["user_id"];
     616           0 :     cached = true;
     617           0 :     free(login_mmc);
     618             :   }
     619             : 
     620             :   else {
     621             :     // If not cached in memcached
     622           0 :     LOG(debug) << "Username: " << username << " NOT cached in Memcached";
     623             : 
     624             :     mongoc_client_t *mongodb_client =
     625           0 :         mongoc_client_pool_pop(_mongodb_client_pool);
     626           0 :     if (!mongodb_client) {
     627           0 :       ServiceException se;
     628           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     629           0 :       se.message = "Failed to pop a client from MongoDB pool";
     630           0 :       throw se;
     631             :     }
     632             :     auto collection =
     633           0 :         mongoc_client_get_collection(mongodb_client, "user", "user");
     634           0 :     if (!collection) {
     635           0 :       ServiceException se;
     636           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     637           0 :       se.message = "Failed to create collection user from DB user";
     638           0 :       throw se;
     639             :     }
     640           0 :     bson_t *query = bson_new();
     641           0 :     BSON_APPEND_UTF8(query, "username", username.c_str());
     642             : 
     643           0 :     auto find_span = opentracing::Tracer::Global()->StartSpan(
     644           0 :         "user_mongo_find_client", {opentracing::ChildOf(&span->context())});
     645             :     mongoc_cursor_t *cursor =
     646           0 :         mongoc_collection_find_with_opts(collection, query, nullptr, nullptr);
     647             :     const bson_t *doc;
     648           0 :     bool found = mongoc_cursor_next(cursor, &doc);
     649           0 :     find_span->Finish();
     650             : 
     651             :     bson_error_t error;
     652           0 :     if (mongoc_cursor_error(cursor, &error)) {
     653           0 :       LOG(error) << error.message;
     654           0 :       bson_destroy(query);
     655           0 :       mongoc_cursor_destroy(cursor);
     656           0 :       mongoc_collection_destroy(collection);
     657           0 :       mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     658           0 :       ServiceException se;
     659           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     660           0 :       se.message = error.message;
     661           0 :       throw se;
     662             :     }
     663             : 
     664           0 :     if (!found) {
     665           0 :       LOG(warning) << "User: " << username << " doesn't exist in MongoDB";
     666           0 :       bson_destroy(query);
     667           0 :       mongoc_cursor_destroy(cursor);
     668           0 :       mongoc_collection_destroy(collection);
     669           0 :       mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     670           0 :       ServiceException se;
     671           0 :       se.errorCode = ErrorCode::SE_UNAUTHORIZED;
     672           0 :       se.message = "User: " + username + " is not registered";
     673           0 :       throw se;
     674             :     } else {
     675           0 :       LOG(debug) << "Username: " << username << " found in MongoDB";
     676             :       bson_iter_t iter_password;
     677             :       bson_iter_t iter_salt;
     678             :       bson_iter_t iter_user_id;
     679           0 :       if (bson_iter_init_find(&iter_password, doc, "password") &&
     680           0 :           bson_iter_init_find(&iter_salt, doc, "salt") &&
     681           0 :           bson_iter_init_find(&iter_user_id, doc, "user_id")) {
     682           0 :         password_stored = bson_iter_value(&iter_password)->value.v_utf8.str;
     683           0 :         salt_stored = bson_iter_value(&iter_salt)->value.v_utf8.str;
     684           0 :         user_id_stored = bson_iter_value(&iter_user_id)->value.v_int64;
     685           0 :         login_json["password"] = password_stored;
     686           0 :         login_json["salt"] = salt_stored;
     687           0 :         login_json["user_id"] = user_id_stored;
     688             :       } else {
     689           0 :         LOG(error) << "user: " << username << " entry is NOT complete";
     690           0 :         bson_destroy(query);
     691           0 :         mongoc_cursor_destroy(cursor);
     692           0 :         mongoc_collection_destroy(collection);
     693           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     694           0 :         ServiceException se;
     695           0 :         se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     696           0 :         se.message = "user: " + username + " entry is NOT complete";
     697           0 :         throw se;
     698             :       }
     699           0 :       bson_destroy(query);
     700           0 :       mongoc_cursor_destroy(cursor);
     701           0 :       mongoc_collection_destroy(collection);
     702           0 :       mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     703             :     }
     704             :   }
     705             : 
     706           0 :   if (user_id_stored != -1 && !salt_stored.empty() &&
     707           0 :       !password_stored.empty()) {
     708             :     bool auth =
     709           0 :         picosha2::hash256_hex_string(password + salt_stored) == password_stored;
     710           0 :     if (auth) {
     711           0 :       auto user_id_str = std::to_string(user_id_stored);
     712             :       auto timestamp_str = std::to_string(
     713           0 :           duration_cast<seconds>(system_clock::now().time_since_epoch())
     714           0 :               .count());
     715           0 :       jwt::jwt_object obj{algorithm("HS256"), secret(_secret),
     716           0 :                           payload({{"user_id", user_id_str},
     717             :                                    {"username", username},
     718             :                                    {"timestamp", timestamp_str},
     719           0 :                                    {"ttl", "3600"}})};
     720           0 :       _return = obj.signature();
     721             :     } else {
     722           0 :       ServiceException se;
     723           0 :       se.errorCode = ErrorCode::SE_UNAUTHORIZED;
     724           0 :       se.message = "Incorrect username or password";
     725           0 :       throw se;
     726             :     }
     727             :   } else {
     728           0 :     ServiceException se;
     729           0 :     se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     730           0 :     se.message = "Username: " + username + " incomplete login information.";
     731           0 :     throw se;
     732             :   }
     733             : 
     734           0 :   if (!cached) {
     735             :     memcached_client =
     736           0 :         memcached_pool_pop(_memcached_client_pool, true, &memcached_rc);
     737           0 :     if (!memcached_client) {
     738           0 :       LOG(warning) << "Failed to pop a client from memcached pool";
     739             :     } else {
     740           0 :       auto set_login_span = opentracing::Tracer::Global()->StartSpan(
     741           0 :           "user_mmc_set_client", {opentracing::ChildOf(&span->context())});
     742           0 :       std::string login_str = login_json.dump();
     743             :       memcached_rc =
     744           0 :           memcached_set(memcached_client, (username + ":login").c_str(),
     745           0 :                         (username + ":login").length(), login_str.c_str(),
     746           0 :                         login_str.length(), 0, 0);
     747           0 :       set_login_span->Finish();
     748           0 :       if (memcached_rc != MEMCACHED_SUCCESS) {
     749           0 :         LOG(warning) << "Failed to set the login info of user " << username
     750           0 :                      << " to Memcached: "
     751           0 :                      << memcached_strerror(memcached_client, memcached_rc);
     752             :       }
     753           0 :       memcached_pool_push(_memcached_client_pool, memcached_client);
     754             :     }
     755             :   }
     756           0 :   span->Finish();
     757           0 :   LOG(info) << "Login completed [req_id=" << req_id << ", username=" << username << "]";
     758           0 : }
     759       75167 : int64_t UserHandler::GetUserId(
     760             :     int64_t req_id, const std::string &username,
     761             :     const std::map<std::string, std::string> &carrier) {
     762      150390 :   LOG(info) << "Received GetUserId request [req_id=" << req_id << ", username=" << username << "]";
     763      150479 :   TextMapReader reader(carrier);
     764      150478 :   std::map<std::string, std::string> writer_text_map;
     765      150474 :   TextMapWriter writer(writer_text_map);
     766      150482 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
     767      150455 :   auto span = opentracing::Tracer::Global()->StartSpan(
     768      300955 :       "get_user_id_server", {opentracing::ChildOf(parent_span->get())});
     769       75215 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
     770             : 
     771             :   size_t user_id_size;
     772             :   uint32_t memcached_flags;
     773             : 
     774             :   memcached_return_t memcached_rc;
     775             :   memcached_st *memcached_client =
     776       75227 :       memcached_pool_pop(_memcached_client_pool, true, &memcached_rc);
     777             :   char *user_id_mmc;
     778       75246 :   if (memcached_client) {
     779      150460 :     auto id_get_span = opentracing::Tracer::Global()->StartSpan(
     780             :         "user_mmc_get_user_id_client",
     781      300970 :         {opentracing::ChildOf(&span->context())});
     782             :     user_id_mmc =
     783      150448 :         memcached_get(memcached_client, (username + ":user_id").c_str(),
     784      150468 :                       (username + ":user_id").length(), &user_id_size,
     785       75236 :                       &memcached_flags, &memcached_rc);
     786       75240 :     id_get_span->Finish();
     787       75192 :     if (!user_id_mmc && memcached_rc != MEMCACHED_NOTFOUND) {
     788           0 :       ServiceException se;
     789           0 :       se.errorCode = ErrorCode::SE_MEMCACHED_ERROR;
     790           0 :       se.message = memcached_strerror(memcached_client, memcached_rc);
     791           0 :       memcached_pool_push(_memcached_client_pool, memcached_client);
     792           0 :       throw se;
     793             :     }
     794       75192 :     memcached_pool_push(_memcached_client_pool, memcached_client);
     795             :   } else {
     796           0 :     LOG(warning) << "Failed to pop a client from memcached pool";
     797             :   }
     798             : 
     799       75231 :   int64_t user_id = -1;
     800       75231 :   bool cached = false;
     801       75231 :   if (user_id_mmc) {
     802       74049 :     cached = true;
     803       74049 :     LOG(debug) << "Found user_id of username :" << username << " in Memcached";
     804       74023 :     user_id = std::stoul(user_id_mmc);
     805       74056 :     free(user_id_mmc);
     806             :   } else {
     807             :     // If not cached in memcached
     808        1182 :     LOG(debug) << "user_id not cached in Memcached";
     809             :     mongoc_client_t *mongodb_client =
     810        1182 :         mongoc_client_pool_pop(_mongodb_client_pool);
     811        1182 :     if (!mongodb_client) {
     812           0 :       ServiceException se;
     813           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     814           0 :       se.message = "Failed to pop a client from MongoDB pool";
     815           0 :       throw se;
     816             :     }
     817             :     auto collection =
     818        1182 :         mongoc_client_get_collection(mongodb_client, "user", "user");
     819        1182 :     if (!collection) {
     820           0 :       ServiceException se;
     821           0 :       se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     822           0 :       se.message = "Failed to create collection user from DB user";
     823           0 :       throw se;
     824             :     }
     825        1182 :     bson_t *query = bson_new();
     826        1182 :     BSON_APPEND_UTF8(query, "username", username.c_str());
     827             : 
     828        2364 :     auto find_span = opentracing::Tracer::Global()->StartSpan(
     829        4728 :         "user_mongo_find_client", {opentracing::ChildOf(&span->context())});
     830             :     mongoc_cursor_t *cursor =
     831        1182 :         mongoc_collection_find_with_opts(collection, query, nullptr, nullptr);
     832             :     const bson_t *doc;
     833        1182 :     bool found = mongoc_cursor_next(cursor, &doc);
     834        1182 :     find_span->Finish();
     835        1182 :     if (!found) {
     836             :       bson_error_t error;
     837           0 :       if (mongoc_cursor_error(cursor, &error)) {
     838           0 :         LOG(error) << error.message;
     839           0 :         bson_destroy(query);
     840           0 :         mongoc_cursor_destroy(cursor);
     841           0 :         mongoc_collection_destroy(collection);
     842           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     843           0 :         ServiceException se;
     844           0 :         se.errorCode = ErrorCode::SE_MONGODB_ERROR;
     845           0 :         se.message = error.message;
     846           0 :         throw se;
     847             :       } else {
     848           0 :         LOG(warning) << "User: " << username << " doesn't exist in MongoDB";
     849           0 :         bson_destroy(query);
     850           0 :         mongoc_cursor_destroy(cursor);
     851           0 :         mongoc_collection_destroy(collection);
     852           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     853           0 :         ServiceException se;
     854           0 :         se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     855           0 :         se.message = "User: " + username + " is not registered";
     856           0 :         throw se;
     857             :       }
     858             :     } else {
     859        1182 :       LOG(debug) << "User: " << username << " found in MongoDB";
     860             :       bson_iter_t iter;
     861        1181 :       if (bson_iter_init_find(&iter, doc, "user_id")) {
     862        1181 :         user_id = bson_iter_value(&iter)->value.v_int64;
     863             :       } else {
     864           0 :         LOG(error) << "user_id attribute of user " << username
     865           0 :                    << " was not found in the User object";
     866           0 :         bson_destroy(query);
     867           0 :         mongoc_cursor_destroy(cursor);
     868           0 :         mongoc_collection_destroy(collection);
     869           0 :         mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     870           0 :         ServiceException se;
     871           0 :         se.errorCode = ErrorCode::SE_THRIFT_HANDLER_ERROR;
     872           0 :         se.message = "user_id attribute of user: " + username +
     873           0 :                      " was not found in the User object";
     874           0 :         throw se;
     875             :       }
     876             :     }
     877        1182 :     bson_destroy(query);
     878        1181 :     mongoc_cursor_destroy(cursor);
     879        1182 :     mongoc_collection_destroy(collection);
     880        1182 :     mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
     881             :   }
     882             : 
     883       75237 :   if (!cached) {
     884             :     memcached_client =
     885        1181 :         memcached_pool_pop(_memcached_client_pool, true, &memcached_rc);
     886        1182 :     if (!memcached_client) {
     887           0 :       LOG(warning) << "Failed to pop a client from memcached pool";
     888             :     } else {
     889        2364 :       std::string user_id_str = std::to_string(user_id);
     890        2364 :       auto set_login_span = opentracing::Tracer::Global()->StartSpan(
     891        4728 :           "user_mmc_set_client", {opentracing::ChildOf(&span->context())});
     892             :       memcached_rc =
     893        3545 :           memcached_set(memcached_client, (username + ":user_id").c_str(),
     894        2364 :                         (username + ":user_id").length(), user_id_str.c_str(),
     895        1182 :                         user_id_str.length(), 0, 0);
     896        1182 :       set_login_span->Finish();
     897        1181 :       if (memcached_rc != MEMCACHED_SUCCESS) {
     898           0 :         LOG(warning) << "Failed to set the login info of user " << username
     899           0 :                      << " to Memcached: "
     900           0 :                      << memcached_strerror(memcached_client, memcached_rc);
     901             :       }
     902        1181 :       memcached_pool_push(_memcached_client_pool, memcached_client);
     903             :     }
     904             :   }
     905             : 
     906       75238 :   span->Finish();
     907      150425 :   LOG(info) << "GetUserId completed [req_id=" << req_id << ", username=" << username << "]";
     908      150481 :   return user_id;
     909             : }
     910             : 
     911             : /*
     912             :  * The following code which obtaines machine ID from machine's MAC address was
     913             :  * inspired from https://stackoverflow.com/a/16859693.
     914             :  *
     915             :  * MAC address is obtained from /sys/class/net/<netif>/address
     916             :  */
     917           1 : u_int16_t HashMacAddressPid(const std::string &mac) {
     918           1 :   u_int16_t hash = 0;
     919           2 :   std::string mac_pid = mac + std::to_string(getpid());
     920          19 :   for (unsigned int i = 0; i < mac_pid.size(); i++) {
     921          18 :     hash += (mac[i] << ((i & 1) * 8));
     922             :   }
     923           2 :   return hash;
     924             : }
     925             : 
     926           1 : std::string GetMachineId(std::string &netif) {
     927           2 :   std::string mac_hash;
     928             : 
     929           2 :   std::string mac_addr_filename = "/sys/class/net/" + netif + "/address";
     930           2 :   std::ifstream mac_addr_file;
     931           1 :   mac_addr_file.open(mac_addr_filename);
     932           1 :   if (!mac_addr_file) {
     933           0 :     LOG(fatal) << "Cannot read MAC address from net interface " << netif;
     934           0 :     return "";
     935             :   }
     936           2 :   std::string mac;
     937           1 :   mac_addr_file >> mac;
     938           1 :   if (mac == "") {
     939           0 :     LOG(fatal) << "Cannot read MAC address from net interface " << netif;
     940           0 :     return "";
     941             :   }
     942           1 :   mac_addr_file.close();
     943             : 
     944           2 :   LOG(info) << "MAC address = " << mac;
     945             : 
     946           2 :   std::stringstream stream;
     947           1 :   stream << std::hex << HashMacAddressPid(mac);
     948           1 :   mac_hash = stream.str();
     949             : 
     950           1 :   if (mac_hash.size() > 3) {
     951           1 :     mac_hash.erase(0, mac_hash.size() - 3);
     952           0 :   } else if (mac_hash.size() < 3) {
     953           0 :     mac_hash = std::string(3 - mac_hash.size(), '0') + mac_hash;
     954             :   }
     955           1 :   return mac_hash;
     956             : }
     957             : }  // namespace social_network
     958             : 
     959             : #endif  // SOCIAL_NETWORK_MICROSERVICES_USERHANDLER_H

Generated by: LCOV version 1.12