chctlex.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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 update_maxspeeds($params)
  92. {
  93. foreach ($params as $key => $val)
  94. {
  95. [$name, $spec, $card_type] = explode('-', $key);
  96. $quality = $this->mNameMapQuality["{$name}-{$card_type}-{$spec}"] ?? 0;
  97. if ($quality <= 0) continue;
  98. $prefix = $this->prefix($name,$spec,$card_type,$quality);
  99. $ctl = $this->mSpeedtable[$prefix] ?? null;
  100. if(is_null($ctl)) continue;
  101. Log::record("update_maxspeeds {$key} speed={$val}",Log::DEBUG);
  102. $ctl->update_maxspeeds($val);
  103. }
  104. }
  105. public function match($names, int $spec, int $card_type, int $quality, $max_inprice)
  106. {
  107. $trace = new scope_trace(__METHOD__);
  108. if ($card_type == mtopcard\ThirdRefillCard) {
  109. return $names;
  110. }
  111. $pThis = $this;
  112. $price_filter = function ($names, $spec, $card_type, $quality) use ($pThis, $max_inprice)
  113. {
  114. $ctls = [];
  115. foreach ($names as $name)
  116. {
  117. Log::record("channel=$name",Log::DEBUG);
  118. $key = $pThis->prefix($name,$spec,$card_type,$quality);
  119. if(array_key_exists($key,$pThis->mSpeedtable))
  120. {
  121. $item = $pThis->mSpeedtable[$key];
  122. $inPrice = $item->price();
  123. if ($max_inprice !== false && $inPrice > $max_inprice) {
  124. Log::record("skip channel=$name",Log::DEBUG);
  125. } else {
  126. $ctls[] = $item;
  127. }
  128. }
  129. else {
  130. Log::record("cannot find key=$key in speedtable.",Log::DEBUG);
  131. }
  132. }
  133. return $ctls;
  134. };
  135. $ctl_items = $price_filter($names,$spec,$card_type,$quality);
  136. Log::record("ctl_items count=" . count($ctl_items), Log::DEBUG);
  137. $chooser = function ($ctl_items)
  138. {
  139. $usable_items = [];
  140. foreach ($ctl_items as $item)
  141. {
  142. if($item->opened()) {
  143. $usable_items[] = $item;
  144. }
  145. }
  146. return $usable_items;
  147. };
  148. //去掉已经关闭通道
  149. $usable_items = $chooser($ctl_items);
  150. Log::record("usable_items count=" . count($usable_items), Log::DEBUG);
  151. //不过载的排在前面
  152. $ascending = function ($l, $r)
  153. {
  154. $lproity = $l->priority();
  155. $rproity = $r->priority();
  156. $lover = $l->speed_overload() ? 1 : 0;
  157. $rover = $r->speed_overload() ? 1 : 0;
  158. if($lover == $rover)
  159. {
  160. if ($lover) {
  161. return $lproity > $rproity ? -1 : 1; //如果都过载保优先级高的
  162. } else {
  163. return $lproity < $rproity ? -1 : 1;
  164. }
  165. }
  166. else {
  167. return $lover < $rover ? -1 : 1;
  168. }
  169. };
  170. usort($usable_items, $ascending);
  171. $result = [];
  172. $over_loads = [];
  173. foreach ($usable_items as $item)
  174. {
  175. $name = $item->name();
  176. $over_load = $item->speed_overload();
  177. if($over_load) {
  178. $over_loads[] = $name;
  179. } else {
  180. $result[] = $name;
  181. }
  182. }
  183. $result = array_merge($result, $over_loads);
  184. Log::record("result=" . implode(',', $result), Log::DEBUG);
  185. return $result;
  186. }
  187. private function prefix($name,$spec,$card_type,$quality)
  188. {
  189. return "{$name}-{$spec}-{$card_type}-{$quality}";
  190. }
  191. public function auto_match($names, int $spec, int $card_type, int $quality, $out_price, $max_inprice, $left_time): array
  192. {
  193. $desc_profit = function ($l, $r) use($out_price)
  194. {
  195. $lProfit = $out_price - $l->price();
  196. $rProfit = $out_price - $r->price();
  197. $lVal = $l->compile_val($lProfit);
  198. $rVal = $r->compile_val($rProfit);
  199. Log::record("auto_match desc_profit lname={$l->name()} lval={$lVal} rname={$r->name()} rval={$rVal}",Log::DEBUG);
  200. if ($lVal == $rVal)
  201. {
  202. if($lVal == 0.0)
  203. {
  204. $lSubmits = $l->submits();
  205. $rSubmits = $r->submits();
  206. if($lSubmits > $rSubmits) {
  207. return 1;
  208. }
  209. elseif ($lSubmits < $rSubmits) {
  210. return -1;
  211. }
  212. else {
  213. return 0;
  214. }
  215. }
  216. elseif ($lProfit > $rProfit) {
  217. return -1;
  218. }
  219. elseif ($lProfit < $rProfit) {
  220. return 1;
  221. }
  222. else {
  223. return 0;
  224. }
  225. }
  226. elseif ($lVal > $rVal) {
  227. return -1;
  228. }
  229. else {
  230. return 1;
  231. }
  232. };
  233. $pThis = $this;
  234. $price_filter = function ($names,$spec,$card_type,$quality) use($pThis,$max_inprice)
  235. {
  236. $ctls = [];
  237. foreach ($names as $name)
  238. {
  239. $key = $pThis->prefix($name,$spec,$card_type,$quality);
  240. if(array_key_exists($key,$pThis->mSpeedtable))
  241. {
  242. $item = $pThis->mSpeedtable[$key];
  243. $inPrice = $item->price();
  244. //Log::record("key={$key} inPrice = {$inPrice} max_inprice = {$max_inprice}",Log::DEBUG);
  245. if ($max_inprice !== false && $inPrice > $max_inprice) {
  246. continue;
  247. } else {
  248. $ctls[] = $item;
  249. }
  250. }
  251. }
  252. return $ctls;
  253. };
  254. $ctl_splitor = function ($ctls)
  255. {
  256. $zeros = [];
  257. $workers = [];
  258. $overs = [];
  259. $stops = [];
  260. foreach ($ctls as $item)
  261. {
  262. Log::record("ctl_splitor {$item->name()} speed={$item->cur_speed()} max_speed={$item->max_speed()}",Log::DEBUG);
  263. if($item->zero_speed()) {
  264. $zeros[] = $item;
  265. }
  266. elseif($item->speed_stoped()) {
  267. $stops[] = $item;
  268. }
  269. elseif($item->speed_overload()) {
  270. $overs[] = $item;
  271. }
  272. else {
  273. $workers[] = $item;
  274. }
  275. }
  276. return [$zeros, $workers, $overs, $stops];
  277. };
  278. $time_map = function ($ctls, $left_time)
  279. {
  280. $header = [];
  281. $ender = [];
  282. foreach ($ctls as $item)
  283. {
  284. if($item->notify_time() <= $left_time + 600) {
  285. $header[] = $item;
  286. } else {
  287. $ender[] = $item;
  288. }
  289. }
  290. return array_merge($header,$ender);
  291. };
  292. $header_fun = function (int $spec, int $card_type, int $quality) {
  293. return "auto_match {$quality}-{$spec}-{$card_type}";
  294. };
  295. $header = $header_fun($spec,$card_type,$quality);
  296. $names_getter = function ($ctls) {
  297. $names = [];
  298. foreach ($ctls as $item) {
  299. $names[] = $item->name();
  300. }
  301. return $names;
  302. };
  303. $ctlitem_logger = function ($tag, $ctls) use ($header,$names_getter)
  304. {
  305. $result = [];
  306. foreach ($ctls as $item) {
  307. $result[] = "{$item->name()}: speed={$item->cur_speed()} max_speed={$item->max_speed()} notify={$item->notify_time()}";
  308. }
  309. $sname = implode(',', $result);
  310. Log::record("{$header} {$tag} :{$sname}",Log::DEBUG);
  311. };
  312. //end for log
  313. //working .....
  314. $names = array_unique($names);
  315. Log::record("auto_match outprice= {$out_price} max_inprice={$max_inprice} names=" . implode(',', $names), Log::DEBUG);
  316. $ctls = $price_filter($names, $spec, $card_type, $quality);
  317. $ctlitem_logger("price filter", $ctls);
  318. [$zeros, $workers, $overloads, $stops] = $ctl_splitor($ctls);
  319. $ctlitem_logger("zeros",$zeros);
  320. $ctlitem_logger("workers",$workers);
  321. $ctlitem_logger("overloads",$overloads);
  322. $ctlitem_logger("stops",$stops);
  323. usort($workers, $desc_profit);
  324. usort($overloads, $desc_profit);
  325. usort($stops, $desc_profit);
  326. $ctlitem_logger("sort workers",$workers);
  327. $ctlitem_logger("sort overloads",$overloads);
  328. $ctlitem_logger("sort stops",$stops);
  329. $ctls = array_merge($zeros, $workers, $overloads, $stops);
  330. $ctlitem_logger("result merge ctls", $ctls);
  331. $ctls = $time_map($ctls, $left_time);
  332. $ctlitem_logger("result time check ctls", $ctls);
  333. $names = $names_getter($ctls);
  334. return $names;
  335. }
  336. }