stanley-king 3 yıl önce
ebeveyn
işleme
fbc8bc2bdc

+ 10 - 0
docker/compose/stanley/docker-compose.yml

@@ -247,3 +247,13 @@ services:
       - /Users/stanley-king/work/PHPProject/stdata:/var/www/html/data/stdata
     container_name: "panda-reader"
     command: ['python','reader.py']
+
+  mchreadersrv:
+    image: pycpu:3.7.10
+    volumes:
+      - ../../conf/etc/localtime:/etc/localtime:ro
+      - ../../../:/var/www/html
+      - /Users/stanley-king/work/PHPProject/shoplog:/var/www/html/data/log
+      - /Users/stanley-king/work/PHPProject/stdata:/var/www/html/data/stdata
+    container_name: "panda-reader"
+    command: ['python','mchreader.py']

+ 5 - 2
helper/refill/RefillBase.php

@@ -64,11 +64,12 @@ class RefillBase
             if ($order_id !== false) {
                 return $this->proc_notify($order_id, $success, $can_try, $chname);
             } else {
-                Log::record("系统无此订单ID:{$order_id}", Log::ERR);
+                Log::record("{$chname} callback 系统无此订单ID:{$order_id}", Log::ERR);
             }
         }
         else {
-            Log::record("{$chname} 签名失败.");
+            $orgdata = json_decode($input);
+            Log::record("{$chname} 签名失败:input={$orgdata}",Log::ERR);
         }
 
         return true;
@@ -103,9 +104,11 @@ class RefillBase
             $card_type = intval($refill_info['card_type']);
             $spec = intval($refill_info['refill_amount']);
             $mchid = intval($refill_info['mchid']);
+            $org_quality = intval($refill_info['org_quality']);
 
             if ($success) {
                 util::incr_notify($chname, $card_type, $spec, $quality, true);
+                util::incr_user_success($mchid,$card_type, $spec,$org_quality);
                 $logic_vr_order->changeOrderStateSuccess($order_id);
             }
             elseif ($can_try)

+ 4 - 4
helper/refill/api/lingzh/haohao/RefillCallBack.php

@@ -23,15 +23,15 @@ class RefillCallBack implements refill\IRefillCallBack
     {
         ksort($params);
 
-        $signature_string = '';
+        $body = '';
         foreach ($params as $k => $v) {
             if (false === $this->check_empty($v)) {
-                $signature_string .= $k . '=' . $v . '&';
+                $body .= "{$k}={$v}&";
             }
         }
-        $signature_string .= "key=" . config::KEY;
+        $body .= "key=" . config::KEY;
 
-        return strtoupper(md5($signature_string));
+        return strtoupper(md5($body));
     }
 
     private function check_empty($value)

+ 4 - 4
helper/refill/api/lingzh/haohao/RefillOil.php

@@ -59,14 +59,14 @@ class RefillOil extends refill\IRefillPhone
     {
         ksort($params);
 
-        $signature_string = '';
+        $body = '';
         foreach ($params as $k => $v) {
             if (strlen($v)) {
-                $signature_string .= $k . '=' . $v . '&';
+                $body .= "{$k}={$v}&";
             }
         }
-        $signature_string .= "key=" . config::KEY;
+        $body .= "key=" . config::KEY;
 
-        return strtoupper(md5($signature_string));
+        return strtoupper(md5($body));
     }
 }

+ 1 - 1
helper/refill/policy/xyz/policy.php

