LCOV - code coverage report
Current view: top level - src/TextService - TextHandler.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 70 108 64.8 %
Date: 2025-11-04 00:23:49 Functions: 4 6 66.7 %

          Line data    Source code
       1             : #ifndef SOCIAL_NETWORK_MICROSERVICES_TEXTHANDLER_H
       2             : #define SOCIAL_NETWORK_MICROSERVICES_TEXTHANDLER_H
       3             : 
       4             : #include <future>
       5             : #include <iostream>
       6             : #include <regex>
       7             : #include <string>
       8             : 
       9             : #include "../../gen-cpp/TextService.h"
      10             : #include "../../gen-cpp/UrlShortenService.h"
      11             : #include "../../gen-cpp/UserMentionService.h"
      12             : #include "../ClientPool.h"
      13             : #include "../ThriftClient.h"
      14             : #include "../logger.h"
      15             : #include "../tracing.h"
      16             : 
      17             : namespace social_network {
      18             : 
      19             : class TextHandler : public TextServiceIf {
      20             :  public:
      21             :   TextHandler(ClientPool<ThriftClient<UrlShortenServiceClient>> *,
      22             :               ClientPool<ThriftClient<UserMentionServiceClient>> *);
      23           0 :   ~TextHandler() override = default;
      24             : 
      25             :   void ComposeText(TextServiceReturn &_return, int64_t, const std::string &,
      26             :                    const std::map<std::string, std::string> &) override;
      27             : 
      28             :  private:
      29             :   ClientPool<ThriftClient<UrlShortenServiceClient>> *_url_client_pool;
      30             :   ClientPool<ThriftClient<UserMentionServiceClient>> *_user_mention_client_pool;
      31             : };
      32             : 
      33           1 : TextHandler::TextHandler(
      34             :     ClientPool<ThriftClient<UrlShortenServiceClient>> *url_client_pool,
      35             :     ClientPool<ThriftClient<UserMentionServiceClient>>
      36           1 :         *user_mention_client_pool) {
      37           1 :   _url_client_pool = url_client_pool;
      38           1 :   _user_mention_client_pool = user_mention_client_pool;
      39           1 : }
      40             : 
      41         200 : void TextHandler::ComposeText(
      42             :     TextServiceReturn &_return, int64_t req_id, const std::string &text,
      43             :     const std::map<std::string, std::string> &carrier) {
      44             :   // 新增:记录收到的 ComposeText 请求
      45         400 :   LOG(info) << "Received ComposeText request [req_id=" << req_id << ", text length=" << text.length() << "]";
      46             : 
      47             :   // Initialize a span
      48         400 :   TextMapReader reader(carrier);
      49         400 :   std::map<std::string, std::string> writer_text_map;
      50         400 :   TextMapWriter writer(writer_text_map);
      51         400 :   auto parent_span = opentracing::Tracer::Global()->Extract(reader);
      52         400 :   auto span = opentracing::Tracer::Global()->StartSpan(
      53         800 :       "compose_text_server", {opentracing::ChildOf(parent_span->get())});
      54         200 :   opentracing::Tracer::Global()->Inject(span->context(), writer);
      55             : 
      56         400 :   std::vector<std::string> mention_usernames;
      57         400 :   std::smatch m;
      58         400 :   std::regex e("@[a-zA-Z0-9-_]+");
      59         400 :   auto s = text;
      60         200 :   while (std::regex_search(s, m, e)) {
      61           0 :     auto user_mention = m.str();
      62           0 :     user_mention = user_mention.substr(1, user_mention.length());
      63           0 :     mention_usernames.emplace_back(user_mention);
      64           0 :     s = m.suffix().str();
      65             :   }
      66             : 
      67         400 :   std::vector<std::string> urls;
      68         200 :   e = "(http://|https://)([a-zA-Z0-9_!~*'().&=+$%-]+)";
      69         200 :   s = text;
      70         200 :   while (std::regex_search(s, m, e)) {
      71           0 :     auto url = m.str();
      72           0 :     urls.emplace_back(url);
      73           0 :     s = m.suffix().str();
      74             :   }
      75             : 
      76             :   // 新增:记录提取到的 @用户 和 URL 数量
      77         400 :   LOG(info) << "Extracted mentions and urls [req_id=" << req_id << ", mention count=" << mention_usernames.size() << ", url count=" << urls.size() << "]";
      78             : 
      79         200 :   auto shortened_urls_future = std::async(std::launch::async, [&]() {
      80         400 :     auto url_span = opentracing::Tracer::Global()->StartSpan(
      81         800 :         "compose_urls_client", {opentracing::ChildOf(&span->context())});
      82             : 
      83         400 :     std::map<std::string, std::string> url_writer_text_map;
      84         400 :     TextMapWriter url_writer(url_writer_text_map);
      85         200 :     opentracing::Tracer::Global()->Inject(url_span->context(), url_writer);
      86             : 
      87         400 :     auto url_client_wrapper = _url_client_pool->Pop();
      88         200 :     if (!url_client_wrapper) {
      89           0 :       ServiceException se;
      90           0 :       se.errorCode = ErrorCode::SE_THRIFT_CONN_ERROR;
      91           0 :       se.message = "Failed to connect to url-shorten-service";
      92           0 :       throw se;
      93             :     }
      94         200 :     std::vector<Url> _return_urls;
      95         200 :     auto url_client = url_client_wrapper->GetClient();
      96             :     try {
      97         600 :       url_client->ComposeUrls(_return_urls, req_id, urls, url_writer_text_map);
      98           0 :     } catch (...) {
      99           0 :       LOG(error) << "Failed to upload urls to url-shorten-service";
     100           0 :       _url_client_pool->Remove(url_client_wrapper);
     101           0 :       throw;
     102             :     }
     103         200 :     _url_client_pool->Keepalive(url_client_wrapper);
     104             :     // 新增:成功调用 url-shortener 服务日志
     105         800 :     LOG(info) << "ComposeUrls to url-shorten-service succeeded [req_id=" << req_id << ", url count=" << urls.size() << "]";
     106         400 :     return _return_urls;
     107         400 :   });
     108             : 
     109         200 :   auto user_mention_future = std::async(std::launch::async, [&]() {
     110         400 :     auto user_mention_span = opentracing::Tracer::Global()->StartSpan(
     111             :         "compose_user_mentions_client",
     112         800 :         {opentracing::ChildOf(&span->context())});
     113             : 
     114         400 :     std::map<std::string, std::string> user_mention_writer_text_map;
     115         400 :     TextMapWriter user_mention_writer(user_mention_writer_text_map);
     116         600 :     opentracing::Tracer::Global()->Inject(user_mention_span->context(),
     117         400 :                                           user_mention_writer);
     118             : 
     119         400 :     auto user_mention_client_wrapper = _user_mention_client_pool->Pop();
     120         200 :     if (!user_mention_client_wrapper) {
     121           0 :       ServiceException se;
     122           0 :       se.errorCode = ErrorCode::SE_THRIFT_CONN_ERROR;
     123           0 :       se.message = "Failed to connect to user-mention-service";
     124           0 :       throw se;
     125             :     }
     126         200 :     std::vector<UserMention> _return_user_mentions;
     127         200 :     auto user_mention_client = user_mention_client_wrapper->GetClient();
     128             :     try {
     129         400 :       user_mention_client->ComposeUserMentions(_return_user_mentions, req_id,
     130         400 :                                                mention_usernames,
     131         400 :                                                user_mention_writer_text_map);
     132           0 :     } catch (...) {
     133           0 :       LOG(error) << "Failed to upload user_mentions to user-mention-service";
     134           0 :       _user_mention_client_pool->Remove(user_mention_client_wrapper);
     135           0 :       throw;
     136             :     }
     137             : 
     138         200 :     _user_mention_client_pool->Keepalive(user_mention_client_wrapper);
     139             :     // 新增:成功调用 user-mention 服务日志
     140         800 :     LOG(info) << "ComposeUserMentions to user-mention-service succeeded [req_id=" << req_id << ", mention count=" << mention_usernames.size() << "]";
     141         400 :     return _return_user_mentions;
     142         400 :   });
     143             : 
     144         400 :   std::vector<Url> target_urls;
     145             :   try {
     146         200 :     target_urls = shortened_urls_future.get();
     147           0 :   } catch (...) {
     148           0 :     LOG(error) << "Failed to get shortened urls from url-shorten-service";
     149           0 :     throw;
     150             :   }
     151             : 
     152         400 :   std::vector<UserMention> user_mentions;
     153             :   try {
     154         200 :     user_mentions = user_mention_future.get();
     155           0 :   } catch (...) {
     156           0 :     LOG(error) << "Failed to upload user mentions to user-mention-service";
     157           0 :     throw;
     158             :   }
     159             : 
     160         400 :   std::string updated_text;
     161         200 :   if (!urls.empty()) {
     162           0 :     s = text;
     163           0 :     int idx = 0;
     164           0 :     while (std::regex_search(s, m, e)) {
     165           0 :       auto url = m.str();
     166           0 :       urls.emplace_back(url);
     167           0 :       updated_text += m.prefix().str() + target_urls[idx].shortened_url;
     168           0 :       s = m.suffix().str();
     169           0 :       idx++;
     170             :     }
     171             :   } else {
     172         200 :     updated_text = text;
     173             :   }
     174             : 
     175         200 :   _return.user_mentions = user_mentions;
     176         200 :   _return.text = updated_text;
     177         200 :   _return.urls = target_urls;
     178             : 
     179             :   // 新增:方法结束日志
     180         400 :   LOG(info) << "ComposeText completed [req_id=" << req_id << ", user_mentions count=" << user_mentions.size() << ", urls count=" << target_urls.size() << "]";
     181             : 
     182         200 :   span->Finish();
     183         200 : }
     184             : 
     185             : }  // namespace social_network
     186             : 
     187             : #endif  // SOCIAL_NETWORK_MICROSERVICES_TEXTHANDLER_H

Generated by: LCOV version 1.12