|
@@ -0,0 +1,375 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+
|
|
|
+namespace refill;
|
|
|
+
|
|
|
+use Log;
|
|
|
+use mtopcard;
|
|
|
+use algorithm;
|
|
|
+use scope_trace;
|
|
|
+
|
|
|
+class chctlex
|
|
|
+{
|
|
|
+ protected $mSpeedtable;
|
|
|
+ protected $mNameMapQuality;
|
|
|
+
|
|
|
+ static $cache_names = [
|
|
|
+ ['quality'=> 1,'name' => 'channel-ctl-oil-common-limit'],
|
|
|
+ ['quality'=> 2,'name' => 'channel-ctl-oil-fast-limit'],
|
|
|
+ ['quality'=> 3,'name' => 'channel-ctl-oil-card-limit'],
|
|
|
+ ['quality'=> 5,'name' => 'channel-ctl-oil-slow-limit'],
|
|
|
+
|
|
|
+ ['quality'=> 1,'name' => 'channel-ctl-phone-common-limit'],
|
|
|
+ ['quality'=> 2,'name' => 'channel-ctl-phone-fast-limit'],
|
|
|
+ ['quality'=> 3,'name' => 'channel-ctl-phone-card-limit'],
|
|
|
+ ['quality'=> 4,'name' => 'channel-ctl-phone-third-limit'],
|
|
|
+ ['quality'=> 5,'name' => 'channel-ctl-phone-slow-limit'], //24 hour
|
|
|
+ ['quality'=> 6,'name' => 'channel-ctl-phone-slow6-limit'], //6 hour
|
|
|
+ ['quality'=> 7,'name' => 'channel-ctl-phone-slow2-limit'], //2 hour
|
|
|
+ ['quality'=> 8,'name' => 'channel-ctl-phone-slow48-limit'],//48 hour
|
|
|
+ ['quality'=> 9,'name' => 'channel-ctl-phone-slow72-limit'] //72 hour
|
|
|
+ ];
|
|
|
+
|
|
|
+ public function __construct()
|
|
|
+ {
|
|
|
+ $this->mSpeedtable = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ public function update_price($policy)
|
|
|
+ {
|
|
|
+ $QPTA = $policy->getQPTA();
|
|
|
+ foreach ($this->mSpeedtable as $key => $item)
|
|
|
+ {
|
|
|
+ $quality = $item->quality();
|
|
|
+ $name = $item->name();
|
|
|
+ $spec = $item->spec();
|
|
|
+ $card_type = $item->card_type();
|
|
|
+
|
|
|
+ $prefix = "{$name}-{$card_type}-{$spec}";
|
|
|
+ if(array_key_exists($quality,$QPTA) && array_key_exists($prefix,$QPTA[$quality])) {
|
|
|
+ $price = $QPTA[$quality][$prefix]['price'];
|
|
|
+ $item->set_price($price);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function load($opened_names)
|
|
|
+ {
|
|
|
+ $this->mSpeedtable = [];
|
|
|
+ $this->mNameMapQuality = [];
|
|
|
+ foreach (self::$cache_names as $cache)
|
|
|
+ {
|
|
|
+ $quality = $cache['quality'];
|
|
|
+ $cache_name = $cache['name'];
|
|
|
+
|
|
|
+ $data = rcache($cache_name,"provider-");
|
|
|
+ $data = unserialize($data['data']);
|
|
|
+
|
|
|
+ $cfgs = empty($data) ? [] : $data;
|
|
|
+
|
|
|
+ foreach ($cfgs as $items)
|
|
|
+ {
|
|
|
+ foreach ($items as $item)
|
|
|
+ {
|
|
|
+ $name = $item['name'];
|
|
|
+ if(!algorithm::binary_search($opened_names,$name)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $amount = $item['amount'];
|
|
|
+ $card_type = $item['type'];
|
|
|
+
|
|
|
+ $opened = $item['opened'] == 1;
|
|
|
+ $sort = $item['sort'];
|
|
|
+ $speed = $item['speed'];
|
|
|
+
|
|
|
+ if($opened == false) continue;
|
|
|
+
|
|
|
+ $key = $this->prefix($name,$amount,$card_type,$quality);
|
|
|
+ $this->mSpeedtable[$key] = new ctl_itemex($name,$card_type,$amount,$speed,$sort,0,$opened,$quality);
|
|
|
+ $this->mNameMapQuality["{$name}-{$card_type}-{$amount}"] = $quality;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function update_chctl($params)
|
|
|
+ {
|
|
|
+ foreach ($params as $key => $val)
|
|
|
+ {
|
|
|
+ [$name, $spec, $card_type] = explode('-', $key);
|
|
|
+
|
|
|
+ $quality = $this->mNameMapQuality["{$name}-{$card_type}-{$spec}"] ?? 0;
|
|
|
+ if($quality <=0) continue;
|
|
|
+
|
|
|
+ $prefix = $this->prefix($name,$spec,$card_type,$quality);
|
|
|
+ $ctl = $this->mSpeedtable[$prefix] ?? null;
|
|
|
+ if(is_null($ctl)) continue;
|
|
|
+
|
|
|
+ $ctl->update_params($val);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ public function match($names, int $spec, int $card_type, int $quality, $max_inprice)
|
|
|
+ {
|
|
|
+ $trace = new scope_trace(__METHOD__);
|
|
|
+ if ($card_type == mtopcard\ThirdRefillCard) {
|
|
|
+ return $names;
|
|
|
+ }
|
|
|
+
|
|
|
+ $pThis = $this;
|
|
|
+ $price_filter = function ($names,$spec,$card_type,$quality) use($pThis,$max_inprice)
|
|
|
+ {
|
|
|
+ $ctls = [];
|
|
|
+ foreach ($names as $name)
|
|
|
+ {
|
|
|
+ $key = $pThis->prefix($name,$spec,$card_type,$quality);
|
|
|
+ if(array_key_exists($key,$pThis->mSpeedtable))
|
|
|
+ {
|
|
|
+ $item = $pThis->mSpeedtable[$key];
|
|
|
+
|
|
|
+ $inPrice = $item->price();
|
|
|
+ if ($max_inprice !== false && $inPrice > $max_inprice) {
|
|
|
+ continue;
|
|
|
+ } else {
|
|
|
+ $ctls[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $ctls;
|
|
|
+ };
|
|
|
+ $ctl_items = $price_filter($names,$spec,$card_type,$quality);
|
|
|
+
|
|
|
+ $chooser = function ($ctl_items)
|
|
|
+ {
|
|
|
+ $usable_items = [];
|
|
|
+ foreach ($ctl_items as $item)
|
|
|
+ {
|
|
|
+ if($item->opened()) {
|
|
|
+ $usable_items[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $usable_items;
|
|
|
+ };
|
|
|
+
|
|
|
+ //去掉已经关闭通道
|
|
|
+ $usable_items = $chooser($ctl_items);
|
|
|
+
|
|
|
+ //不过载的排在前面
|
|
|
+ $ascending = function ($l, $r)
|
|
|
+ {
|
|
|
+ $lproity = $l->priority();
|
|
|
+ $rproity = $r->priority();
|
|
|
+
|
|
|
+ $lover = $l->speed_overload() ? 1 : 0;
|
|
|
+ $rover = $r->speed_overload() ? 1 : 0;
|
|
|
+
|
|
|
+ if($lover == $rover)
|
|
|
+ {
|
|
|
+ if ($lover) {
|
|
|
+ return $lproity > $rproity ? -1 : 1; //如果都过载保优先级高的
|
|
|
+ } else {
|
|
|
+ return $lproity < $rproity ? -1 : 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return $lover < $rover ? -1 : 1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ usort($usable_items, $ascending);
|
|
|
+
|
|
|
+ $result = [];
|
|
|
+
|
|
|
+ $over_loads = [];
|
|
|
+ foreach ($usable_items as $item)
|
|
|
+ {
|
|
|
+ $name = $item->name();
|
|
|
+ $over_load = $item->speed_overload();
|
|
|
+ if($over_load) {
|
|
|
+ $over_loads[] = $item;
|
|
|
+ } else {
|
|
|
+ $result[] = $name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!empty($over_loads))
|
|
|
+ {
|
|
|
+ $assigner = new overload_assigner();
|
|
|
+ $assigner->add($over_loads);
|
|
|
+ $over_loads = $assigner->assign();
|
|
|
+
|
|
|
+ foreach ($over_loads as $item) {
|
|
|
+ $result[] = $item->name();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function prefix($name,$spec,$card_type,$quality)
|
|
|
+ {
|
|
|
+ return "{$name}-{$spec}-{$card_type}-{$quality}";
|
|
|
+ }
|
|
|
+
|
|
|
+ public function auto_match($names, int $spec, int $card_type, int $quality, $out_price, $max_inprice, $left_time): array
|
|
|
+ {
|
|
|
+ $desc_profit = function ($l, $r) use($out_price)
|
|
|
+ {
|
|
|
+ $lProfit = $out_price - $l->price();
|
|
|
+ $rRrofit = $out_price - $r->price();
|
|
|
+
|
|
|
+ $lVal = $l->compile_val($lProfit);
|
|
|
+ $rVal = $r->compile_val($lProfit);
|
|
|
+
|
|
|
+ if ($lVal == $rVal)
|
|
|
+ {
|
|
|
+ if($lVal == 0.0)
|
|
|
+ {
|
|
|
+ $lSubmits = $l->submits();
|
|
|
+ $rSubmits = $r->submits();
|
|
|
+
|
|
|
+ if($lSubmits > $rSubmits) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ elseif ($lProfit < $rRrofit) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ elseif ($lProfit > $rRrofit) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ elseif ($lProfit < $rRrofit) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ elseif ($lVal > $rVal) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ $pThis = $this;
|
|
|
+ $price_filter = function ($names,$spec,$card_type,$quality) use($pThis,$max_inprice)
|
|
|
+ {
|
|
|
+ $ctls = [];
|
|
|
+ foreach ($names as $name)
|
|
|
+ {
|
|
|
+ $key = $pThis->prefix($name,$spec,$card_type,$quality);
|
|
|
+ if(array_key_exists($key,$pThis->mSpeedtable))
|
|
|
+ {
|
|
|
+ $item = $pThis->mSpeedtable[$key];
|
|
|
+ $inPrice = $item->price();
|
|
|
+ if ($max_inprice !== false && $inPrice > $max_inprice) {
|
|
|
+ continue;
|
|
|
+ } else {
|
|
|
+ $ctls[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Log::record("auto_match speed table key={$key} is empty.",Log::DEBUG);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $ctls;
|
|
|
+ };
|
|
|
+
|
|
|
+ $ctl_splitor = function ($ctls)
|
|
|
+ {
|
|
|
+ $feeds = [];
|
|
|
+ $workers = [];
|
|
|
+ $overs = [];
|
|
|
+
|
|
|
+ foreach ($ctls as $item)
|
|
|
+ {
|
|
|
+ if($item->need_feed()) {
|
|
|
+ $feeds[] = $item;
|
|
|
+ }
|
|
|
+ elseif($item->speed_overload()) {
|
|
|
+ $overs[] = $item;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $workers[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [$feeds,$workers,$overs];
|
|
|
+ };
|
|
|
+
|
|
|
+ $assign_feeds = function ($feeds)
|
|
|
+ {
|
|
|
+ if(empty($feeds)) {
|
|
|
+ return [[],[]];
|
|
|
+ }
|
|
|
+
|
|
|
+ $count = count($feeds);
|
|
|
+ $pos = mt_rand(0, $count * 60);
|
|
|
+
|
|
|
+ $cur_feeds = [];
|
|
|
+ $next_feeds = [];
|
|
|
+
|
|
|
+ $i = 0;
|
|
|
+ foreach ($feeds as $item)
|
|
|
+ {
|
|
|
+ if($i == $pos) {
|
|
|
+ $cur_feeds[] = $item;
|
|
|
+ } else {
|
|
|
+ $next_feeds[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [$cur_feeds,$next_feeds];
|
|
|
+ };
|
|
|
+
|
|
|
+ $time_map = function ($ctls, $left_time)
|
|
|
+ {
|
|
|
+ $header = [];
|
|
|
+ $ender = [];
|
|
|
+ foreach ($ctls as $item)
|
|
|
+ {
|
|
|
+ if($item->notify_time() > $left_time) {
|
|
|
+ $header[] = $item;
|
|
|
+ } else {
|
|
|
+ $ender[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return array_merge($header,$ender);
|
|
|
+ };
|
|
|
+
|
|
|
+ $names = array_unique($names);
|
|
|
+ Log::record("auto_match outprice= {$out_price} names=" . implode(',', $names), Log::DEBUG);
|
|
|
+ $ctls = $price_filter($names,$spec,$card_type,$quality);
|
|
|
+ [$feeds,$workers,$overloads] = $ctl_splitor($ctls);
|
|
|
+
|
|
|
+ [$cur_feeds,$next_feeds] = $assign_feeds($feeds);
|
|
|
+ usort($workers, $desc_profit);
|
|
|
+
|
|
|
+ if(!empty($overloads)) {
|
|
|
+ $assigner = new overload_assigner();
|
|
|
+ $assigner->add($overloads);
|
|
|
+ $overloads = $assigner->assign();
|
|
|
+ }
|
|
|
+
|
|
|
+ $ctls = array_merge($cur_feeds, $workers, $overloads, $next_feeds);
|
|
|
+ $ctls = $time_map($ctls,$left_time);
|
|
|
+
|
|
|
+ $names = [];
|
|
|
+ foreach ($ctls as $item) {
|
|
|
+ $names[] = $item->name();
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::record("auto_match result names=" . implode(',', $names), Log::DEBUG);
|
|
|
+ return $names;
|
|
|
+ }
|
|
|
+}
|