@@ -86,12 +86,12 @@ class policy extends ProviderManager implements IPolicy
         $result = [];
         foreach ($name_overloads as $name => $overload)
         {
+            Log::record("channel {$name} has overloaded {$overload}",Log::DEBUG);
             if(!isset($first)) {
                 $first = $overload;
             }
 
             if($overload) continue;
-
             foreach ($providers as $provider)
             {
                 if($name == $provider->name()) {

+ 14 - 3
helper/refill/util.php

@@ -304,13 +304,24 @@ class util
     }
 
     //统计用户提交数据
-    public static function incr_user_commit($card_type, $spec)
+    public static function incr_user_commit($mchid,$card_type, $spec,$quality)
     {
         $ins = Cache::getInstance('cacheredis');
 
-        $name = 'channel_monitor_user';
+        $name = 'user_monitor_commit';
         $sec = time();
-        $key_sec = "succ-{$card_type}-{$spec}-{$sec}";
+        $key_sec = "{$mchid}-{$quality}-{$card_type}-{$spec}-{$sec}";
+
+        $ins->hIncrBy($name, $key_sec, 1);
+    }
+
+    public static function incr_user_success($mchid,$card_type, $spec,$quality)
+    {
+        $ins = Cache::getInstance('cacheredis');
+
+        $name = 'user_monitor_success';
+        $sec = time();
+        $key_sec = "{$mchid}-{$quality}-{$card_type}-{$spec}-{$sec}";
 
         $ins->hIncrBy($name, $key_sec, 1);
     }

+ 2 - 6
plot/DataCenter.py

@@ -1,7 +1,5 @@
-from threading import Thread
 import os
 import time as stime
-from Singleton import Singleton
 import redis
 import h5py
 from os import path
@@ -309,16 +307,14 @@ class DataCenter(object):
         ySucc = ySucc / (all + 0.00000001)
         xs = np.array([stime.strftime('%H:%M', stime.localtime(d + day_stamp)) for d in x])
         ax.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=0))
-        ax.plot(xs, ySucc, ls='--', marker='o', label=self._label(path,succ_count,all_count))
+        ax.plot(xs, ySucc, ls='--', marker='o', label=self._label(path, succ_count, all_count))
         return True
 
-    def _label(self, path,count,all):
+    def _label(self, path, count, all):
         ratio = 0.00
         if all > 0:
             ratio = round(count * 100 / all, 2)
 
-
-
         items = re.split(r'/', path)
         if len(items) == 6:
             (_, _sday, _chname, _quality, _card_type, _amount) = items

+ 339 - 0
plot/MchDataCenter.py

