仿RabbitMq实现简易消息队列正式篇(路由匹配篇)

时间:2025-04-06 21:49:27
  • #ifndef __M_ROUTE_H_
  • #define __M_ROUTE_H_
  • #include <iostream>
  • #include "../mqcommon/"
  • #include "../mqcommon/"
  • #include "../mqcommon/"
  • namespace mymq
  • {
  • class Router
  • {
  • public:
  • static bool isLegalRoutingKey(const std::string& routing_key)
  • {
  • // routing_key: 不需要判断是否包含有非法字符即可,合法字符(a ~ z, A ~ Z, 0 ~ 9, ....)
  • for(auto& ch : routing_key)
  • {
  • if((ch >= 'a' && ch <= 'z') ||
  • (ch >= 'A' && ch <= 'Z') ||
  • (ch >= '1' && ch <= '9') ||
  • (ch == '_' || ch == '.'))
  • continue;
  • return false;
  • }
  • return true;
  • }
  • static bool isLegalBindingKey(const std::string& binding_key)
  • {
  • for(auto& ch : binding_key)
  • {
  • if((ch >= 'a' && ch <= 'z') ||
  • (ch >= 'A' && ch <= 'Z') ||
  • (ch >= '1' && ch <= '9') ||
  • (ch == '_' || ch == '.') ||
  • (ch == '#' || ch == '*'))
  • continue;
  • return false;
  • }
  • // 2. * 和 # 必须独立存在
  • std::vector<std::string> sub_word;
  • StrHelper::split(binding_key, ".", sub_word);
  • for(std::string& word : sub_word)
  • {
  • if((word.size() > 1) && (("*") != std::string::npos && (("#") != std::string::npos)))
  • {
  • return false;
  • }
  • }
  • // 3. * 和 # 不能连续出现
  • for(int i = 1; i < sub_word.size(); i++)
  • {
  • if(sub_word[i] == "*" && sub_word[i - 1] == "#")
  • {
  • return false;
  • }
  • if(sub_word[i] == "#" && sub_word[i - 1] == "#")
  • {
  • return false;
  • }
  • if(sub_word[i] == "#" && sub_word[i - 1] == "*")
  • {
  • return false;
  • }
  • }
  • return true;
  • }
  • static bool route(ExchangeType type, const std::string& routing_key, const std::string& binding_key)
  • {
  • if(type == ExchangeType::DIRECT)
  • {
  • return (routing_key == binding_key);
  • }
  • else if(type == ExchangeType::FANOUT)
  • {
  • return true;
  • }
  • // 主题交换 : 要进行模式匹配 :
  • // 1. 将 binding_key 与 routing_key 进行字符串分割,得到各个单词数组
  • std::vector<std::string> bkeys, rkeys;
  • int n_rkeys = StrHelper::split(routing_key, ".", rkeys);
  • int n_bkeys = StrHelper::split(binding_key, ".", bkeys);
  • // 2. 定义标记数组, 并初始化[0][0]位置为true, 其他位置为false
  • std::vector<std::vector<bool>> dp(n_bkeys + 1, std::vector<bool>(n_rkeys + 1));
  • dp[0][0] = true;
  • //3. 如果binding_key以#开始,则将#对应的第0行全部为1
  • for(int i = 1; i < n_bkeys; i++)
  • {
  • if(bkeys[i - 1] == "#")
  • {
  • dp[i][0] = true;
  • continue;
  • }
  • break;
  • }
  • // 4. 使用routing_key中的每个单词与binding_key中的每个单词进行匹配并标记数组
  • for(int i = 1; i < n_bkeys + 1; i++)
  • {
  • for(int j = 1; j < n_rkeys + 1; j++)
  • {
  • if(bkeys[i - 1] == rkeys[j - 1] || bkeys[i - 1] == "*")
  • {
  • dp[i][j] = dp[i - 1][j - 1];
  • }
  • else if(bkeys[i - 1] == "#")
  • {
  • dp[i][j] = dp[i - 1][j - 1] | dp[i][j - 1] | dp[i - 1][j];
  • }
  • }
  • }
  • return dp[n_bkeys][n_rkeys];
  • }
  • };
  • }
  • #endif