Line data Source code
1 : #ifndef SOCIAL_NETWORK_MICROSERVICES_SRC_URLSHORTENSERVICE_URLSHORTENHANDLER_H_
2 : #define SOCIAL_NETWORK_MICROSERVICES_SRC_URLSHORTENSERVICE_URLSHORTENHANDLER_H_
3 :
4 : #include <random>
5 : #include <chrono>
6 : #include <future>
7 :
8 : #include <mongoc.h>
9 : #include <libmemcached/memcached.h>
10 : #include <libmemcached/util.h>
11 : #include <bson/bson.h>
12 :
13 : #include "../../gen-cpp/UrlShortenService.h"
14 : #include "../../gen-cpp/social_network_types.h"
15 : #include "../logger.h"
16 : #include "../tracing.h"
17 :
18 : #define HOSTNAME "http://short-url/"
19 :
20 : namespace social_network {
21 :
22 : class UrlShortenHandler : public UrlShortenServiceIf {
23 : public:
24 : UrlShortenHandler(memcached_pool_st *, mongoc_client_pool_t *, std::mutex *);
25 0 : ~UrlShortenHandler() override = default;
26 :
27 : void ComposeUrls(std::vector<Url> &, int64_t,
28 : const std::vector<std::string> &,
29 : const std::map<std::string, std::string> &) override;
30 :
31 : void GetExtendedUrls(std::vector<std::string> &, int64_t,
32 : const std::vector<std::string> &,
33 : const std::map<std::string, std::string> &) override ;
34 :
35 : private:
36 : memcached_pool_st *_memcached_client_pool;
37 : mongoc_client_pool_t *_mongodb_client_pool;
38 : static std::mt19937 _generator;
39 : std::uniform_int_distribution<int> _distribution;
40 : std::string _GenRandomStr(int length);
41 : std::mutex *_thread_lock;
42 : };
43 :
44 2 : std::mt19937 UrlShortenHandler::_generator = std::mt19937(std::chrono::duration_cast<std::chrono::milliseconds>(
45 3 : std::chrono::system_clock::now().time_since_epoch()).count() % 0xffffffff);
46 :
47 1 : UrlShortenHandler::UrlShortenHandler(
48 : memcached_pool_st *memcached_client_pool,
49 : mongoc_client_pool_t *mongodb_client_pool,
50 1 : std::mutex *thread_lock) {
51 1 : _memcached_client_pool = memcached_client_pool;
52 1 : _mongodb_client_pool = mongodb_client_pool;
53 1 : _thread_lock = thread_lock;
54 1 : _distribution = std::uniform_int_distribution<int>(0, 61);
55 1 : }
56 :
57 0 : std::string UrlShortenHandler::_GenRandomStr(int length) {
58 : const char char_map[] = "abcdefghijklmnopqrstuvwxyzABCDEF"
59 0 : "GHIJKLMNOPQRSTUVWXYZ0123456789";
60 0 : std::string return_str;
61 0 : _thread_lock->lock();
62 0 : for (int i = 0; i < length; ++i) {
63 0 : return_str.append(1, char_map[_distribution(_generator)]);
64 : }
65 0 : _thread_lock->unlock();
66 0 : return return_str;
67 : }
68 0 : void UrlShortenHandler::ComposeUrls(
69 : std::vector<Url> &_return,
70 : int64_t req_id,
71 : const std::vector<std::string> &urls,
72 : const std::map<std::string, std::string> &carrier) {
73 :
74 : // 新增:记录收到的 ComposeUrls 请求
75 0 : LOG(info) << "Received ComposeUrls request [req_id=" << req_id << ", url count=" << urls.size() << "]";
76 :
77 : // Initialize a span
78 0 : TextMapReader reader(carrier);
79 0 : std::map<std::string, std::string> writer_text_map;
80 0 : TextMapWriter writer(writer_text_map);
81 0 : auto parent_span = opentracing::Tracer::Global()->Extract(reader);
82 0 : auto span = opentracing::Tracer::Global()->StartSpan(
83 : "compose_urls_server",
84 0 : { opentracing::ChildOf(parent_span->get()) });
85 0 : opentracing::Tracer::Global()->Inject(span->context(), writer);
86 :
87 0 : std::vector<Url> target_urls;
88 0 : std::future<void> mongo_future;
89 :
90 0 : if (!urls.empty()) {
91 0 : for (auto &url : urls) {
92 0 : Url new_target_url;
93 0 : new_target_url.expanded_url = url;
94 0 : new_target_url.shortened_url = HOSTNAME +
95 0 : _GenRandomStr(10);
96 0 : target_urls.emplace_back(new_target_url);
97 : }
98 : // 新增:记录生成的短链数量
99 0 : LOG(info) << "Generated short urls [req_id=" << req_id << ", count=" << target_urls.size() << "]";
100 :
101 0 : mongo_future = std::async(
102 0 : std::launch::async, [&](){
103 0 : mongoc_client_t *mongodb_client = mongoc_client_pool_pop(
104 0 : _mongodb_client_pool);
105 0 : if (!mongodb_client) {
106 0 : ServiceException se;
107 0 : se.errorCode = ErrorCode::SE_MONGODB_ERROR;
108 0 : se.message = "Failed to pop a client from MongoDB pool";
109 0 : throw se;
110 : }
111 : auto collection = mongoc_client_get_collection(
112 0 : mongodb_client, "url-shorten", "url-shorten");
113 0 : if (!collection) {
114 0 : ServiceException se;
115 0 : se.errorCode = ErrorCode::SE_MONGODB_ERROR;
116 0 : se.message = "Failed to create collection user from DB user";
117 0 : mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
118 0 : throw se;
119 : }
120 :
121 0 : auto mongo_span = opentracing::Tracer::Global()->StartSpan(
122 : "url_mongo_insert_client",
123 0 : { opentracing::ChildOf(&span->context()) });
124 :
125 : mongoc_bulk_operation_t *bulk;
126 : bson_t *doc;
127 : bson_error_t error;
128 : bson_t reply;
129 : bool ret;
130 : bulk = mongoc_collection_create_bulk_operation_with_opts(
131 0 : collection, nullptr);
132 0 : for (auto &url : target_urls) {
133 0 : doc = bson_new();
134 0 : BSON_APPEND_UTF8(doc, "shortened_url", url.shortened_url.c_str());
135 0 : BSON_APPEND_UTF8(doc, "expanded_url", url.expanded_url.c_str());
136 0 : mongoc_bulk_operation_insert (bulk, doc);
137 0 : bson_destroy(doc);
138 : }
139 0 : ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
140 0 : if (!ret) {
141 0 : LOG(error) << "MongoDB error: "<< error.message;
142 0 : ServiceException se;
143 0 : se.errorCode = ErrorCode::SE_MONGODB_ERROR;
144 0 : se.message = "Failed to insert urls to MongoDB";
145 0 : bson_destroy (&reply);
146 0 : mongoc_bulk_operation_destroy(bulk);
147 0 : mongoc_collection_destroy(collection);
148 0 : mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
149 0 : throw se;
150 : }
151 0 : bson_destroy (&reply);
152 0 : mongoc_bulk_operation_destroy(bulk);
153 0 : mongoc_collection_destroy(collection);
154 0 : mongoc_client_pool_push(_mongodb_client_pool, mongodb_client);
155 0 : mongo_span->Finish();
156 : // 新增:成功写入MongoDB日志
157 0 : LOG(info) << "Short urls inserted into MongoDB successfully [req_id=" << req_id << ", count=" << target_urls.size() << "]";
158 0 : });
159 :
160 : }
161 :
162 0 : if (!urls.empty()) {
163 : try {
164 0 : mongo_future.get();
165 0 : } catch (...) {
166 0 : LOG(error) << "Failed to upload shortened urls from MongoDB";
167 0 : throw;
168 : }
169 : }
170 :
171 0 : _return = target_urls;
172 :
173 : // 新增:方法结束日志
174 0 : LOG(info) << "ComposeUrls completed [req_id=" << req_id << ", return count=" << _return.size() << "]";
175 :
176 0 : span->Finish();
177 :
178 0 : }
179 :
180 0 : void UrlShortenHandler::GetExtendedUrls(
181 : std::vector<std::string> &_return,
182 : int64_t req_id,
183 : const std::vector<std::string> &shortened_id,
184 : const std::map<std::string, std::string> &carrier) {
185 :
186 : // TODO: Implement GetExtendedUrls
187 0 : }
188 :
189 : }
190 :
191 :
192 :
193 : #endif //SOCIAL_NETWORK_MICROSERVICES_SRC_URLSHORTENSERVICE_URLSHORTENHANDLER_H_
|