@@ -0,0 +1,339 @@
+import os
+import time as stime
+import redis
+import h5py
+from os import path
+import re
+from datetime import timedelta
+import numpy as np
+from matplotlib.figure import Figure
+from matplotlib import ticker
+from io import BytesIO
+import logging
+
+
+class MchDataCenter(object):
+    pos_map = {
+        'commit-succ': 0, 'notify-succ': 1
+    }
+
+    def __init__(self):
+        self._mquit = False
+        self._mRHost = ''
+        self._mRPort = 6379
+        self._file_name = '/var/www/html/data/stdata/user.hdf5'
+
+    def set_redis(self, rhost, rport):
+        self._mRHost = rhost
+        self._mRPort = rport
+
+    def stop(self):
+        self._mquit = True
+        pass
+
+    def prepare_data(self):
+        while True:
+            try:
+                # pool = redis.ConnectionPool(host='121.89.223.81', port=57649, db=0)
+                pool = redis.ConnectionPool(host=self._mRHost, port=self._mRPort, db=0)
+                r = redis.Redis(connection_pool=pool)
+
+                if path.exists(self._file_name):
+                    hfive = h5py.File(self._file_name, 'a')
+                else:
+                    hfive = h5py.File(self._file_name, 'w')
+
+                self.read_redis(hfive, r, 'nc_channel_monitor_commit', 'commit')
+                self.read_redis(hfive, r, 'nc_channel_monitor_notify', 'notify')
+                hfive.close()
+
+                self.del_redis(r, 'nc_channel_monitor_commit')
+                self.del_redis(r, 'nc_channel_monitor_notify')
+            except Exception as ex:
+                print(ex)
+            finally:
+                for i in range(60):
+                    if self._mquit == True:
+                        break
+                    else:
+                        stime.sleep(1)
+
+    def del_redis(self, redis, name):
+        latest_time = int(stime.time()) - 300
+        for item in redis.hscan_iter(name):
+            key = str(item[0], encoding="utf-8")
+            items = re.split(r'-', key)
+
+            fdel = True
+            if len(items) == 6:
+                (stype, chname, quality, card_type, amount, time) = items
+                time = int(time)
+                if latest_time <= time:
+                    fdel = False
+
+            if fdel:
+                redis.hdel(name, key)
+        pass
+
+    def read_redis(self, hfive, redis, name, prefix):
+        i = 0
+        for item in redis.hscan_iter(name):
+            key = str(item[0], encoding="utf-8")
+            val = str(item[1], encoding="utf-8")
+            print(f'{prefix}:{i}')
+            i += 1
+            self.parase(hfive, key, val, prefix)
+
+    def parase(self, hfive, text, val, prefix):
+        items = re.split(r'-', text)
+        if len(items) != 6:
+            return False
+
+        (stype, chname, quality, card_type, amount, time) = items
+        if stype == 'succ':
+            pos = self.pos_map[f'{prefix}-succ']
+        elif stype == 'fail':
+            pos = self.pos_map[f'{prefix}-fail']
+        else:
+            return False
+
+        time = int(time)
+        today = self.day_stamp(time)
+        path = f'/{today}/{chname}/{quality}/{card_type}/{amount}'
+        if path not in hfive:
+            hfive[path] = np.zeros((5, 86400))
+
+        diff = time - today
+        if diff < 0:
+            print(diff)
+        hfive[path][pos, diff] = val
+        print(path, pos, diff, val, hfive[path][pos, diff])
+        pass
+
+    def day_stamp(self, stamp):
+        stamp = int(stamp)
+        x = stime.gmtime(stamp + 8 * 3600)
+        diff = timedelta(hours=x.tm_hour, minutes=x.tm_min, seconds=x.tm_sec)
+        today = stamp - diff.total_seconds()
+        return int(today)
+
+    def _days(self, root):
+        result = []
+        try:
+            for name, sub in root.items():
+                if isinstance(sub, h5py.Group):
+                    result.append(name)
+        except Exception as ex:
+            print(ex)
+        finally:
+            return result
+
+    def days(self):
+        try:
+            hfive = h5py.File(self._file_name, 'r')
+            root = hfive.require_group('/')
+            days = self._days(root)
+            hfive.close()
+            return days
+        except Exception as ex:
+            print(ex)
+            return []
+
+    def paths(self, time_stamp):
+        try:
+            day_stamp = self.day_stamp(time_stamp)
+            hfive = h5py.File(self._file_name, 'r')
+            group = hfive.require_group(f'/{day_stamp}')
+            paths = self.dir(group)
+            hfive.close()
+            return paths
+        except Exception as ex:
+            print(ex)
+            return []
+
+    def dir(self, group):
+        result = []
+        for name, sub in group.items():
+            if isinstance(sub, h5py.Group):
+                result.extend(self.dir(sub))
+            else:
+                result.append(sub.name)
+        return result
+
+    def draw_plot(self, start_time, interval=300, **kwargs):
+        logger = logging.getLogger('app')
+        hfive = h5py.File(self._file_name, 'r')
+        try:
+            filer_text, paths = self.datasets(hfive, start_time, **kwargs)
+            day_stamp = self.day_stamp(start_time)
+            start_pos = start_time - day_stamp
+
+            cur_day = self.day_stamp(stime.time())
+            if day_stamp == cur_day:
+                end_pos = int(stime.time()) - day_stamp
+            else:
+                end_pos = -1
+
+            fig = Figure(figsize=(16, 8))
+            ax = fig.subplots()
+
+            predata = np.zeros((5, 86400))
+            x = np.arange(0, 86400, interval)
+
+            sub_count = 0
+            for path, data in self.read_data(hfive, paths):
+                data = np.array(data)
+                predata = predata + data
+                ret = self._draw_plot(ax, x, day_stamp, start_pos, end_pos, data, interval, path)
+                if ret:
+                    sub_count += 1
+
+            if sub_count > 1:
+                self._draw_plot(ax, x, day_stamp, start_pos, end_pos, predata, interval, filer_text)
+
+            ax.legend()
+            ax.grid()
+            ax.set_title('success ratio')
+            ax.set(xlabel='time', ylabel='ratio')
+            fig.autofmt_xdate()
+            fig.subplots_adjust(left=0.05, right=0.999, top=0.95, bottom=0.1)
+
+            buf = BytesIO()
+            fig.savefig(buf, format="png")
+            return buf
+        except Exception as ex:
+            print(ex)
+        finally:
+            hfive.close()
+
+    def read_data(self, hfive, paths):
+        for path in paths:
+            yield path, hfive[path]
+
+    def datasets(self, hfive, start_time, **kwargs):
+        logger = logging.getLogger('app')
+
+        day_stamp = self.day_stamp(start_time)
+        sday = f'{day_stamp}'
+        root = hfive.require_group('/')
+        days = self._days(root)
+        if sday not in days:
+            return False
+
+        group = hfive.require_group(sday)
+        dsets = self.dir(group)
+
+        chname = quality = card_type = amount = None
+        for key, val in kwargs.items():
+            if val is None:
+                continue
+
+            if key == 'chname':
+                chname = val
+            elif key == 'quality':
+                quality = f'{val}'
+            elif key == 'card_type':
+                card_type = f'{val}'
+            elif key == 'amount':
+                amount = f'{val}'
+            else:
+                continue
+        return self._filter(dsets, chname=chname, quality=quality, card_type=card_type, amount=amount)
+
+    def _filter(self, dsets, chname=None, quality=None, card_type=None, amount=None):
+        filer_text = ''
+        if chname is not None:
+            filer_text = chname
+        if quality is not None:
+            filer_text = filer_text + f"-qua:{quality}"
+        if card_type is not None:
+            filer_text = filer_text + f"-type:{card_type}"
+        if amount is not None:
+            filer_text = filer_text + f"-amount:{amount}"
+
+        paths = []
+        for text in dsets:
+            items = re.split(r'/', text)
+            if len(items) != 6:
+                return False
+            (_, _sday, _chname, _quality, _card_type, _amount) = items
+            if (chname is not None) and (_chname != chname):
+                continue
+            if (quality is not None) and (_quality != quality):
+                continue
+            if (card_type is not None) and (_card_type != card_type):
+                continue
+            if (amount is not None) and (_amount != amount):
+                continue
+            paths.append(text)
+
+        return filer_text, paths
+
+    def _draw_plot(self, ax, x, day_stamp, start_pos, end_pos, data, interval=300, path=''):
+        # 'commit-succ': 0, 'commit-fail': 1, 'notify-succ': 2, 'notify-fail': 3, 'user_succ': 4
+        logging.getLogger('app').debug("path=%s", path)
+        all = data[2] + data[3]
+        all = all.reshape((-1, interval))
+        all = np.sum(all, axis=1)
+
+        ySucc = data[2]
+        ySucc = ySucc.reshape((-1, interval))
+        ySucc = np.sum(ySucc, axis=1)
+
+        if end_pos == -1:
+            pos = np.where(x >= start_pos)
+            x = x[pos]
+            ySucc = ySucc[pos]
+            all = all[pos]
+        else:
+            pos = np.where(start_pos <= x)
+            x = x[pos]
+            ySucc = ySucc[pos]
+            all = all[pos]
+
+            pos = np.where(x < end_pos)
+            x = x[pos]
+            ySucc = ySucc[pos]
+            all = all[pos]
+
+        succ_count = int(np.sum(ySucc))
+        all_count = int(np.sum(all))
+
+        opened = np.where(ySucc > 0.000001)
+        if len(opened[0]) == 0:
+            logging.getLogger('app').debug("path=%s,opened=False", path)
+            return False
+
+        ySucc = ySucc / (all + 0.00000001)
+        xs = np.array([stime.strftime('%H:%M', stime.localtime(d + day_stamp)) for d in x])
+        ax.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=0))
+        ax.plot(xs, ySucc, ls='--', marker='o', label=self._label(path, succ_count, all_count))
+        return True
+
+    def _label(self, path, count, all):
+        ratio = 0.00
+        if all > 0:
+            ratio = round(count * 100 / all, 2)
+
+        items = re.split(r'/', path)
+        if len(items) == 6:
+            (_, _sday, _chname, _quality, _card_type, _amount) = items
+            card_type = ''
+            if _card_type == '1':
+                card_type = 'SY'
+            elif _card_type == '2':
+                card_type = 'SH'
+            elif _card_type == '4':
+                card_type = 'YD'
+            elif _card_type == '5':
+                card_type = 'LT'
+            elif _card_type == '6':
+                card_type = 'DX'
+            return f"{_chname}-{_quality}-{card_type}-{_amount}:{count}/{all} = {ratio}%"
+        else:
+            if path == '' or path is None:
+                path = 'average'
+            return f"{path}:{count}/{all} = {ratio}%"
+
+
+dataCenter = DataCenter()

