quaility.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <?php
  2. namespace refill;
  3. use Log;
  4. use mtopcard;
  5. use scope_trace;
  6. class Quality
  7. {
  8. const LowestQuality = 1;
  9. const Normal = 1;
  10. const Quick = 2;
  11. const CardKey = 3;
  12. const ThirdShop = 4;
  13. const SlowTwentyFour = 5;
  14. const SlowSix = 6;
  15. const SlowTwo = 7;
  16. const SlowFortyEight = 8;
  17. const SlowSeventyTwo = 9;
  18. const Fastest = 10;
  19. const HighestQuality = 10;
  20. const SlowNormal = 11; // 7 -> 1
  21. const ThirdNormal = 12; // 4 -> 1
  22. const DefSuccess = 13; // 1 -> 3 -> 2
  23. const NormalQuick = 14;
  24. const SlowSixNormal = 15;
  25. const NormalCardkey = 16;
  26. const NormalQuickCardkey = 17; //1->2->3
  27. const QuickCardkey = 18; //2 -> 3
  28. const CardkeyNormalQuick = 19;
  29. const OilWithoutSN = 1;
  30. const OilQuick = 2;
  31. const OilCardKey = 3;
  32. const OilWithSN = 5;
  33. const OilSN_NONE_HAS = 20;
  34. const OilSN_HAS_NONE = 21;
  35. const OIL_SN_CARDKEY = 22;
  36. const OIL_SNNONE_CARDKEY = 23;
  37. const OIL_SN_SNNONE_CARDKEY = 24;
  38. const OIL_SNNONE_SN_CARDKEY = 25;
  39. const OIL_SNNONE_SN_CARDKEY_QUICK = 26;
  40. protected $mMchPhonectl;
  41. protected $mMchoilctl;
  42. protected $mSpeeds;
  43. protected $mQualities;
  44. protected $mTryAdjuster;
  45. protected $mRatioCtl;
  46. public function __construct()
  47. {
  48. $this->mMchPhonectl = new mchctl();
  49. $this->mMchoilctl = new mchoilctl();
  50. $this->mTryAdjuster = new try_judge();
  51. $this->mRatioCtl = null;
  52. }
  53. public function load()
  54. {
  55. $this->mMchPhonectl->load();
  56. $this->mMchoilctl->load();
  57. $this->mTryAdjuster->load();
  58. }
  59. public function setRatioCtl($ratio_ctl) {
  60. $this->mRatioCtl = $ratio_ctl;
  61. }
  62. public function qualities($quality)
  63. {
  64. if (array_key_exists($quality, $this->mQualities)) {
  65. return $this->mQualities[$quality];
  66. } else {
  67. return [];
  68. }
  69. }
  70. public function mechants_quality() {
  71. return $this->mMchPhonectl->mechants_quality();
  72. }
  73. public function find_quality(order $order, $caller): array
  74. {
  75. $card_type = $order->card_type();
  76. $is_phone = function ($card_type)
  77. {
  78. $types = [mtopcard\ChinaMobileCard, mtopcard\ChinaUnicomCard, mtopcard\ChinaTelecomCard];
  79. if (in_array($card_type, $types)) {
  80. return true;
  81. }
  82. else {
  83. return false;
  84. }
  85. };
  86. $is_oil = function ($card_type)
  87. {
  88. $types = [mtopcard\PetroChinaCard, mtopcard\SinopecCard];
  89. if (in_array($card_type, $types)) {
  90. return true;
  91. }
  92. else {
  93. return false;
  94. }
  95. };
  96. if($is_phone($card_type)) {
  97. return $this->mobile_quality($order);
  98. }
  99. elseif($is_oil($card_type)) {
  100. [$org, $qualities] = $this->oil_quality($order, $caller);
  101. return [$org,$qualities,false];
  102. }
  103. else {
  104. return [0, [],false];
  105. }
  106. }
  107. private function oil_quality(order $order, $caller): array
  108. {
  109. $mchid = $order->mchid();
  110. $quality = $order->org_quality();
  111. $times = $order->commit_times();
  112. $used_time = $order->elapse_secs();
  113. Log::record("oil_quality mchid={$mchid},quality={$quality},times={$times}",Log::DEBUG);
  114. if($quality == 0)
  115. {
  116. [$success,$setting_quality,$time_out] = $this->mMchoilctl->getCtls($mchid);
  117. if($success)
  118. {
  119. if(array_key_exists($setting_quality,$this->mQualities)) {
  120. $org = $setting_quality;
  121. $qualities = $this->mQualities[$setting_quality];
  122. }
  123. else {
  124. $org = $setting_quality;
  125. $qualities = [$setting_quality];
  126. }
  127. }
  128. else {
  129. $org = self::Normal;
  130. $qualities = $this->mQualities[$org];
  131. }
  132. }
  133. elseif(array_key_exists($quality,$this->mQualities)) {
  134. $org = $quality;
  135. $qualities = $this->mQualities[$quality];
  136. }
  137. else {
  138. Log::record("find_quality: cannot find any quality",Log::DEBUG);
  139. return [0,[]];
  140. }
  141. Log::record("oil_quality find qualities = " . implode(',', $qualities), Log::DEBUG);
  142. $qualities = $this->calc_oil_quality($qualities,$times,$used_time,$caller);
  143. $order->set_can_overprice(true, false);
  144. return [$org,$qualities];
  145. }
  146. //通过每种类型通道耗时,倒推当前可用通道,并优先走推荐通道.
  147. private function calc_oil_quality($qualities, $times, $used_time, $caller)
  148. {
  149. $result = [];
  150. if($used_time > 900) {
  151. return $result;
  152. }
  153. $total_times = 0;
  154. foreach ($qualities as $quality)
  155. {
  156. $cur_times = $caller->calc_times($quality);
  157. if($cur_times <= 0) continue;
  158. $total_times += $cur_times;
  159. if($total_times > $times) {
  160. $result[] = $quality;
  161. }
  162. }
  163. Log::record("calc_oil_quality result = " . implode(',',$result),Log::DEBUG);
  164. return $result;
  165. }
  166. private function mobile_quality(order $order): array
  167. {
  168. $mchid = $order->mchid();
  169. $org_quality = $order->org_quality();
  170. if($org_quality == 0)
  171. {
  172. [$success,$setting_quality,$time_out] = $this->mMchPhonectl->getCtls($mchid);
  173. if($success)
  174. {
  175. if (array_key_exists($setting_quality, $this->mQualities)) {
  176. $org_quality = $setting_quality;
  177. } else {
  178. $org_quality = $setting_quality;
  179. }
  180. }
  181. else {
  182. $org_quality = self::Normal; //如果没设置质量,默认为普通
  183. $time_out = $this->mSpeeds[$org_quality]['retry_timeout'];
  184. }
  185. }
  186. elseif(array_key_exists($org_quality,$this->mQualities)) {
  187. [$success, $setting_quality, $time_out] = $this->mMchPhonectl->getCtls($mchid);
  188. }
  189. else {
  190. Log::record("find_quality: cannot find any quality",Log::DEBUG);
  191. return [0,[],false];
  192. }
  193. if($time_out <= 0) {
  194. $time_out = $this->mSpeeds[$org_quality]['retry_timeout'];
  195. }
  196. $qualities = $this->qualities($org_quality);
  197. $max_times = $this->max_times($mchid, $org_quality, $qualities);
  198. if(!empty($qualities)) {
  199. $order->set_first_quality($qualities[0]);
  200. }
  201. //有成功率控制,需要用大数据计算的
  202. if ($this->mRatioCtl->exist($mchid)) {
  203. Log::record("ratio_phone_quality exist=true",Log::DEBUG);
  204. [$qualities, $match_ratio] = $this->ratio_phone_quality($order, $qualities);
  205. return [$org_quality, $qualities, $match_ratio];
  206. } else {
  207. $fMixed = PolicyUtil::mixed_quality($org_quality);
  208. $qualities = $this->calc_phone_quality($order, $qualities, $fMixed, $time_out, $max_times);
  209. return [$org_quality, $qualities, false];
  210. }
  211. }
  212. private function time_checker(order $order, $qualities)
  213. {
  214. $mchid = $order->mchid();
  215. $commit_times = $order->commit_times();
  216. $used_time = $order->elapse_secs();
  217. $ch_filter = $order->filter();
  218. $cur_quality = $order->cur_quality();
  219. $order_time = $order->order_time();
  220. //用于计算
  221. $calc_steps = function ($mchid, $qualities) use ($ch_filter, $order_time)
  222. {
  223. $steps = [];
  224. $cdf = [0,0];
  225. foreach ($qualities as $quality)
  226. {
  227. $qua_times = $this->mRatioCtl->times($mchid, $quality);
  228. $qua_secs = $this->mRatioCtl->seconds($mchid, $quality);
  229. if($qua_times == false || $qua_secs == false) {
  230. continue;
  231. }
  232. $cdf[0] += $qua_times;
  233. $cdf[1] += $qua_secs;
  234. $cdf[2] = $qua_times;
  235. Log::record("ratio_phone_quality time_checker time=$cdf[0] secs=$cdf[1]", Log::DEBUG);
  236. $steps[$quality] = $cdf;
  237. $ch_filter->set_timeout($quality,$order_time + $cdf[1]);
  238. }
  239. return $steps;
  240. };
  241. $calc_usable_qualities = function ($qualities, $steps) use ($cur_quality, $commit_times, $used_time, $ch_filter)
  242. {
  243. $usable = [];
  244. $compare = $cur_quality > 0 ? false : true;
  245. foreach ($qualities as $quality)
  246. {
  247. if($compare == false)
  248. {
  249. if($quality == $cur_quality) {
  250. $compare = true;
  251. }
  252. }
  253. if($compare === false) {
  254. continue;
  255. }
  256. if(!array_key_exists($quality,$steps)) {
  257. continue;
  258. }
  259. [$max_times,$max_secs,$qua_times] = $steps[$quality];
  260. $per_secs = $ch_filter->per_secs($quality);
  261. Log::record("ratio_phone_quality time_checker a per_secs=$per_secs", Log::DEBUG);
  262. if($per_secs == 0) {
  263. $per_secs = $this->mSpeeds[$quality]['per_secs'];
  264. Log::record("ratio_phone_quality time_checker b per_secs=$per_secs", Log::DEBUG);
  265. }
  266. if($max_times > $commit_times and $max_secs > $used_time + $per_secs)
  267. {
  268. [$cur_times,$cur_secs] = $ch_filter->total($quality);
  269. if($qua_times > $cur_times) {
  270. $usable[] = $quality;
  271. }
  272. }
  273. }
  274. return $usable;
  275. };
  276. $steps = $calc_steps($mchid,$qualities);
  277. $matches = $calc_usable_qualities($qualities, $steps);
  278. return $matches;
  279. }
  280. private function ratio_phone_quality(order $order, $all_qualities)
  281. {
  282. $mchid = $order->mchid();
  283. $org_quality = $order->org_quality();
  284. $spec = $order->spec();
  285. $card_type = $order->card_type();
  286. $used_times = $order->commit_times();
  287. $used_time = $order->elapse_secs();
  288. [$succ,$max_times,$time_out] = $this->mRatioCtl->total($mchid,$all_qualities);
  289. $left_time = $time_out - $used_time;
  290. Log::record("left_time=$left_time used_time=$used_time max_times=$max_times used_times=$used_times",Log::DEBUG);
  291. if ($left_time <= 0 || $max_times <= $used_times) {
  292. return [[],false];
  293. }
  294. if (count($all_qualities) == 1) {
  295. Log::record("all_qualities count = 1",Log::DEBUG);
  296. return [$all_qualities, true];
  297. }
  298. $pTryAdjuster = $this->mTryAdjuster;
  299. $timeing_checker = function ($qualities) use($pTryAdjuster,$mchid)
  300. {
  301. foreach ($qualities as $quality)
  302. {
  303. $ret = $pTryAdjuster->can_try($mchid,$quality);
  304. if($ret == false) {
  305. return false;
  306. }
  307. }
  308. return true;
  309. };
  310. $qualities_log = function ($tag,$qualities)
  311. {
  312. $str = implode(',',$qualities);
  313. Log::record("$tag=$str", Log::DEBUG);
  314. };
  315. if($used_times > 0)
  316. {
  317. $qualities_log("ratio_phone_quality $mchid-$card_type-$spec all_qualities", $all_qualities);
  318. [$match_ratio, $can_last] = $this->mRatioCtl->ratio_match($mchid, $org_quality, $card_type, $spec, $all_qualities);
  319. Log::record("ratio_phone_quality mchid=$mchid must calc next quality match_ratio=$match_ratio can_last=$can_last", Log::DEBUG);
  320. $order->set_can_overprice($match_ratio,$can_last);
  321. $pre_qualities = $this->time_checker($order, $all_qualities);
  322. $qualities_log("ratio_phone_quality $mchid-$card_type-$spec usable_qualities",$pre_qualities);
  323. if (!$timeing_checker($pre_qualities)) {
  324. $pre_qualities = [];
  325. Log::record("calc_quality timeing_checker result is empty", Log::DEBUG);
  326. }
  327. $qualities_log("ratio_phone_quality $mchid-$card_type-$spec after timeing_checker qualities", $pre_qualities);
  328. $cur_qualities = $pre_qualities;
  329. }
  330. else {
  331. $match_ratio = true;
  332. $cur_qualities = $all_qualities;
  333. }
  334. return [$cur_qualities, $match_ratio];
  335. }
  336. private function max_times($mchid,$quality,$qualities)
  337. {
  338. [$succ, $times,$secs] = $this->mRatioCtl->total($mchid,$qualities);
  339. if ($succ) {
  340. return $times;
  341. } else {
  342. return $this->mSpeeds[$quality]['retry_times'];
  343. }
  344. }
  345. //通过每种类型通道耗时,倒推当前可用通道,并优先走推荐通道.
  346. private function calc_phone_quality(order $order, $qualities, $fMixed, $time_out, $max_times)
  347. {
  348. $mchid = $order->mchid();
  349. $used_times = $order->commit_times();
  350. $used_time = $order->elapse_secs();
  351. $left_time = $time_out - $used_time;
  352. if(!$fMixed)
  353. {
  354. if($left_time <= 0 || $max_times <= $used_times) {
  355. return [];
  356. }
  357. }
  358. $pTryAdjuster = $this->mTryAdjuster;
  359. $timeing_checker = function ($qualities) use($pTryAdjuster,$mchid)
  360. {
  361. foreach ($qualities as $quality)
  362. {
  363. $ret = $pTryAdjuster->can_try($mchid,$quality);
  364. if($ret == false) {
  365. return false;
  366. }
  367. }
  368. return true;
  369. };
  370. if($used_times > 0)
  371. {
  372. $qualities = $this->time_checker($order, $qualities);
  373. Log::record("calc_phone_quality times_checker result = " . implode(',', $qualities), Log::DEBUG);
  374. if(!$timeing_checker($qualities)) {
  375. $qualities = [];
  376. Log::record("calc_quality timeing_checker result is empty", Log::DEBUG);
  377. }
  378. }
  379. return $qualities;
  380. }
  381. }