chctlex.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <?php
  2. namespace refill;
  3. use Log;
  4. use mtopcard;
  5. use algorithm;
  6. use scope_trace;
  7. class chctlex
  8. {
  9. protected $mSpeedtable;
  10. protected $mNameMapQuality;
  11. static $cache_names = [
  12. ['quality'=> 1,'name' => 'channel-ctl-oil-common-limit'],
  13. ['quality'=> 2,'name' => 'channel-ctl-oil-fast-limit'],
  14. ['quality'=> 3,'name' => 'channel-ctl-oil-card-limit'],
  15. ['quality'=> 5,'name' => 'channel-ctl-oil-slow-limit'],
  16. ['quality'=> 1,'name' => 'channel-ctl-phone-common-limit'],
  17. ['quality'=> 2,'name' => 'channel-ctl-phone-fast-limit'],
  18. ['quality'=> 3,'name' => 'channel-ctl-phone-card-limit'],
  19. ['quality'=> 4,'name' => 'channel-ctl-phone-third-limit'],
  20. ['quality'=> 5,'name' => 'channel-ctl-phone-slow-limit'], //24 hour
  21. ['quality'=> 6,'name' => 'channel-ctl-phone-slow6-limit'], //6 hour
  22. ['quality'=> 7,'name' => 'channel-ctl-phone-slow2-limit'], //2 hour
  23. ['quality'=> 8,'name' => 'channel-ctl-phone-slow48-limit'],//48 hour
  24. ['quality'=> 9,'name' => 'channel-ctl-phone-slow72-limit'] //72 hour
  25. ];
  26. public function __construct()
  27. {
  28. $this->mSpeedtable = [];
  29. }
  30. public function update_price($policy)
  31. {
  32. $QPTA = $policy->getQPTA();
  33. foreach ($this->mSpeedtable as $key => $item)
  34. {
  35. $quality = $item->quality();
  36. $name = $item->name();
  37. $spec = $item->spec();
  38. $card_type = $item->card_type();
  39. $prefix = "{$name}-{$card_type}-{$spec}";
  40. if(array_key_exists($quality,$QPTA) && array_key_exists($prefix,$QPTA[$quality])) {
  41. $price = $QPTA[$quality][$prefix]['price'];
  42. $item->set_price($price);
  43. }
  44. }
  45. }
  46. public function load($opened_names)
  47. {
  48. $this->mSpeedtable = [];
  49. $this->mNameMapQuality = [];
  50. foreach (self::$cache_names as $cache)
  51. {
  52. $quality = $cache['quality'];
  53. $cache_name = $cache['name'];
  54. $data = rcache($cache_name,"provider-");
  55. $data = unserialize($data['data']);
  56. $cfgs = empty($data) ? [] : $data;
  57. foreach ($cfgs as $items)
  58. {
  59. foreach ($items as $item)
  60. {
  61. $name = $item['name'];
  62. if(!algorithm::binary_search($opened_names,$name)) {
  63. continue;
  64. }
  65. $amount = $item['amount'];
  66. $card_type = $item['type'];
  67. $opened = $item['opened'] == 1;
  68. $sort = $item['sort'];
  69. $speed = $item['speed'];
  70. if($opened == false) continue;
  71. $key = $this->prefix($name,$amount,$card_type,$quality);
  72. $this->mSpeedtable[$key] = new ctl_itemex($name,$card_type,$amount,$speed,$sort,0,$opened,$quality);
  73. $this->mNameMapQuality["{$name}-{$card_type}-{$amount}"] = $quality;
  74. }
  75. }
  76. }
  77. }
  78. public function update_chctl($params)
  79. {
  80. foreach ($params as $key => $val)
  81. {
  82. [$name, $spec, $card_type] = explode('-', $key);
  83. $quality = $this->mNameMapQuality["{$name}-{$card_type}-{$spec}"] ?? 0;
  84. if($quality <=0) continue;
  85. $prefix = $this->prefix($name,$spec,$card_type,$quality);
  86. $ctl = $this->mSpeedtable[$prefix] ?? null;
  87. if(is_null($ctl)) continue;
  88. $ctl->update_params($val);
  89. }
  90. }
  91. public function match($names, int $spec, int $card_type, int $quality, $max_inprice)
  92. {
  93. $trace = new scope_trace(__METHOD__);
  94. if ($card_type == mtopcard\ThirdRefillCard) {
  95. return $names;
  96. }
  97. $pThis = $this;
  98. $price_filter = function ($names,$spec,$card_type,$quality) use($pThis,$max_inprice)
  99. {
  100. $ctls = [];
  101. foreach ($names as $name)
  102. {
  103. $key = $pThis->prefix($name,$spec,$card_type,$quality);
  104. if(array_key_exists($key,$pThis->mSpeedtable))
  105. {
  106. $item = $pThis->mSpeedtable[$key];
  107. $inPrice = $item->price();
  108. if ($max_inprice !== false && $inPrice > $max_inprice) {
  109. continue;
  110. } else {
  111. $ctls[] = $item;
  112. }
  113. }
  114. }
  115. return $ctls;
  116. };
  117. $ctl_items = $price_filter($names,$spec,$card_type,$quality);
  118. $chooser = function ($ctl_items)
  119. {
  120. $usable_items = [];
  121. foreach ($ctl_items as $item)
  122. {
  123. if($item->opened()) {
  124. $usable_items[] = $item;
  125. }
  126. }
  127. return $usable_items;
  128. };
  129. //去掉已经关闭通道
  130. $usable_items = $chooser($ctl_items);
  131. //不过载的排在前面
  132. $ascending = function ($l, $r)
  133. {
  134. $lproity = $l->priority();
  135. $rproity = $r->priority();
  136. $lover = $l->speed_overload() ? 1 : 0;
  137. $rover = $r->speed_overload() ? 1 : 0;
  138. if($lover == $rover)
  139. {
  140. if ($lover) {
  141. return $lproity > $rproity ? -1 : 1; //如果都过载保优先级高的
  142. } else {
  143. return $lproity < $rproity ? -1 : 1;
  144. }
  145. }
  146. else {
  147. return $lover < $rover ? -1 : 1;
  148. }
  149. };
  150. usort($usable_items, $ascending);
  151. $result = [];
  152. $over_loads = [];
  153. foreach ($usable_items as $item)
  154. {
  155. $name = $item->name();
  156. $over_load = $item->speed_overload();
  157. if($over_load) {
  158. $over_loads[] = $item;
  159. } else {
  160. $result[] = $name;
  161. }
  162. }
  163. if(!empty($over_loads))
  164. {
  165. $assigner = new overload_assigner();
  166. $assigner->add($over_loads);
  167. $over_loads = $assigner->assign();
  168. foreach ($over_loads as $item) {
  169. $result[] = $item->name();
  170. }
  171. }
  172. return $result;
  173. }
  174. private function prefix($name,$spec,$card_type,$quality)
  175. {
  176. return "{$name}-{$spec}-{$card_type}-{$quality}";
  177. }
  178. public function auto_match($names, int $spec, int $card_type, int $quality, $out_price, $max_inprice, $left_time): array
  179. {
  180. $desc_profit = function ($l, $r) use($out_price)
  181. {
  182. $lProfit = $out_price - $l->price();
  183. $rProfit = $out_price - $r->price();
  184. $lVal = $l->compile_val($lProfit);
  185. $rVal = $r->compile_val($rProfit);
  186. Log::record("auto_match desc_profit lname={$l->name()} lval={$lVal} rname={$r->name()} rval={$rVal}",Log::DEBUG);
  187. if ($lVal == $rVal)
  188. {
  189. if($lVal == 0.0)
  190. {
  191. $lSubmits = $l->submits();
  192. $rSubmits = $r->submits();
  193. if($lSubmits > $rSubmits) {
  194. return 1;
  195. }
  196. elseif ($lSubmits < $rSubmits) {
  197. return -1;
  198. }
  199. else {
  200. return 0;
  201. }
  202. }
  203. elseif ($lProfit > $rProfit) {
  204. return -1;
  205. }
  206. elseif ($lProfit < $rProfit) {
  207. return 1;
  208. }
  209. else {
  210. return 0;
  211. }
  212. }
  213. elseif ($lVal > $rVal) {
  214. return -1;
  215. }
  216. else {
  217. return 1;
  218. }
  219. };
  220. $pThis = $this;
  221. $price_filter = function ($names,$spec,$card_type,$quality) use($pThis,$max_inprice)
  222. {
  223. $ctls = [];
  224. foreach ($names as $name)
  225. {
  226. $key = $pThis->prefix($name,$spec,$card_type,$quality);
  227. if(array_key_exists($key,$pThis->mSpeedtable))
  228. {
  229. $item = $pThis->mSpeedtable[$key];
  230. $inPrice = $item->price();
  231. if ($max_inprice !== false && $inPrice > $max_inprice) {
  232. continue;
  233. } else {
  234. $ctls[] = $item;
  235. }
  236. }
  237. }
  238. return $ctls;
  239. };
  240. $ctl_splitor = function ($ctls)
  241. {
  242. $feeds = [];
  243. $workers = [];
  244. $overs = [];
  245. foreach ($ctls as $item)
  246. {
  247. Log::record("ctl_splitor {$item->name()} speed={$item->cur_speed()} max_speed={$item->max_speed()}",Log::DEBUG);
  248. if($item->need_feed()) {
  249. $feeds[] = $item;
  250. }
  251. elseif($item->speed_overload()) {
  252. $overs[] = $item;
  253. }
  254. else {
  255. $workers[] = $item;
  256. }
  257. }
  258. return [$feeds,$workers,$overs];
  259. };
  260. $assign_feeds = function ($feeds)
  261. {
  262. if(empty($feeds)) {
  263. return [[],[]];
  264. }
  265. $max = count($feeds) - 1;
  266. $pos = mt_rand(0, $max);
  267. $cur_feeds = [];
  268. $next_feeds = [];
  269. $i = 0;
  270. foreach ($feeds as $item)
  271. {
  272. if($i == $pos) {
  273. $cur_feeds[] = $item;
  274. } else {
  275. $next_feeds[] = $item;
  276. }
  277. $i++;
  278. }
  279. return [$cur_feeds,$next_feeds];
  280. };
  281. $time_map = function ($ctls, $left_time)
  282. {
  283. $header = [];
  284. $ender = [];
  285. foreach ($ctls as $item)
  286. {
  287. if($item->notify_time() > $left_time) {
  288. $header[] = $item;
  289. } else {
  290. $ender[] = $item;
  291. }
  292. }
  293. return array_merge($header,$ender);
  294. };
  295. //for log
  296. $header_fun = function (int $spec, int $card_type, int $quality) {
  297. return "auto_match {$quality}-{$spec}-{$card_type}";
  298. };
  299. $header = $header_fun($spec,$card_type,$quality);
  300. $names_getter = function ($ctls) {
  301. $names = [];
  302. foreach ($ctls as $item) {
  303. $names[] = $item->name();
  304. }
  305. return $names;
  306. };
  307. $ctlitem_logger = function ($tag, $ctls) use ($header,$names_getter)
  308. {
  309. $names = $names_getter($ctls);
  310. $sname = implode(',', $names);
  311. Log::record("{$header} {$tag} :{$sname}",Log::DEBUG);
  312. };
  313. //end for log
  314. //working .....
  315. $names = array_unique($names);
  316. Log::record("auto_match outprice= {$out_price} names=" . implode(',', $names), Log::DEBUG);
  317. $ctls = $price_filter($names, $spec, $card_type, $quality);
  318. $ctlitem_logger("price filter", $ctls);
  319. [$feeds,$workers,$overloads] = $ctl_splitor($ctls);
  320. [$cur_feeds,$next_feeds] = $assign_feeds($feeds);
  321. $ctlitem_logger("cur feeds",$cur_feeds);
  322. $ctlitem_logger("next feeds",$next_feeds);
  323. $ctlitem_logger("over loads",$overloads);
  324. usort($workers, $desc_profit);
  325. $ctlitem_logger("sort works",$workers);
  326. if(!empty($overloads)) {
  327. $assigner = new overload_assigner();
  328. $assigner->add($overloads);
  329. $overloads = $assigner->assign();
  330. }
  331. $ctls = array_merge($cur_feeds, $workers, $overloads, $next_feeds);
  332. $ctls = $time_map($ctls,$left_time);
  333. $ctlitem_logger("result ctls",$ctls);
  334. $names = $names_getter($ctls);
  335. return $names;
  336. }
  337. }