+ 0 - 2
plot/app.py

@@ -23,7 +23,6 @@ app.debug = True
 
 curname = __name__
 
-
 @app.route('/plot/index')
 def index():
     time_stamp = request.args.get('time_stamp')
@@ -51,7 +50,6 @@ def index():
     data = base64.b64encode(buf.getbuffer()).decode("ascii")
     return f"<img src='data:image/png;base64,{data}'/>"
 
-
 @app.route('/plot/days')
 def days():
     dates = dataCenter.days()

+ 23 - 0
plot/mchreader.py

@@ -0,0 +1,23 @@
+from DataCenter import dataCenter
+import signal as sig
+import sys,getopt
+
+if __name__ == '__main__':
+    try:
+        opts, args = getopt.getopt(sys.argv[1:],"h:p:",["host=",'port='])
+    except Exception as ex:
+        print(ex)
+        sys.exit(2)
+
+    rhost = ''
+    rport=6379
+    for o, val in opts:
+        if o in ("-h", "--host"):
+            rhost = val
+        elif o in ('-p', "--port"):
+            rport = int(val)
+        else:
+            print("Err argv")
+    dataCenter.set_redis(rhost,rport)
+    sig.signal(sig.SIGINT, lambda: dataCenter.stop())
+    dataCenter.prepare_data()

+ 5 - 3
rdispatcher/proxy.php

@@ -43,8 +43,6 @@ class proxy
             $params['card_type'] = $card_type;
             $params['regin_no'] = $regin_no;
 
-            refill\util::incr_user_commit($card_type,$amount);
-
             global $config;
             if($config['phone_life_check'] == true && $card_type != mtopcard\PetroChinaCard && $card_type != mtopcard\SinopecCard) {
                 $need_check = true;
@@ -52,6 +50,10 @@ class proxy
         }
 
         [$org_quality,$quality] = refill\RefillFactory::instance()->find_quality($mchid,$amount,$card_type,$org_quality,$commit_times,time() - $order_time);
+        if($card_type == 0) {
+            refill\util::incr_user_commit($mchid,$card_type,$amount,$org_quality);
+        }
+
         if ($need_check)
         {
             $valided = mtopcard\valid_phone($card_no);
@@ -178,7 +180,7 @@ class proxy
             'quantity' => $quantity,
             'third_card_type' => $third_card_type];
 
-        refill\util::incr_user_commit($card_type,$amount);
+        refill\util::incr_user_commit($mchid,$card_type,$amount,$org_quality);
 
         [$errcode, $errmsg, $order_id, $neterr] = refill\RefillFactory::instance()->add($mchid, $buyer_id, $amount, $card_no,
             $mch_order, $idcard, $card_name, $notify_url, $org_quality,$org_quality,