瀏覽代碼

初始化

tgz 2 年之前
父節點
當前提交
41ccea56a5
共有 100 個文件被更改,包括 9643 次插入37 次删除
  1. 6 7
      .gitignore
  2. 17 4
      LICENSE
  3. 14 9
      README.md
  4. 37 0
      app/command/Test.php
  5. 20 0
      app/controller/Track.php
  6. 63 0
      app/functions.php
  7. 61 0
      app/middleware/ExternalSignCheck.php
  8. 42 0
      app/middleware/StaticFile.php
  9. 48 0
      app/model/DouyinTrack.php
  10. 32 0
      app/model/TableSuffix.php
  11. 29 0
      app/model/Test.php
  12. 23 0
      app/queue/redis/TiktokTrack.php
  13. 11 0
      app/services/BaseService.php
  14. 96 0
      app/services/TrackService.php
  15. 14 0
      app/view/index/view.html
  16. 67 17
      composer.json
  17. 3086 0
      composer.lock
  18. 24 0
      config/app.php
  19. 21 0
      config/autoload.php
  20. 18 0
      config/bootstrap.php
  21. 15 0
      config/container.php
  22. 35 0
      config/database.php
  23. 15 0
      config/dependence.php
  24. 17 0
      config/exception.php
  25. 37 0
      config/log.php
  26. 15 0
      config/middleware.php
  27. 4 0
      config/plugin/kriss/webman-logger/app.php
  28. 88 0
      config/plugin/kriss/webman-logger/log-channel.php
  29. 7 0
      config/plugin/kriss/webman-logger/middleware.php
  30. 44 0
      config/plugin/tinywan/exception-handler/app.php
  31. 69 0
      config/plugin/tinywan/jwt/app.php
  32. 18 0
      config/plugin/webman/console/app.php
  33. 4 0
      config/plugin/webman/log/app.php
  34. 21 0
      config/plugin/webman/log/middleware.php
  35. 4 0
      config/plugin/webman/redis-queue/app.php
  36. 7 0
      config/plugin/webman/redis-queue/command.php
  37. 11 0
      config/plugin/webman/redis-queue/process.php
  38. 13 0
      config/plugin/webman/redis-queue/redis.php
  39. 40 0
      config/process.php
  40. 22 0
      config/redis.php
  41. 20 0
      config/route.php
  42. 31 0
      config/server.php
  43. 61 0
      config/session.php
  44. 23 0
      config/static.php
  45. 25 0
      config/translation.php
  46. 22 0
      config/view.php
  47. 195 0
      process/Monitor.php
  48. 28 0
      process/Task.php
  49. 12 0
      public/404.html
  50. 二進制
      public/favicon.ico
  51. 4 0
      runtime/.gitignore
  52. 2 0
      runtime/logs/.gitignore
  53. 2 0
      runtime/views/.gitignore
  54. 117 0
      start.php
  55. 55 0
      support/Plugin.php
  56. 24 0
      support/Request.php
  57. 24 0
      support/Response.php
  58. 90 0
      support/bootstrap.php
  59. 11 0
      support/facade/Logger.php
  60. 480 0
      support/helpers.php
  61. 7 0
      webman/.gitignore
  62. 21 0
      webman/LICENSE
  63. 16 0
      webman/README.md
  64. 37 0
      webman/app/command/Test.php
  65. 20 0
      webman/app/controller/Track.php
  66. 63 0
      webman/app/functions.php
  67. 61 0
      webman/app/middleware/ExternalSignCheck.php
  68. 42 0
      webman/app/middleware/StaticFile.php
  69. 48 0
      webman/app/model/DouyinTrack.php
  70. 32 0
      webman/app/model/TableSuffix.php
  71. 29 0
      webman/app/model/Test.php
  72. 23 0
      webman/app/queue/redis/TiktokTrack.php
  73. 11 0
      webman/app/services/BaseService.php
  74. 96 0
      webman/app/services/TrackService.php
  75. 14 0
      webman/app/view/index/view.html
  76. 69 0
      webman/composer.json
  77. 3086 0
      webman/composer.lock
  78. 24 0
      webman/config/app.php
  79. 21 0
      webman/config/autoload.php
  80. 18 0
      webman/config/bootstrap.php
  81. 15 0
      webman/config/container.php
  82. 35 0
      webman/config/database.php
  83. 15 0
      webman/config/dependence.php
  84. 17 0
      webman/config/exception.php
  85. 37 0
      webman/config/log.php
  86. 15 0
      webman/config/middleware.php
  87. 4 0
      webman/config/plugin/kriss/webman-logger/app.php
  88. 88 0
      webman/config/plugin/kriss/webman-logger/log-channel.php
  89. 7 0
      webman/config/plugin/kriss/webman-logger/middleware.php
  90. 44 0
      webman/config/plugin/tinywan/exception-handler/app.php
  91. 69 0
      webman/config/plugin/tinywan/jwt/app.php
  92. 18 0
      webman/config/plugin/webman/console/app.php
  93. 4 0
      webman/config/plugin/webman/log/app.php
  94. 21 0
      webman/config/plugin/webman/log/middleware.php
  95. 4 0
      webman/config/plugin/webman/redis-queue/app.php
  96. 7 0
      webman/config/plugin/webman/redis-queue/command.php
  97. 11 0
      webman/config/plugin/webman/redis-queue/process.php
  98. 13 0
      webman/config/plugin/webman/redis-queue/redis.php
  99. 40 0
      webman/config/process.php
  100. 0 0
      webman/config/redis.php

+ 6 - 7
.gitignore

@@ -1,8 +1,7 @@
-# ---> Laravel
-/bootstrap/compiled.php
-.env.*.php
-.env.php
+/.idea
+/.vscode
+/vendor
+*.log
 .env
-
-
-/vendor/
+/tests/tmp
+/tests/.phpunit.result.cache

+ 17 - 4
LICENSE

@@ -1,8 +1,21 @@
 MIT License
-Copyright (c) <year> <copyright holders>
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+Copyright (c) 2021 walkor<walkor@workerman.net> and contributors (see https://github.com/walkor/webman/contributors)
 
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 14 - 9
README.md

@@ -1,11 +1,16 @@
-# general_channel
+# webman
 
-追书云分销公共模块
+High performance HTTP Service Framework for PHP based on [Workerman](https://github.com/walkor/workerman).
 
-1.App\Consts\ 对应项目要有自身的配置;
-2.App\Controllers\ 控制器要有继承 重写或扩写自身项目的逻辑;
-3.App\Service\ 对应项目要继承相应的类 扩写自身项目的逻辑;
-4.composer require genneral/channel=@dev 一般直接用这个,如果有稳定的包版本可以往下走
-5.项目代码更新需要标记版本 https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%89%93%E6%A0%87%E7%AD%BE git 版本控制; 
-6.更新包管理平台 服务器上执行/usr/local/php/bin/php /usr/local/satis/bin/satis build /usr/local/satis/satis.json /usr/local/satis/repo 更新包的最新信息; https://comstock.zhuishuyun.com/ 查看有无对应包
-7.composer 包安装 composer require genneral/channel {包版本号} -vvv ;.composer 包更新 composer update genneral/channel {包版本号} -vvv 
+# Manual
+
+https://www.workerman.net/doc/webman
+
+# Benchmarks
+
+https://www.techempower.com/benchmarks/#section=test&runid=9716e3cd-9e53-433c-b6c5-d2c48c9593c1&hw=ph&test=db&l=zg24n3-1r&a=2
+![image](https://user-images.githubusercontent.com/6073368/96447814-120fc980-1245-11eb-938d-6ea408716c72.png)
+
+## LICENSE
+
+MIT

+ 37 - 0
app/command/Test.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace app\command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Output\OutputInterface;
+
+
+class Test extends Command
+{
+    protected static $defaultName = 'Test:t1';
+    protected static $defaultDescription = 'Test';
+
+    /**
+     * @return void
+     */
+    protected function configure()
+    {
+        $this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return int
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $name = $input->getArgument('name');
+        $output->writeln('Hello Test');
+        return self::SUCCESS;
+    }
+
+}

+ 20 - 0
app/controller/Track.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace app\controller;
+
+use support\Request;
+use support\Db;
+use App\services\TrackService;
+use support\facade\Logger;
+
+class Track
+{
+    public function index(Request $request)
+    {
+        $params = $request->all();
+        //Logger::app($params);
+        TrackService::push($params);
+        return 'success' ;
+    }
+
+}

+ 63 - 0
app/functions.php

@@ -0,0 +1,63 @@
+<?php
+use Hashids\Hashids;
+
+/**
+ * Here is your custom functions.
+ */
+    /*
+    快速排序
+*/
+function quickSort($array)
+{
+    if(!isset($array[1]))
+        return $array;
+    $mid = $array[0]; //获取一个用于分割的关键字,一般是首个元素
+    $leftArray = array();
+    $rightArray = array();
+
+    foreach($array as $v)
+    {
+        if($v > $mid)
+            $rightArray[] = $v;  //把比$mid大的数放到一个数组里
+        if($v < $mid)
+            $leftArray[] = $v;   //把比$mid小的数放到另一个数组里
+    }
+
+    $leftArray = quickSort($leftArray); //把比较小的数组再一次进行分割
+    $leftArray[] = $mid;        //把分割的元素加到小的数组后面,不能忘了它哦
+
+    $rightArray = quickSort($rightArray);  //把比较大的数组再一次进行分割
+    return array_merge($leftArray,$rightArray);  //组合两个结果
+}
+
+// 获取Hashids 对象
+function getHashids(){
+    global $hashids;
+    if($hashids instanceof Hashids ){
+        return $hashids;
+    }
+    $hashids = new Hashids('D6M97LIvpp4qWuz3nKzqi6yYN4GAA61b',32);
+    return $hashids;
+    
+}
+
+/**
+ * 获取对象或数组的属性值
+ * @param        $param
+ * @param        $key
+ * @param string $default
+ * @return mixed|string
+ */
+function getProp($param, $key, $default = '')
+{
+    $result = $default;
+    if (is_object($param) && isset($param->$key)) {
+        $result = $param->$key;
+    }
+
+    if (is_array($param) && isset($param[$key])) {
+        $result = $param[$key];
+    }
+
+    return $result;
+}

+ 61 - 0
app/middleware/ExternalSignCheck.php

@@ -0,0 +1,61 @@
+<?php
+namespace App\Middleware;
+
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+class ExternalSignCheck implements MiddlewareInterface
+{
+    
+    public function process(Request $request, callable $next): Response
+    {
+        // Access to files beginning with. Is prohibited
+        if (strpos($request->path(), '/.') !== false) {
+            return response('<h1>403 forbidden</h1>', 403);
+        }
+        /** @var Response $response */
+        $response = $next($request);
+        // Add cross domain HTTP header
+        /*$response->withHeaders([
+            'Access-Control-Allow-Origin'      => '*',
+            'Access-Control-Allow-Credentials' => 'true',
+        ]);*/
+        return $response;
+    }
+    
+    /**
+     * 外部通用 判断签名是否正确.
+     */
+    public function handle($request, Closure $next)
+    {
+        $timestamp = !empty($request->get('timestamp'))?$request->get('timestamp'):'';
+        $sign = !empty($request->get('sign'))?$request->get('sign'):'';
+        $response = $next($request);
+
+        return $response;
+    }
+    
+    public function sign($params, $key)
+    {
+        $data = $params;
+        //签名步骤一:按字典序排序参数
+        ksort($data);
+        $buff = "";
+        foreach ($data as $k => $v) {
+            if ($v != null && $k !== "sign" && $v !== "" && !is_array($v)) {
+                $buff .= $k . "=" . $v . "&";
+            }
+        }
+        $buff = trim($buff, "&");
+        //签名步骤二:在string后加入KEY
+        $string = $buff . "&key=" . $key;
+//        \Log::info('Seconds_string:'.$string.'Seconds_key:'.$key);
+        //签名步骤三:MD5加密
+        $string = md5($string);
+        //签名步骤四:所有字符转为大写
+        $result = strtoupper($string);
+        
+        return $result;
+    }
+}

+ 42 - 0
app/middleware/StaticFile.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace app\middleware;
+
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+/**
+ * Class StaticFile
+ * @package app\middleware
+ */
+class StaticFile implements MiddlewareInterface
+{
+    public function process(Request $request, callable $next): Response
+    {
+        // Access to files beginning with. Is prohibited
+        if (strpos($request->path(), '/.') !== false) {
+            return response('<h1>403 forbidden</h1>', 403);
+        }
+        /** @var Response $response */
+        $response = $next($request);
+        // Add cross domain HTTP header
+        /*$response->withHeaders([
+            'Access-Control-Allow-Origin'      => '*',
+            'Access-Control-Allow-Credentials' => 'true',
+        ]);*/
+        return $response;
+    }
+}

+ 48 - 0
app/model/DouyinTrack.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\model;
+
+//use Illuminate\Database\Eloquent\Model;
+use support\Model;
+
+/**
+ * Class DouyinTrack
+ * @package App\Models
+ * @version April 8, 2020, 2:05 pm CST
+ *
+ * @property string $link_source
+ * @property string $link
+ * @property string $source
+ * @property string $ip_ua
+ * @property string $distribution_channel_id
+ * @property string $click_id
+ * @property string $ua
+ * @property string $ip
+ * @property string $log_time
+ * @property string $adid
+ */
+class DouyinTrack extends Model
+{
+    use TableSuffix;
+
+    public $table = 'douyin_tracks';
+
+    const CREATED_AT = 'created_at';
+    const UPDATED_AT = 'updated_at';
+    
+    protected $connection = 'mysql';
+
+    public $fillable = [
+        'link_source',
+        'link',
+        'source',
+        'ip_ua',
+        'distribution_channel_id',
+        'click_id',
+        'ua',
+        'ip',
+        'log_time',
+        'adid',
+        'callback',
+    ];
+}

+ 32 - 0
app/model/TableSuffix.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\model;
+
+trait TableSuffix
+{
+    private static $suffix;
+
+    public static function suffix($suffix)
+    {
+        static::$suffix = $suffix;
+    }
+
+    public function __construct(array $attributes = [])
+    {
+        $this->table .= static::$suffix;
+        parent::__construct($attributes);
+    }
+
+    public static function model(int $month = 0)
+    {
+        $suffix = '';
+        if ($month == 0) {
+            $suffix = date('Ym');
+        } else {
+            $suffix = date('Ym', strtotime("last day of {$month} month"));
+        }
+        self::suffix($suffix);
+        $model = new self;
+        return $model;
+    }
+}

+ 29 - 0
app/model/Test.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace app\model;
+
+use support\Model;
+
+class Test extends Model
+{
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'test';
+
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected $primaryKey = 'id';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = false;
+}

+ 23 - 0
app/queue/redis/TiktokTrack.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace app\queue\redis;
+
+use Webman\RedisQueue\Consumer;
+use App\services\TrackService;
+use support\facade\Logger;
+
+class TiktokTrack implements Consumer
+{
+    // 要消费的队列名
+    public $queue = 'tiktok_track';
+
+    // 连接名,对应 plugin/webman/redis-queue/redis.php 里的连接`
+    public $connection = 'default';
+
+    // 消费
+    public function consume($data)
+    {
+        //Logger::app(time());
+        TrackService::cronDeal();
+    }
+}

+ 11 - 0
app/services/BaseService.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace App\services;
+
+
+class BaseService
+{
+    public static function test (){
+        return 111;
+    }
+}

+ 96 - 0
app/services/TrackService.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\services;
+
+use App\model\DouyinTrack;
+use support\Redis;
+use support\Log;
+use support\facade\Logger;
+
+class TrackService 
+{
+    
+    /**
+     *  把请求信息,放到redis队列中
+     */
+    public static function push ($params){
+        $dycallback = getProp($params,'dycallback');
+        switch ($dycallback) {
+            case 1:
+                //投递队列
+                $params['log_time'] = date('Y-m-d H:i:s',time());
+                Redis::lpush('tiktok_track',json_encode($params));
+                // if (!Redis::get('tiktok_track_deal_lock')) { // 锁住
+                //     Redis::setEx('tiktok_track_deal_lock',1,1);
+                //     self::TiktokRedisDeal();
+                // }
+                break;
+            default:
+                // code...
+                break;
+        }
+    }
+    
+    /**
+     *  定时任务批量处理
+     */
+    public static function cronDeal (){
+        // 处理巨量平台的
+        self::TiktokRedisDeal();
+    }
+    
+    /**
+     *  批量处理 巨量 平台发送过来的检测链接 数据信息。-避免过多的install
+     */
+    public static function TiktokRedisDeal ($data= []){
+        if (!$data) {
+            $len = Redis::llen('tiktok_track');
+            //Logger::app('tiktok_track:len'.$len);
+            if($len > 4000){
+                $len= 4000;
+            }
+            for ($i = 1; $i <= $len; $i++) {
+                 $data[] = Redis::rpop('tiktok_track');
+            }
+        }
+        if(empty($data)){
+            return false;
+        }
+        $inster = [] ;
+        $model =  DouyinTrack::model();
+        foreach ($data as $val){
+           $params = json_decode($val,true);
+           if(!getProp($params,'channel_id','')){
+               continue;
+           }
+            //整理数据+
+           $inster[] = [
+                'link' => getProp($params,'link',''),
+                'link_source' => 'tiktok',
+                'ip' => getProp($params,'ip',''),
+                'ua' => getProp($params,'ua',''),
+                'source' => 'zsy',
+                'ip_ua' => md5(getProp($params,'ip','') . getProp($params,'ua','')),
+                'distribution_channel_id' => getProp($params,'channel_id',''),
+                'log_time' => getProp($params,'log_time',''),
+                'created_at' => date('Y-m-d H:i:s',time()),
+                'adid' => getProp($params,'adid',''),
+                'callback' => getProp($params,'clickid',''),
+                //新添加
+                'advertiser_id' => getProp($params,'advertiser_id',''),
+                'campaign_id' => getProp($params,'campaign_id',''),
+                'creativeid' => getProp($params,'creativeid',''),
+                
+            ];
+            if(count($inster) >= 2000){
+                $model->insert($inster);
+                $inster = [];
+            }
+        }
+        if ($inster) {
+            $model->insert($inster);
+        }
+    }
+    
+    
+}

+ 14 - 0
app/view/index/view.html

@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="shortcut icon" href="/favicon.ico"/>
+    <title>webman</title>
+
+</head>
+<body>
+hello <?=htmlspecialchars($name)?>
+</body>
+</html>

+ 67 - 17
composer.json

@@ -1,19 +1,69 @@
 {
-    "name": "general/channel",
-    "description": "分销公共模块",
-    "license": "MIT",
-    "type": "library",
-    "authors": [
-        {
-            "name": "fly",
-            "email": "flyingstarsan.yu@gmail.com"
-        }
-    ],
-    "require": {},
-    "autoload": {
-        "psr-4": {
-            "General\\": "src"
-        }
+  "name": "workerman/webman",
+  "type": "project",
+  "keywords": [
+    "high performance",
+    "http service"
+  ],
+  "homepage": "http://www.workerman.net",
+  "license": "MIT",
+  "description": "High performance HTTP Service Framework.",
+  "authors": [
+    {
+      "name": "walkor",
+      "email": "walkor@workerman.net",
+      "homepage": "http://www.workerman.net",
+      "role": "Developer"
+    }
+  ],
+  "support": {
+    "email": "walkor@workerman.net",
+    "issues": "https://github.com/walkor/webman/issues",
+    "forum": "http://wenda.workerman.net/",
+    "wiki": "http://workerman.net/doc/webman",
+    "source": "https://github.com/walkor/webman"
+  },
+  "require": {
+    "php": ">=7.2",
+    "workerman/webman-framework": "^1.3.14",
+    "monolog/monolog": "^2.0",
+    "psr/container": "^1.1.1",
+    "illuminate/database": "^9.17",
+    "illuminate/pagination": "^9.17",
+    "illuminate/events": "^9.20",
+    "symfony/var-dumper": "^6.1",
+    "tinywan/exception-handler": "^0.1.0",
+    "webman/console": "^1.0",
+    "hashids/hashids": "^4.1",
+    "vlucas/phpdotenv": "^5.4",
+    "illuminate/redis": "^9.20",
+    "webman/redis-queue": "^1.2",
+    "tinywan/jwt": "^1.3",
+    "workerman/crontab": "^1.0",
+    "webman/log": "^1.0",
+    "kriss/webman-logger": "^1.2"
+  },
+  "suggest": {
+    "ext-event": "For better performance. "
+  },
+  "autoload": {
+    "psr-4": {
+      "": "./",
+      "App\\": "./app"
     },
-    "minimum-stability": "dev"
-}
+    "files": [
+      "./support/helpers.php"
+    ]
+  },
+  "scripts": {
+    "post-package-install": [
+      "support\\Plugin::install"
+    ],
+    "post-package-update": [
+      "support\\Plugin::install"
+    ],
+    "pre-package-uninstall": [
+      "support\\Plugin::uninstall"
+    ]
+  }
+}

文件差異過大導致無法顯示
+ 3086 - 0
composer.lock


+ 24 - 0
config/app.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\Request;
+
+return [
+    'debug' => true,
+    'default_timezone' => 'Asia/Shanghai',
+    'request_class' => Request::class,
+    'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public',
+    'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime',
+    'controller_suffix' => '',
+];

+ 21 - 0
config/autoload.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'files' => [
+        base_path() . '/app/functions.php',
+        base_path() . '/support/Request.php',
+        base_path() . '/support/Response.php',
+    ]
+];

+ 18 - 0
config/bootstrap.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    support\bootstrap\Session::class,
+    support\bootstrap\LaravelDb::class,
+];

+ 15 - 0
config/container.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return new Webman\Container;

+ 35 - 0
config/database.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+//return [];
+return [
+     // 默认数据库
+     'default' => 'mysql',
+     // 各种数据库配置
+     'connections' => [
+         'mysql' => [
+             'driver'      => 'mysql',
+             'host'        =>   getenv('DB_HOST'),
+             'port'        =>   getenv('DB_PORT'),
+             'database'    =>   getenv('DB_DATABASE'),
+             'username'    =>   getenv('DB_USERNAME'),
+             'password'    =>   getenv('DB_PASSWORD'),
+             'unix_socket' =>  '',
+             'charset'     => 'utf8',
+             'collation'   => 'utf8_unicode_ci',
+             'prefix'      => '',
+             'strict'      => true,
+             'engine'      => null,
+         ]
+    ]
+ ];

+ 15 - 0
config/dependence.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [];

+ 17 - 0
config/exception.php

@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    '' => support\exception\Handler::class,
+];

+ 37 - 0
config/log.php

@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\facade\Logger;
+
+return array_merge(
+    [
+        'default' => [
+            'handlers' => [
+                [
+                    'class' => Monolog\Handler\RotatingFileHandler::class,
+                    'constructor' => [
+                        runtime_path() . '/logs/webman.log',
+                        7, //$maxFiles
+                        Monolog\Logger::DEBUG,
+                    ],
+                    'formatter' => [
+                        'class' => Monolog\Formatter\LineFormatter::class,
+                        'constructor' => [null, 'Y-m-d H:i:s', true],
+                    ],
+                ]
+            ],
+        ],
+    ],
+    Logger::getLogChannelConfigs(), // merge 这个
+);

+ 15 - 0
config/middleware.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [];

+ 4 - 0
config/plugin/kriss/webman-logger/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => true,
+];

+ 88 - 0
config/plugin/kriss/webman-logger/log-channel.php

@@ -0,0 +1,88 @@
+<?php
+
+use Kriss\WebmanLogger\Formatter\ChannelFormatter;
+use Kriss\WebmanLogger\Formatter\ChannelMixedFormatter;
+use Kriss\WebmanLogger\Processors\RequestRouteProcessor;
+use Kriss\WebmanLogger\Processors\RequestUidProcessor;
+use Kriss\WebmanLogger\Processors\CurrentUserProcessor;
+use Monolog\Processor\PsrLogMessageProcessor;
+
+return [
+    // channels
+    'channels' => [
+        'app',
+        'sql',
+    ],
+    // 记录等级,仅大于设定等级的日志才会真实写入日志文件
+    'levels' => [
+        // 默认等级
+        'default' => config('app.debug') ? 'debug' : 'info',
+        // 特殊的等级
+        'special' => [
+            //'channelName' => 'info',
+        ],
+    ],
+    // processors
+    'processors' => function () {
+        return [
+            new PsrLogMessageProcessor('Y-m-d H:i:s'),
+            new RequestRouteProcessor(),
+            new CurrentUserProcessor(function () {
+                // 返回当前用户id
+                return 0;
+            }),
+            new RequestUidProcessor(),
+        ];
+    },
+    // 模式
+    'modes' => [
+        // 按照channel分目录记录
+        'split' => [
+            'class' => Kriss\WebmanLogger\Mode\SplitMode::class,
+            'enable' => true,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelFormatter::class,
+            ],
+            'max_files' => 30, // 最大文件数
+        ],
+        // 将所有channel合并到一起记录
+        'mix' => [
+            'class' => Kriss\WebmanLogger\Mode\MixMode::class,
+            'enable' => false,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelMixedFormatter::class,
+            ],
+            'max_files' => 30, // 最大文件数
+            'name' => 'channelMixed', // 合并时的日志文件名
+        ],
+        // 控制台输出
+        'stdout' => [
+            'class' => Kriss\WebmanLogger\Mode\StdoutMode::class,
+            'enable' => false,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelMixedFormatter::class,
+            ],
+        ],
+        // 输出到 redis
+        'redis' => [
+            'class' => Kriss\WebmanLogger\Mode\RedisMode::class,
+            'enable' => false,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelFormatter::class,
+            ],
+            'redis' => function () {
+                return support\Redis::connection('default')->client();
+            },
+            'redis_key_prefix' => 'webmanLog:',
+            'redis_size' => 0,
+        ],
+    ],
+];

+ 7 - 0
config/plugin/kriss/webman-logger/middleware.php

@@ -0,0 +1,7 @@
+<?php
+
+return [
+    '' => [
+        Kriss\WebmanLogger\Middleware\RequestUid::class,
+    ],
+];

+ 44 - 0
config/plugin/tinywan/exception-handler/app.php

@@ -0,0 +1,44 @@
+<?php
+
+return [
+    'enable' => true,
+    // 错误异常配置
+    'exception_handler' => [
+        // 不需要记录错误日志
+        'dont_report' => [
+            Tinywan\ExceptionHandler\Exception\BadRequestHttpException::class,
+            Tinywan\ExceptionHandler\Exception\UnauthorizedHttpException::class,
+            Tinywan\ExceptionHandler\Exception\ForbiddenHttpException::class,
+            Tinywan\ExceptionHandler\Exception\NotFoundHttpException::class,
+            Tinywan\ExceptionHandler\Exception\RouteNotFoundException::class,
+            Tinywan\ExceptionHandler\Exception\TooManyRequestsHttpException::class,
+            Tinywan\ExceptionHandler\Exception\ServerErrorHttpException::class,
+            Tinywan\Validate\Exception\ValidateException::class,
+            Tinywan\Jwt\Exception\JwtTokenException::class
+        ],
+        // 自定义HTTP状态码
+        'status' => [
+            'validate' => 400, // 验证器异常
+            'jwt_token' => 401, // JWT 认证失败
+            'jwt_token_expired' => 402, // JWT 令牌过期
+            'server_error' => 500, // 服务器内部错误
+        ],
+        // 自定义响应消息
+        'body' => [
+            'code' => 0,
+            'msg' => '服务器内部异常',
+            'data' => null
+        ],
+        // 事件
+        'event' => [
+            'enable' => false,
+            // 钉钉机器人
+            'ding_talk' => [
+                'accessToken' => 'xxxxxxxxxxxxxxxx',
+                'secret' => 'xxxxxxxxxxxxxxxx',
+                'title' => '钉钉机器人异常通知',
+            ]
+        ],
+    ],
+
+];

+ 69 - 0
config/plugin/tinywan/jwt/app.php

@@ -0,0 +1,69 @@
+<?php
+
+return [
+    'enable' => true,
+    'jwt' => [
+        // 算法类型 HS256、HS384、HS512、RS256、RS384、RS512、ES256、ES384、Ed25519
+        'algorithms' => 'HS256',
+        // access令牌秘钥
+        'access_secret_key' => '2022d3d3LmJq',
+        // access令牌过期时间,单位:秒。默认 2 小时
+        'access_exp' => 7200,
+        // refresh令牌秘钥
+        'refresh_secret_key' => '2022KTxigxc9o50c',
+        // refresh令牌过期时间,单位:秒。默认 7 天
+        'refresh_exp' => 604800,
+        // refresh 令牌是否禁用,默认不禁用 false
+        'refresh_disable' => false,
+        // 令牌签发者
+        'iss' => 'webman.tinywan.cn',
+        // 时钟偏差冗余时间,单位秒。建议这个余地应该不大于几分钟。
+        'leeway' => 60,
+        // 单设备登录
+        'is_single_device' => false,
+        // 缓存令牌时间,单位:秒。默认 7 天
+        'cache_token_ttl' => 604800,
+        // 缓存令牌前缀
+        'cache_token_pre' => 'JWT:TOKEN:',
+        // 用户信息模型
+        'user_model' => function($uid){
+            return [];
+        },
+
+        /**
+         * access令牌私钥
+         */
+        'access_private_key' => <<<EOD
+-----BEGIN RSA PRIVATE KEY-----
+...
+-----END RSA PRIVATE KEY-----
+EOD,
+
+        /**
+         * access令牌公钥
+         */
+        'access_public_key' => <<<EOD
+-----BEGIN PUBLIC KEY-----
+...
+-----END PUBLIC KEY-----
+EOD,
+
+        /**
+         * refresh令牌私钥
+         */
+        'refresh_private_key' => <<<EOD
+-----BEGIN RSA PRIVATE KEY-----
+...
+-----END RSA PRIVATE KEY-----
+EOD,
+
+        /**
+         * refresh令牌公钥
+         */
+        'refresh_public_key' => <<<EOD
+-----BEGIN PUBLIC KEY-----
+...
+-----END PUBLIC KEY-----
+EOD,
+    ],
+];

+ 18 - 0
config/plugin/webman/console/app.php

@@ -0,0 +1,18 @@
+<?php
+return [
+    'enable'            => true,
+
+    'phar_file_output_dir'    => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
+
+    'phar_filename'     => 'webman.phar',
+
+    'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
+
+    'private_key_file'  => '', // The file path for certificate or OpenSSL private key file.
+
+    //'exclude_pattern'   => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
+
+    'exclude_files'     => [
+        '.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
+    ]
+];

+ 4 - 0
config/plugin/webman/log/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => false,
+];

+ 21 - 0
config/plugin/webman/log/middleware.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Webman\Log\Middleware;
+
+return [
+    '' => [
+        Middleware::class
+    ]
+];

+ 4 - 0
config/plugin/webman/redis-queue/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => true,
+];

+ 7 - 0
config/plugin/webman/redis-queue/command.php

@@ -0,0 +1,7 @@
+<?php
+
+use Webman\RedisQueue\Command\MakeConsumerCommand;
+
+return [
+    MakeConsumerCommand::class
+];

+ 11 - 0
config/plugin/webman/redis-queue/process.php

@@ -0,0 +1,11 @@
+<?php
+return [
+    'consumer'  => [
+        'handler'     => Webman\RedisQueue\Process\Consumer::class,
+        'count'       => 16, // 可以设置多进程同时消费
+        'constructor' => [
+            // 消费者类目录
+            'consumer_dir' => app_path() . '/queue/redis'
+        ]
+    ]
+];

+ 13 - 0
config/plugin/webman/redis-queue/redis.php

@@ -0,0 +1,13 @@
+<?php
+return [
+    'default' => [
+        'host' => 'redis://127.0.0.1:6379',
+        'options' => [
+            'auth' => null,       // 密码,字符串类型,可选参数
+            'db' => 0,            // 数据库
+            'prefix' => '',       // key 前缀
+            'max_attempts'  => 3, // 消费失败后,重试次数
+            'retry_seconds' => 3, // 重试间隔,单位秒
+        ]
+    ],
+];

+ 40 - 0
config/process.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+
+return [
+    // File update detection and automatic reload
+    'monitor' => [
+        'handler' => process\Monitor::class,
+        'reloadable' => false,
+        'constructor' => [
+            // Monitor these directories
+            'monitor_dir' => [
+                app_path(),
+                config_path(),
+                base_path() . '/process',
+                base_path() . '/support',
+                base_path() . '/resource',
+                base_path() . '/.env',
+            ],
+            // Files with these suffixes will be monitored
+            'monitor_extensions' => [
+                'php', 'html', 'htm', 'env'
+            ]
+        ]
+    ],
+    'cron' => [
+        'handler'  => process\Task::class
+    ]
+];

+ 22 - 0
config/redis.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'default' => [
+        'host' => getenv('REDIS_HOST'),
+        'password' => null,
+        'port' => getenv('REDIS_PORT'),
+        'database' => 0,
+    ],
+];

+ 20 - 0
config/route.php

@@ -0,0 +1,20 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Webman\Route;
+
+Route::any('/track', [app\controller\Track::class, 'index']);
+
+
+

+ 31 - 0
config/server.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'listen' => 'http://0.0.0.0:'.getenv('LISTEN_PORT'),
+    'transport' => 'tcp',
+    'context' => [],
+    'name' => 'webman',
+    'count' => cpu_count() * 5,
+    'user' => '',
+    'group' => '',
+    'reusePort' => false,
+    'event_loop' => '',
+    'stop_timeout' => 2,
+    'pid_file' => runtime_path() . '/webman.pid',
+    'status_file' => runtime_path() . '/webman.status',
+    'stdout_file' => runtime_path() . '/logs/stdout.log',
+    'log_file' => runtime_path() . '/logs/workerman.log',
+    'max_package_size' => 10 * 1024 * 1024
+];

+ 61 - 0
config/session.php

@@ -0,0 +1,61 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+
+    'type' => 'file', // or redis or redis_cluster
+
+    'handler' => Webman\FileSessionHandler::class,
+
+    'config' => [
+        'file' => [
+            'save_path' => runtime_path() . '/sessions',
+        ],
+        'redis' => [
+            'host' => '127.0.0.1',
+            'port' => 6379,
+            'auth' => '',
+            'timeout' => 2,
+            'database' => '',
+            'prefix' => 'redis_session_',
+        ],
+        'redis_cluster' => [
+            'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'],
+            'timeout' => 2,
+            'auth' => '',
+            'prefix' => 'redis_session_',
+        ]
+    ],
+
+    'session_name' => 'PHPSID',
+    
+    'auto_update_timestamp' => false,
+
+    'lifetime' => 7*24*60*60,
+
+    'cookie_lifetime' => 365*24*60*60,
+
+    'cookie_path' => '/',
+
+    'domain' => '',
+    
+    'http_only' => true,
+
+    'secure' => false,
+    
+    'same_site' => '',
+
+    'gc_probability' => [1, 1000],
+
+];

+ 23 - 0
config/static.php

@@ -0,0 +1,23 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+/**
+ * Static file settings
+ */
+return [
+    'enable' => true,
+    'middleware' => [     // Static file Middleware
+        //app\middleware\StaticFile::class,
+    ],
+];

+ 25 - 0
config/translation.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+/**
+ * Multilingual configuration
+ */
+return [
+    // Default language
+    'locale' => 'zh_CN',
+    // Fallback language
+    'fallback_locale' => ['zh_CN', 'en'],
+    // Folder where language files are stored
+    'path' => base_path() . '/resource/translations',
+];

+ 22 - 0
config/view.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\view\Raw;
+use support\view\Twig;
+use support\view\Blade;
+use support\view\ThinkPHP;
+
+return [
+    'handler' => Raw::class
+];

+ 195 - 0
process/Monitor.php

@@ -0,0 +1,195 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace process;
+
+use Workerman\Timer;
+use Workerman\Worker;
+
+/**
+ * Class FileMonitor
+ * @package process
+ */
+class Monitor
+{
+    /**
+     * @var array
+     */
+    protected $_paths = [];
+
+    /**
+     * @var array
+     */
+    protected $_extensions = [];
+
+    /**
+     * FileMonitor constructor.
+     * @param $monitor_dir
+     * @param $monitor_extensions
+     * @param $memory_limit
+     */
+    public function __construct($monitor_dir, $monitor_extensions, $memory_limit = null)
+    {
+        $this->_paths = (array)$monitor_dir;
+        $this->_extensions = $monitor_extensions;
+        if (!Worker::getAllWorkers()) {
+            return;
+        }
+        $disable_functions = explode(',', ini_get('disable_functions'));
+        if (in_array('exec', $disable_functions, true)) {
+            echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n";
+        } else {
+            if (!Worker::$daemonize) {
+                Timer::add(1, function () {
+                    $this->checkAllFilesChange();
+                });
+            }
+        }
+
+        $memory_limit = $this->getMemoryLimit($memory_limit);
+        if ($memory_limit && DIRECTORY_SEPARATOR === '/') {
+            Timer::add(60, [$this, 'checkMemory'], [$memory_limit]);
+        }
+    }
+
+    /**
+     * @param $monitor_dir
+     */
+    public function checkFilesChange($monitor_dir)
+    {
+        static $last_mtime, $too_many_files_check;
+        if (!$last_mtime) {
+            $last_mtime = time();
+        }
+        clearstatcache();
+        if (!is_dir($monitor_dir)) {
+            if (!is_file($monitor_dir)) {
+                return;
+            }
+            $iterator = [new \SplFileInfo($monitor_dir)];
+        } else {
+            // recursive traversal directory
+            $dir_iterator = new \RecursiveDirectoryIterator($monitor_dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS);
+            $iterator = new \RecursiveIteratorIterator($dir_iterator);
+        }
+        $count = 0;
+        foreach ($iterator as $file) {
+            $count ++;
+            /** var SplFileInfo $file */
+            if (is_dir($file)) {
+                continue;
+            }
+            // check mtime
+            if ($last_mtime < $file->getMTime() && in_array($file->getExtension(), $this->_extensions, true)) {
+                $var = 0;
+                exec(PHP_BINARY . " -l " . $file, $out, $var);
+                if ($var) {
+                    $last_mtime = $file->getMTime();
+                    continue;
+                }
+                $last_mtime = $file->getMTime();
+                echo $file . " update and reload\n";
+                // send SIGUSR1 signal to master process for reload
+                if (DIRECTORY_SEPARATOR === '/') {
+                    posix_kill(posix_getppid(), SIGUSR1);
+                } else {
+                    return true;
+                }
+                break;
+            }
+        }
+        if (!$too_many_files_check && $count > 1000) {
+            echo "Monitor: There are too many files ($count files) in $monitor_dir which makes file monitoring very slow\n";
+            $too_many_files_check = 1;
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    public function checkAllFilesChange()
+    {
+        foreach ($this->_paths as $path) {
+            if ($this->checkFilesChange($path)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param $memory_limit
+     * @return void
+     */
+    public function checkMemory($memory_limit)
+    {
+        $ppid = posix_getppid();
+        $children_file = "/proc/$ppid/task/$ppid/children";
+        if (!is_file($children_file) || !($children = file_get_contents($children_file))) {
+            return;
+        }
+        foreach (explode(' ', $children) as $pid) {
+            $pid = (int)$pid;
+            $status_file = "/proc/$pid/status";
+            if (!is_file($status_file) || !($status = file_get_contents($status_file))) {
+                continue;
+            }
+            $mem = 0;
+            if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) {
+                $mem = $match[1];
+            }
+            $mem = (int)($mem / 1024);
+            if ($mem >= $memory_limit) {
+                posix_kill($pid, SIGINT);
+            }
+        }
+    }
+
+    /**
+     * Get memory limit
+     * @return float
+     */
+    protected function getMemoryLimit($memory_limit)
+    {
+        if ($memory_limit === 0) {
+            return 0;
+        }
+        $use_php_ini = false;
+        if (!$memory_limit) {
+            $memory_limit = ini_get('memory_limit');
+            $use_php_ini = true;
+        }
+
+        if ($memory_limit == -1) {
+            return 0;
+        }
+        $unit = $memory_limit[strlen($memory_limit) - 1];
+        if ($unit == 'G') {
+            $memory_limit = 1024 * (int)$memory_limit;
+        } else if ($unit == 'M') {
+            $memory_limit = (int)$memory_limit;
+        } else if ($unit == 'K') {
+            $memory_limit = (int)($memory_limit / 1024);
+        } else {
+            $memory_limit = (int)($memory_limit / (1024 * 1024));
+        }
+        if ($memory_limit < 30) {
+            $memory_limit = 30;
+        }
+        if ($use_php_ini) {
+            $memory_limit = (int)(0.8 * $memory_limit);
+        }
+        return $memory_limit;
+    }
+}

+ 28 - 0
process/Task.php

@@ -0,0 +1,28 @@
+<?php
+namespace process;
+
+use Workerman\Crontab\Crontab;
+use support\Log;
+use App\services\TrackService;
+use Webman\RedisQueue\Redis;
+
+class Task
+{
+    public function onWorkerStart()
+    {
+        // 每一秒执行
+        new Crontab('*/1 * * * * *', function(){
+            //TrackService::cronDeal();
+            //echo date('Y-m-d H:i:s')."\n";
+             // 队列名
+            $queue = 'tiktok_track';
+            // 投递消息
+            Redis::send($queue, []);
+            // usleep(300000);
+            // Redis::send($queue, []);
+            // usleep(300000);
+            // Redis::send($queue, []);
+        });
+        
+    }
+}

+ 12 - 0
public/404.html

@@ -0,0 +1,12 @@
+<html>
+<head>
+    <title>404 Not Found - webman</title>
+</head>
+<body>
+<center>
+    <h1>404 Not Found</h1>
+</center>
+<hr>
+<center><a href="https://www.workerman.net">webman</a></center>
+</body>
+</html>

二進制
public/favicon.ico


+ 4 - 0
runtime/.gitignore

@@ -0,0 +1,4 @@
+*
+!logs
+!views
+!.gitignore

+ 2 - 0
runtime/logs/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 2 - 0
runtime/views/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 117 - 0
start.php

@@ -0,0 +1,117 @@
+#!/usr/bin/env php
+<?php
+require_once __DIR__ . '/vendor/autoload.php';
+
+use Workerman\Worker;
+use Workerman\Protocols\Http;
+use Workerman\Connection\TcpConnection;
+use Webman\App;
+use Webman\Config;
+use Webman\Route;
+use Webman\Middleware;
+use Dotenv\Dotenv;
+use support\Request;
+use support\Log;
+use support\Container;
+
+ini_set('display_errors', 'on');
+error_reporting(E_ALL);
+
+if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
+    if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
+        Dotenv::createUnsafeImmutable(base_path())->load();
+    } else {
+        Dotenv::createMutable(base_path())->load();
+    }
+}
+
+Config::load(config_path(), ['route', 'container']);
+
+$error_reporting = config('app.error_reporting');
+if (isset($error_reporting)) {
+    error_reporting($error_reporting);
+}
+
+if ($timezone = config('app.default_timezone')) {
+    date_default_timezone_set($timezone);
+}
+
+$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
+if ( !file_exists($runtime_logs_path) || !is_dir($runtime_logs_path) ) {
+    if (!mkdir($runtime_logs_path,0777,true)) {
+        throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
+    }
+}
+
+$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
+if ( !file_exists($runtime_views_path) || !is_dir($runtime_views_path) ) {
+    if (!mkdir($runtime_views_path,0777,true)) {
+        throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
+    }
+}
+
+Worker::$onMasterReload = function () {
+    if (function_exists('opcache_get_status')) {
+        if ($status = opcache_get_status()) {
+            if (isset($status['scripts']) && $scripts = $status['scripts']) {
+                foreach (array_keys($scripts) as $file) {
+                    opcache_invalidate($file, true);
+                }
+            }
+        }
+    }
+};
+
+$config = config('server');
+Worker::$pidFile = $config['pid_file'];
+Worker::$stdoutFile = $config['stdout_file'];
+Worker::$logFile = $config['log_file'];
+Worker::$eventLoopClass = $config['event_loop'] ?? '';
+TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10 * 1024 * 1024;
+if (property_exists(Worker::class, 'statusFile')) {
+    Worker::$statusFile = $config['status_file'] ?? '';
+}
+if (property_exists(Worker::class, 'stopTimeout')) {
+    Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
+}
+
+if ($config['listen']) {
+    $worker = new Worker($config['listen'], $config['context']);
+    $property_map = [
+        'name',
+        'count',
+        'user',
+        'group',
+        'reusePort',
+        'transport',
+        'protocol'
+    ];
+    foreach ($property_map as $property) {
+        if (isset($config[$property])) {
+            $worker->$property = $config[$property];
+        }
+    }
+
+    $worker->onWorkerStart = function ($worker) {
+        require_once base_path() . '/support/bootstrap.php';
+        $app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());
+        Http::requestClass(config('app.request_class', config('server.request_class', Request::class)));
+        $worker->onMessage = [$app, 'onMessage'];
+    };
+}
+
+// Windows does not support custom processes.
+if (\DIRECTORY_SEPARATOR === '/') {
+    foreach (config('process', []) as $process_name => $config) {
+        worker_start($process_name, $config);
+    }
+    foreach (config('plugin', []) as $firm => $projects) {
+        foreach ($projects as $name => $project) {
+            foreach ($project['process'] ?? [] as $process_name => $config) {
+                worker_start("plugin.$firm.$name.$process_name", $config);
+            }
+        }
+    }
+}
+
+Worker::runAll();

+ 55 - 0
support/Plugin.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace support;
+
+class Plugin
+{
+    public static function install($event)
+    {
+        static::findHepler();
+        $operation = $event->getOperation();
+        $autoload = method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload();
+        if (!isset($autoload['psr-4'])) {
+            return;
+        }
+        $namespace = key($autoload['psr-4']);
+        $install_function = "\\{$namespace}Install::install";
+        $plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
+        if (defined($plugin_const) && is_callable($install_function)) {
+            $install_function();
+        }
+    }
+
+    public static function update($event)
+    {
+        static::install($event);
+    }
+
+    public static function uninstall($event)
+    {
+        static::findHepler();
+        $autoload = $event->getOperation()->getPackage()->getAutoload();
+        if (!isset($autoload['psr-4'])) {
+            return;
+        }
+        $namespace = key($autoload['psr-4']);
+        $uninstall_function = "\\{$namespace}Install::uninstall";
+        $plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
+        if (defined($plugin_const) && is_callable($uninstall_function)) {
+            $uninstall_function();
+        }
+    }
+
+    protected static function findHepler()
+    {
+        // Plugin.php in vendor
+        $file = __DIR__ . '/../../../../../support/helpers.php';
+        if (is_file($file)) {
+            require_once $file;
+            return;
+        }
+        // Plugin.php in webman
+        require_once __DIR__ . '/helpers.php';
+    }
+
+}

+ 24 - 0
support/Request.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace support;
+
+/**
+ * Class Request
+ * @package support
+ */
+class Request extends \Webman\Http\Request
+{
+
+}

+ 24 - 0
support/Response.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace support;
+
+/**
+ * Class Response
+ * @package support
+ */
+class Response extends \Webman\Http\Response
+{
+
+}

+ 90 - 0
support/bootstrap.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Dotenv\Dotenv;
+use support\Container;
+use Webman\Config;
+use Webman\Route;
+use Webman\Middleware;
+
+$worker = $worker ?? null;
+
+if ($timezone = config('app.default_timezone')) {
+    date_default_timezone_set($timezone);
+}
+
+set_error_handler(function ($level, $message, $file = '', $line = 0, $context = []) {
+    if (error_reporting() & $level) {
+        throw new ErrorException($message, 0, $level, $file, $line);
+    }
+});
+
+if ($worker) {
+    register_shutdown_function(function ($start_time) {
+        if (time() - $start_time <= 1) {
+            sleep(1);
+        }
+    }, time());
+}
+
+if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
+    if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
+        Dotenv::createUnsafeImmutable(base_path())->load();
+    } else {
+        Dotenv::createMutable(base_path())->load();
+    }
+}
+
+Config::reload(config_path(), ['route', 'container']);
+
+foreach (config('plugin', []) as $firm => $projects) {
+    foreach ($projects as $name => $project) {
+        foreach ($project['autoload']['files'] ?? [] as $file) {
+            include_once $file;
+        }
+    }
+}
+
+foreach (config('autoload.files', []) as $file) {
+    include_once $file;
+}
+
+$container = Container::instance();
+Route::container($container);
+Middleware::container($container);
+
+Middleware::load(config('middleware', []));
+foreach (config('plugin', []) as $firm => $projects) {
+    foreach ($projects as $name => $project) {
+        Middleware::load($project['middleware'] ?? []);
+    }
+}
+Middleware::load(['__static__' => config('static.middleware', [])]);
+
+foreach (config('bootstrap', []) as $class_name) {
+    /** @var \Webman\Bootstrap $class_name */
+    $class_name::start($worker);
+}
+
+foreach (config('plugin', []) as $firm => $projects) {
+    foreach ($projects as $name => $project) {
+        foreach ($project['bootstrap'] ?? [] as $class_name) {
+            /** @var \Webman\Bootstrap $class_name */
+            $class_name::start($worker);
+        }
+    }
+}
+
+Route::load(config_path());
+

+ 11 - 0
support/facade/Logger.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace support\facade;
+
+/**
+ * @method static void app($msg, string $type = 'info', array $context = [])
+ * @method static void sql($msg, string $type = 'info', array $context = [])
+ */
+class Logger extends \Kriss\WebmanLogger\Logger
+{
+}

+ 480 - 0
support/helpers.php

@@ -0,0 +1,480 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\Request;
+use support\Response;
+use support\Translation;
+use support\Container;
+use support\view\Raw;
+use support\view\Blade;
+use support\view\ThinkPHP;
+use support\view\Twig;
+use Workerman\Worker;
+use Webman\App;
+use Webman\Config;
+use Webman\Route;
+
+// Phar support.
+if (is_phar()) {
+    define('BASE_PATH', dirname(__DIR__));
+} else {
+    define('BASE_PATH', realpath(__DIR__ . '/../'));
+}
+define('WEBMAN_VERSION', '1.3.0');
+
+/**
+ * @param $return_phar
+ * @return false|string
+ */
+function base_path($return_phar = true)
+{
+    static $real_path = '';
+    if (!$real_path) {
+        $real_path = is_phar() ? dirname(Phar::running(false)) : BASE_PATH;
+    }
+    return $return_phar ? BASE_PATH : $real_path;
+}
+
+/**
+ * @return string
+ */
+function app_path()
+{
+    return BASE_PATH . DIRECTORY_SEPARATOR . 'app';
+}
+
+/**
+ * @return string
+ */
+function public_path()
+{
+    static $path = '';
+    if (!$path) {
+        $path = config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public');
+    }
+    return $path;
+}
+
+/**
+ * @return string
+ */
+function config_path()
+{
+    return BASE_PATH . DIRECTORY_SEPARATOR . 'config';
+}
+
+/**
+ * Phar support.
+ * Compatible with the 'realpath' function in the phar file.
+ *
+ * @return string
+ */
+function runtime_path()
+{
+    static $path = '';
+    if (!$path) {
+        $path = config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime');
+    }
+    return $path;
+}
+
+/**
+ * @param int $status
+ * @param array $headers
+ * @param string $body
+ * @return Response
+ */
+function response($body = '', $status = 200, $headers = array())
+{
+    return new Response($status, $headers, $body);
+}
+
+/**
+ * @param $data
+ * @param int $options
+ * @return Response
+ */
+function json($data, $options = JSON_UNESCAPED_UNICODE)
+{
+    return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options));
+}
+
+/**
+ * @param $xml
+ * @return Response
+ */
+function xml($xml)
+{
+    if ($xml instanceof SimpleXMLElement) {
+        $xml = $xml->asXML();
+    }
+    return new Response(200, ['Content-Type' => 'text/xml'], $xml);
+}
+
+/**
+ * @param $data
+ * @param string $callback_name
+ * @return Response
+ */
+function jsonp($data, $callback_name = 'callback')
+{
+    if (!is_scalar($data) && null !== $data) {
+        $data = json_encode($data);
+    }
+    return new Response(200, [], "$callback_name($data)");
+}
+
+/**
+ * @param $location
+ * @param int $status
+ * @param array $headers
+ * @return Response
+ */
+function redirect($location, $status = 302, $headers = [])
+{
+    $response = new Response($status, ['Location' => $location]);
+    if (!empty($headers)) {
+        $response->withHeaders($headers);
+    }
+    return $response;
+}
+
+/**
+ * @param $template
+ * @param array $vars
+ * @param null $app
+ * @return Response
+ */
+function view($template, $vars = [], $app = null)
+{
+    static $handler;
+    if (null === $handler) {
+        $handler = config('view.handler');
+    }
+    return new Response(200, [], $handler::render($template, $vars, $app));
+}
+
+/**
+ * @param $template
+ * @param array $vars
+ * @param null $app
+ * @return Response
+ */
+function raw_view($template, $vars = [], $app = null)
+{
+    return new Response(200, [], Raw::render($template, $vars, $app));
+}
+
+/**
+ * @param $template
+ * @param array $vars
+ * @param null $app
+ * @return Response
+ */
+function blade_view($template, $vars = [], $app = null)
+{
+    return new Response(200, [], Blade::render($template, $vars, $app));
+}
+
+/**
+ * @param $template
+ * @param array $vars
+ * @param null $app
+ * @return Response
+ */
+function think_view($template, $vars = [], $app = null)
+{
+    return new Response(200, [], ThinkPHP::render($template, $vars, $app));
+}
+
+/**
+ * @param $template
+ * @param array $vars
+ * @param null $app
+ * @return Response
+ */
+function twig_view($template, $vars = [], $app = null)
+{
+    return new Response(200, [], Twig::render($template, $vars, $app));
+}
+
+/**
+ * @return Request
+ */
+function request()
+{
+    return App::request();
+}
+
+/**
+ * @param $key
+ * @param null $default
+ * @return mixed
+ */
+function config($key = null, $default = null)
+{
+    return Config::get($key, $default);
+}
+
+/**
+ * @param $name
+ * @param ...$parameters
+ * @return string
+ */
+function route($name, ...$parameters)
+{
+    $route = Route::getByName($name);
+    if (!$route) {
+        return '';
+    }
+
+    if (!$parameters) {
+        return $route->url();
+    }
+
+    if (is_array(current($parameters))) {
+        $parameters = current($parameters);
+    }
+
+    return $route->url($parameters);
+}
+
+/**
+ * @param mixed $key
+ * @param mixed $default
+ * @return mixed
+ */
+function session($key = null, $default = null)
+{
+    $session = request()->session();
+    if (null === $key) {
+        return $session;
+    }
+    if (\is_array($key)) {
+        $session->put($key);
+        return null;
+    }
+    if (\strpos($key, '.')) {
+        $key_array = \explode('.', $key);
+        $value = $session->all();
+        foreach ($key_array as $index) {
+            if (!isset($value[$index])) {
+                return $default;
+            }
+            $value = $value[$index];
+        }
+        return $value;
+    }
+    return $session->get($key, $default);
+}
+
+/**
+ * @param null|string $id
+ * @param array $parameters
+ * @param string|null $domain
+ * @param string|null $locale
+ * @return string
+ */
+function trans(string $id, array $parameters = [], string $domain = null, string $locale = null)
+{
+    $res = Translation::trans($id, $parameters, $domain, $locale);
+    return $res === '' ? $id : $res;
+}
+
+/**
+ * @param null|string $locale
+ * @return string
+ */
+function locale(string $locale = null)
+{
+    if (!$locale) {
+        return Translation::getLocale();
+    }
+    Translation::setLocale($locale);
+}
+
+/**
+ * 404 not found
+ *
+ * @return Response
+ */
+function not_found()
+{
+    return new Response(404, [], file_get_contents(public_path() . '/404.html'));
+}
+
+/**
+ * Copy dir.
+ * @param $source
+ * @param $dest
+ * @param bool $overwrite
+ * @return void
+ */
+function copy_dir($source, $dest, $overwrite = false)
+{
+    if (is_dir($source)) {
+        if (!is_dir($dest)) {
+            mkdir($dest);
+        }
+        $files = scandir($source);
+        foreach ($files as $file) {
+            if ($file !== "." && $file !== "..") {
+                copy_dir("$source/$file", "$dest/$file");
+            }
+        }
+    } else if (file_exists($source) && ($overwrite || !file_exists($dest))) {
+        copy($source, $dest);
+    }
+}
+
+/**
+ * Remove dir.
+ * @param $dir
+ * @return bool
+ */
+function remove_dir($dir)
+{
+    if (is_link($dir) || is_file($dir)) {
+        return unlink($dir);
+    }
+    $files = array_diff(scandir($dir), array('.', '..'));
+    foreach ($files as $file) {
+        (is_dir("$dir/$file") && !is_link($dir)) ? remove_dir("$dir/$file") : unlink("$dir/$file");
+    }
+    return rmdir($dir);
+}
+
+/**
+ * @param $worker
+ * @param $class
+ */
+function worker_bind($worker, $class)
+{
+    $callback_map = [
+        'onConnect',
+        'onMessage',
+        'onClose',
+        'onError',
+        'onBufferFull',
+        'onBufferDrain',
+        'onWorkerStop',
+        'onWebSocketConnect'
+    ];
+    foreach ($callback_map as $name) {
+        if (method_exists($class, $name)) {
+            $worker->$name = [$class, $name];
+        }
+    }
+    if (method_exists($class, 'onWorkerStart')) {
+        call_user_func([$class, 'onWorkerStart'], $worker);
+    }
+}
+
+/**
+ * @param $process_name
+ * @param $config
+ * @return void
+ */
+function worker_start($process_name, $config)
+{
+    $worker = new Worker($config['listen'] ?? null, $config['context'] ?? []);
+    $property_map = [
+        'count',
+        'user',
+        'group',
+        'reloadable',
+        'reusePort',
+        'transport',
+        'protocol',
+    ];
+    $worker->name = $process_name;
+    foreach ($property_map as $property) {
+        if (isset($config[$property])) {
+            $worker->$property = $config[$property];
+        }
+    }
+
+    $worker->onWorkerStart = function ($worker) use ($config) {
+        require_once base_path() . '/support/bootstrap.php';
+
+        foreach ($config['services'] ?? [] as $server) {
+            if (!class_exists($server['handler'])) {
+                echo "process error: class {$server['handler']} not exists\r\n";
+                continue;
+            }
+            $listen = new Worker($server['listen'] ?? null, $server['context'] ?? []);
+            if (isset($server['listen'])) {
+                echo "listen: {$server['listen']}\n";
+            }
+            $instance = Container::make($server['handler'], $server['constructor'] ?? []);
+            worker_bind($listen, $instance);
+            $listen->listen();
+        }
+
+        if (isset($config['handler'])) {
+            if (!class_exists($config['handler'])) {
+                echo "process error: class {$config['handler']} not exists\r\n";
+                return;
+            }
+
+            $instance = Container::make($config['handler'], $config['constructor'] ?? []);
+            worker_bind($worker, $instance);
+        }
+
+    };
+}
+
+/**
+ * Phar support.
+ * Compatible with the 'realpath' function in the phar file.
+ *
+ * @param string $file_path
+ * @return string
+ */
+function get_realpath(string $file_path): string
+{
+    if (strpos($file_path, 'phar://') === 0) {
+        return $file_path;
+    } else {
+        return realpath($file_path);
+    }
+}
+
+/**
+ * @return bool
+ */
+function is_phar()
+{
+    return class_exists(\Phar::class, false) && Phar::running();
+}
+
+/**
+ * @return int
+ */
+function cpu_count()
+{
+    // Windows does not support the number of processes setting.
+    if (\DIRECTORY_SEPARATOR === '\\') {
+        return 1;
+    }
+    $count = 4;
+    if (is_callable('shell_exec')) {
+        if (strtolower(PHP_OS) === 'darwin') {
+            $count = (int)shell_exec('sysctl -n machdep.cpu.core_count');
+        } else {
+            $count = (int)shell_exec('nproc');
+        }
+    }
+    return $count > 0 ? $count : 4;
+}

+ 7 - 0
webman/.gitignore

@@ -0,0 +1,7 @@
+/.idea
+/.vscode
+/vendor
+*.log
+.env
+/tests/tmp
+/tests/.phpunit.result.cache

+ 21 - 0
webman/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 walkor<walkor@workerman.net> and contributors (see https://github.com/walkor/webman/contributors)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 16 - 0
webman/README.md

@@ -0,0 +1,16 @@
+# webman
+
+High performance HTTP Service Framework for PHP based on [Workerman](https://github.com/walkor/workerman).
+
+# Manual
+
+https://www.workerman.net/doc/webman
+
+# Benchmarks
+
+https://www.techempower.com/benchmarks/#section=test&runid=9716e3cd-9e53-433c-b6c5-d2c48c9593c1&hw=ph&test=db&l=zg24n3-1r&a=2
+![image](https://user-images.githubusercontent.com/6073368/96447814-120fc980-1245-11eb-938d-6ea408716c72.png)
+
+## LICENSE
+
+MIT

+ 37 - 0
webman/app/command/Test.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace app\command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Output\OutputInterface;
+
+
+class Test extends Command
+{
+    protected static $defaultName = 'Test:t1';
+    protected static $defaultDescription = 'Test';
+
+    /**
+     * @return void
+     */
+    protected function configure()
+    {
+        $this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return int
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $name = $input->getArgument('name');
+        $output->writeln('Hello Test');
+        return self::SUCCESS;
+    }
+
+}

+ 20 - 0
webman/app/controller/Track.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace app\controller;
+
+use support\Request;
+use support\Db;
+use App\services\TrackService;
+use support\facade\Logger;
+
+class Track
+{
+    public function index(Request $request)
+    {
+        $params = $request->all();
+        //Logger::app($params);
+        TrackService::push($params);
+        return 'success' ;
+    }
+
+}

+ 63 - 0
webman/app/functions.php

@@ -0,0 +1,63 @@
+<?php
+use Hashids\Hashids;
+
+/**
+ * Here is your custom functions.
+ */
+    /*
+    快速排序
+*/
+function quickSort($array)
+{
+    if(!isset($array[1]))
+        return $array;
+    $mid = $array[0]; //获取一个用于分割的关键字,一般是首个元素
+    $leftArray = array();
+    $rightArray = array();
+
+    foreach($array as $v)
+    {
+        if($v > $mid)
+            $rightArray[] = $v;  //把比$mid大的数放到一个数组里
+        if($v < $mid)
+            $leftArray[] = $v;   //把比$mid小的数放到另一个数组里
+    }
+
+    $leftArray = quickSort($leftArray); //把比较小的数组再一次进行分割
+    $leftArray[] = $mid;        //把分割的元素加到小的数组后面,不能忘了它哦
+
+    $rightArray = quickSort($rightArray);  //把比较大的数组再一次进行分割
+    return array_merge($leftArray,$rightArray);  //组合两个结果
+}
+
+// 获取Hashids 对象
+function getHashids(){
+    global $hashids;
+    if($hashids instanceof Hashids ){
+        return $hashids;
+    }
+    $hashids = new Hashids('D6M97LIvpp4qWuz3nKzqi6yYN4GAA61b',32);
+    return $hashids;
+    
+}
+
+/**
+ * 获取对象或数组的属性值
+ * @param        $param
+ * @param        $key
+ * @param string $default
+ * @return mixed|string
+ */
+function getProp($param, $key, $default = '')
+{
+    $result = $default;
+    if (is_object($param) && isset($param->$key)) {
+        $result = $param->$key;
+    }
+
+    if (is_array($param) && isset($param[$key])) {
+        $result = $param[$key];
+    }
+
+    return $result;
+}

+ 61 - 0
webman/app/middleware/ExternalSignCheck.php

@@ -0,0 +1,61 @@
+<?php
+namespace App\Middleware;
+
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+class ExternalSignCheck implements MiddlewareInterface
+{
+    
+    public function process(Request $request, callable $next): Response
+    {
+        // Access to files beginning with. Is prohibited
+        if (strpos($request->path(), '/.') !== false) {
+            return response('<h1>403 forbidden</h1>', 403);
+        }
+        /** @var Response $response */
+        $response = $next($request);
+        // Add cross domain HTTP header
+        /*$response->withHeaders([
+            'Access-Control-Allow-Origin'      => '*',
+            'Access-Control-Allow-Credentials' => 'true',
+        ]);*/
+        return $response;
+    }
+    
+    /**
+     * 外部通用 判断签名是否正确.
+     */
+    public function handle($request, Closure $next)
+    {
+        $timestamp = !empty($request->get('timestamp'))?$request->get('timestamp'):'';
+        $sign = !empty($request->get('sign'))?$request->get('sign'):'';
+        $response = $next($request);
+
+        return $response;
+    }
+    
+    public function sign($params, $key)
+    {
+        $data = $params;
+        //签名步骤一:按字典序排序参数
+        ksort($data);
+        $buff = "";
+        foreach ($data as $k => $v) {
+            if ($v != null && $k !== "sign" && $v !== "" && !is_array($v)) {
+                $buff .= $k . "=" . $v . "&";
+            }
+        }
+        $buff = trim($buff, "&");
+        //签名步骤二:在string后加入KEY
+        $string = $buff . "&key=" . $key;
+//        \Log::info('Seconds_string:'.$string.'Seconds_key:'.$key);
+        //签名步骤三:MD5加密
+        $string = md5($string);
+        //签名步骤四:所有字符转为大写
+        $result = strtoupper($string);
+        
+        return $result;
+    }
+}

+ 42 - 0
webman/app/middleware/StaticFile.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace app\middleware;
+
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+/**
+ * Class StaticFile
+ * @package app\middleware
+ */
+class StaticFile implements MiddlewareInterface
+{
+    public function process(Request $request, callable $next): Response
+    {
+        // Access to files beginning with. Is prohibited
+        if (strpos($request->path(), '/.') !== false) {
+            return response('<h1>403 forbidden</h1>', 403);
+        }
+        /** @var Response $response */
+        $response = $next($request);
+        // Add cross domain HTTP header
+        /*$response->withHeaders([
+            'Access-Control-Allow-Origin'      => '*',
+            'Access-Control-Allow-Credentials' => 'true',
+        ]);*/
+        return $response;
+    }
+}

+ 48 - 0
webman/app/model/DouyinTrack.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\model;
+
+//use Illuminate\Database\Eloquent\Model;
+use support\Model;
+
+/**
+ * Class DouyinTrack
+ * @package App\Models
+ * @version April 8, 2020, 2:05 pm CST
+ *
+ * @property string $link_source
+ * @property string $link
+ * @property string $source
+ * @property string $ip_ua
+ * @property string $distribution_channel_id
+ * @property string $click_id
+ * @property string $ua
+ * @property string $ip
+ * @property string $log_time
+ * @property string $adid
+ */
+class DouyinTrack extends Model
+{
+    use TableSuffix;
+
+    public $table = 'douyin_tracks';
+
+    const CREATED_AT = 'created_at';
+    const UPDATED_AT = 'updated_at';
+    
+    protected $connection = 'mysql';
+
+    public $fillable = [
+        'link_source',
+        'link',
+        'source',
+        'ip_ua',
+        'distribution_channel_id',
+        'click_id',
+        'ua',
+        'ip',
+        'log_time',
+        'adid',
+        'callback',
+    ];
+}

+ 32 - 0
webman/app/model/TableSuffix.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\model;
+
+trait TableSuffix
+{
+    private static $suffix;
+
+    public static function suffix($suffix)
+    {
+        static::$suffix = $suffix;
+    }
+
+    public function __construct(array $attributes = [])
+    {
+        $this->table .= static::$suffix;
+        parent::__construct($attributes);
+    }
+
+    public static function model(int $month = 0)
+    {
+        $suffix = '';
+        if ($month == 0) {
+            $suffix = date('Ym');
+        } else {
+            $suffix = date('Ym', strtotime("last day of {$month} month"));
+        }
+        self::suffix($suffix);
+        $model = new self;
+        return $model;
+    }
+}

+ 29 - 0
webman/app/model/Test.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace app\model;
+
+use support\Model;
+
+class Test extends Model
+{
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'test';
+
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected $primaryKey = 'id';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = false;
+}

+ 23 - 0
webman/app/queue/redis/TiktokTrack.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace app\queue\redis;
+
+use Webman\RedisQueue\Consumer;
+use App\services\TrackService;
+use support\facade\Logger;
+
+class TiktokTrack implements Consumer
+{
+    // 要消费的队列名
+    public $queue = 'tiktok_track';
+
+    // 连接名,对应 plugin/webman/redis-queue/redis.php 里的连接`
+    public $connection = 'default';
+
+    // 消费
+    public function consume($data)
+    {
+        //Logger::app(time());
+        TrackService::cronDeal();
+    }
+}

+ 11 - 0
webman/app/services/BaseService.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace App\services;
+
+
+class BaseService
+{
+    public static function test (){
+        return 111;
+    }
+}

+ 96 - 0
webman/app/services/TrackService.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\services;
+
+use App\model\DouyinTrack;
+use support\Redis;
+use support\Log;
+use support\facade\Logger;
+
+class TrackService 
+{
+    
+    /**
+     *  把请求信息,放到redis队列中
+     */
+    public static function push ($params){
+        $dycallback = getProp($params,'dycallback');
+        switch ($dycallback) {
+            case 1:
+                //投递队列
+                $params['log_time'] = date('Y-m-d H:i:s',time());
+                Redis::lpush('tiktok_track',json_encode($params));
+                // if (!Redis::get('tiktok_track_deal_lock')) { // 锁住
+                //     Redis::setEx('tiktok_track_deal_lock',1,1);
+                //     self::TiktokRedisDeal();
+                // }
+                break;
+            default:
+                // code...
+                break;
+        }
+    }
+    
+    /**
+     *  定时任务批量处理
+     */
+    public static function cronDeal (){
+        // 处理巨量平台的
+        self::TiktokRedisDeal();
+    }
+    
+    /**
+     *  批量处理 巨量 平台发送过来的检测链接 数据信息。-避免过多的install
+     */
+    public static function TiktokRedisDeal ($data= []){
+        if (!$data) {
+            $len = Redis::llen('tiktok_track');
+            //Logger::app('tiktok_track:len'.$len);
+            if($len > 4000){
+                $len= 4000;
+            }
+            for ($i = 1; $i <= $len; $i++) {
+                 $data[] = Redis::rpop('tiktok_track');
+            }
+        }
+        if(empty($data)){
+            return false;
+        }
+        $inster = [] ;
+        $model =  DouyinTrack::model();
+        foreach ($data as $val){
+           $params = json_decode($val,true);
+           if(!getProp($params,'channel_id','')){
+               continue;
+           }
+            //整理数据+
+           $inster[] = [
+                'link' => getProp($params,'link',''),
+                'link_source' => 'tiktok',
+                'ip' => getProp($params,'ip',''),
+                'ua' => getProp($params,'ua',''),
+                'source' => 'zsy',
+                'ip_ua' => md5(getProp($params,'ip','') . getProp($params,'ua','')),
+                'distribution_channel_id' => getProp($params,'channel_id',''),
+                'log_time' => getProp($params,'log_time',''),
+                'created_at' => date('Y-m-d H:i:s',time()),
+                'adid' => getProp($params,'adid',''),
+                'callback' => getProp($params,'clickid',''),
+                //新添加
+                'advertiser_id' => getProp($params,'advertiser_id',''),
+                'campaign_id' => getProp($params,'campaign_id',''),
+                'creativeid' => getProp($params,'creativeid',''),
+                
+            ];
+            if(count($inster) >= 2000){
+                $model->insert($inster);
+                $inster = [];
+            }
+        }
+        if ($inster) {
+            $model->insert($inster);
+        }
+    }
+    
+    
+}

+ 14 - 0
webman/app/view/index/view.html

@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="shortcut icon" href="/favicon.ico"/>
+    <title>webman</title>
+
+</head>
+<body>
+hello <?=htmlspecialchars($name)?>
+</body>
+</html>

+ 69 - 0
webman/composer.json

@@ -0,0 +1,69 @@
+{
+  "name": "workerman/webman",
+  "type": "project",
+  "keywords": [
+    "high performance",
+    "http service"
+  ],
+  "homepage": "http://www.workerman.net",
+  "license": "MIT",
+  "description": "High performance HTTP Service Framework.",
+  "authors": [
+    {
+      "name": "walkor",
+      "email": "walkor@workerman.net",
+      "homepage": "http://www.workerman.net",
+      "role": "Developer"
+    }
+  ],
+  "support": {
+    "email": "walkor@workerman.net",
+    "issues": "https://github.com/walkor/webman/issues",
+    "forum": "http://wenda.workerman.net/",
+    "wiki": "http://workerman.net/doc/webman",
+    "source": "https://github.com/walkor/webman"
+  },
+  "require": {
+    "php": ">=7.2",
+    "workerman/webman-framework": "^1.3.14",
+    "monolog/monolog": "^2.0",
+    "psr/container": "^1.1.1",
+    "illuminate/database": "^9.17",
+    "illuminate/pagination": "^9.17",
+    "illuminate/events": "^9.20",
+    "symfony/var-dumper": "^6.1",
+    "tinywan/exception-handler": "^0.1.0",
+    "webman/console": "^1.0",
+    "hashids/hashids": "^4.1",
+    "vlucas/phpdotenv": "^5.4",
+    "illuminate/redis": "^9.20",
+    "webman/redis-queue": "^1.2",
+    "tinywan/jwt": "^1.3",
+    "workerman/crontab": "^1.0",
+    "webman/log": "^1.0",
+    "kriss/webman-logger": "^1.2"
+  },
+  "suggest": {
+    "ext-event": "For better performance. "
+  },
+  "autoload": {
+    "psr-4": {
+      "": "./",
+      "App\\": "./app"
+    },
+    "files": [
+      "./support/helpers.php"
+    ]
+  },
+  "scripts": {
+    "post-package-install": [
+      "support\\Plugin::install"
+    ],
+    "post-package-update": [
+      "support\\Plugin::install"
+    ],
+    "pre-package-uninstall": [
+      "support\\Plugin::uninstall"
+    ]
+  }
+}

文件差異過大導致無法顯示
+ 3086 - 0
webman/composer.lock


+ 24 - 0
webman/config/app.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\Request;
+
+return [
+    'debug' => true,
+    'default_timezone' => 'Asia/Shanghai',
+    'request_class' => Request::class,
+    'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public',
+    'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime',
+    'controller_suffix' => '',
+];

+ 21 - 0
webman/config/autoload.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'files' => [
+        base_path() . '/app/functions.php',
+        base_path() . '/support/Request.php',
+        base_path() . '/support/Response.php',
+    ]
+];

+ 18 - 0
webman/config/bootstrap.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    support\bootstrap\Session::class,
+    support\bootstrap\LaravelDb::class,
+];

+ 15 - 0
webman/config/container.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return new Webman\Container;

+ 35 - 0
webman/config/database.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+//return [];
+return [
+     // 默认数据库
+     'default' => 'mysql',
+     // 各种数据库配置
+     'connections' => [
+         'mysql' => [
+             'driver'      => 'mysql',
+             'host'        =>   getenv('DB_HOST'),
+             'port'        =>   getenv('DB_PORT'),
+             'database'    =>   getenv('DB_DATABASE'),
+             'username'    =>   getenv('DB_USERNAME'),
+             'password'    =>   getenv('DB_PASSWORD'),
+             'unix_socket' =>  '',
+             'charset'     => 'utf8',
+             'collation'   => 'utf8_unicode_ci',
+             'prefix'      => '',
+             'strict'      => true,
+             'engine'      => null,
+         ]
+    ]
+ ];

+ 15 - 0
webman/config/dependence.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [];

+ 17 - 0
webman/config/exception.php

@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    '' => support\exception\Handler::class,
+];

+ 37 - 0
webman/config/log.php

@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\facade\Logger;
+
+return array_merge(
+    [
+        'default' => [
+            'handlers' => [
+                [
+                    'class' => Monolog\Handler\RotatingFileHandler::class,
+                    'constructor' => [
+                        runtime_path() . '/logs/webman.log',
+                        7, //$maxFiles
+                        Monolog\Logger::DEBUG,
+                    ],
+                    'formatter' => [
+                        'class' => Monolog\Formatter\LineFormatter::class,
+                        'constructor' => [null, 'Y-m-d H:i:s', true],
+                    ],
+                ]
+            ],
+        ],
+    ],
+    Logger::getLogChannelConfigs(), // merge 这个
+);

+ 15 - 0
webman/config/middleware.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [];

+ 4 - 0
webman/config/plugin/kriss/webman-logger/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => true,
+];

+ 88 - 0
webman/config/plugin/kriss/webman-logger/log-channel.php

@@ -0,0 +1,88 @@
+<?php
+
+use Kriss\WebmanLogger\Formatter\ChannelFormatter;
+use Kriss\WebmanLogger\Formatter\ChannelMixedFormatter;
+use Kriss\WebmanLogger\Processors\RequestRouteProcessor;
+use Kriss\WebmanLogger\Processors\RequestUidProcessor;
+use Kriss\WebmanLogger\Processors\CurrentUserProcessor;
+use Monolog\Processor\PsrLogMessageProcessor;
+
+return [
+    // channels
+    'channels' => [
+        'app',
+        'sql',
+    ],
+    // 记录等级,仅大于设定等级的日志才会真实写入日志文件
+    'levels' => [
+        // 默认等级
+        'default' => config('app.debug') ? 'debug' : 'info',
+        // 特殊的等级
+        'special' => [
+            //'channelName' => 'info',
+        ],
+    ],
+    // processors
+    'processors' => function () {
+        return [
+            new PsrLogMessageProcessor('Y-m-d H:i:s'),
+            new RequestRouteProcessor(),
+            new CurrentUserProcessor(function () {
+                // 返回当前用户id
+                return 0;
+            }),
+            new RequestUidProcessor(),
+        ];
+    },
+    // 模式
+    'modes' => [
+        // 按照channel分目录记录
+        'split' => [
+            'class' => Kriss\WebmanLogger\Mode\SplitMode::class,
+            'enable' => true,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelFormatter::class,
+            ],
+            'max_files' => 30, // 最大文件数
+        ],
+        // 将所有channel合并到一起记录
+        'mix' => [
+            'class' => Kriss\WebmanLogger\Mode\MixMode::class,
+            'enable' => false,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelMixedFormatter::class,
+            ],
+            'max_files' => 30, // 最大文件数
+            'name' => 'channelMixed', // 合并时的日志文件名
+        ],
+        // 控制台输出
+        'stdout' => [
+            'class' => Kriss\WebmanLogger\Mode\StdoutMode::class,
+            'enable' => false,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelMixedFormatter::class,
+            ],
+        ],
+        // 输出到 redis
+        'redis' => [
+            'class' => Kriss\WebmanLogger\Mode\RedisMode::class,
+            'enable' => false,
+            'except_channels' => [],
+            'only_channels' => [],
+            'formatter' => [
+                'class' => ChannelFormatter::class,
+            ],
+            'redis' => function () {
+                return support\Redis::connection('default')->client();
+            },
+            'redis_key_prefix' => 'webmanLog:',
+            'redis_size' => 0,
+        ],
+    ],
+];

+ 7 - 0
webman/config/plugin/kriss/webman-logger/middleware.php

@@ -0,0 +1,7 @@
+<?php
+
+return [
+    '' => [
+        Kriss\WebmanLogger\Middleware\RequestUid::class,
+    ],
+];

+ 44 - 0
webman/config/plugin/tinywan/exception-handler/app.php

@@ -0,0 +1,44 @@
+<?php
+
+return [
+    'enable' => true,
+    // 错误异常配置
+    'exception_handler' => [
+        // 不需要记录错误日志
+        'dont_report' => [
+            Tinywan\ExceptionHandler\Exception\BadRequestHttpException::class,
+            Tinywan\ExceptionHandler\Exception\UnauthorizedHttpException::class,
+            Tinywan\ExceptionHandler\Exception\ForbiddenHttpException::class,
+            Tinywan\ExceptionHandler\Exception\NotFoundHttpException::class,
+            Tinywan\ExceptionHandler\Exception\RouteNotFoundException::class,
+            Tinywan\ExceptionHandler\Exception\TooManyRequestsHttpException::class,
+            Tinywan\ExceptionHandler\Exception\ServerErrorHttpException::class,
+            Tinywan\Validate\Exception\ValidateException::class,
+            Tinywan\Jwt\Exception\JwtTokenException::class
+        ],
+        // 自定义HTTP状态码
+        'status' => [
+            'validate' => 400, // 验证器异常
+            'jwt_token' => 401, // JWT 认证失败
+            'jwt_token_expired' => 402, // JWT 令牌过期
+            'server_error' => 500, // 服务器内部错误
+        ],
+        // 自定义响应消息
+        'body' => [
+            'code' => 0,
+            'msg' => '服务器内部异常',
+            'data' => null
+        ],
+        // 事件
+        'event' => [
+            'enable' => false,
+            // 钉钉机器人
+            'ding_talk' => [
+                'accessToken' => 'xxxxxxxxxxxxxxxx',
+                'secret' => 'xxxxxxxxxxxxxxxx',
+                'title' => '钉钉机器人异常通知',
+            ]
+        ],
+    ],
+
+];

+ 69 - 0
webman/config/plugin/tinywan/jwt/app.php

@@ -0,0 +1,69 @@
+<?php
+
+return [
+    'enable' => true,
+    'jwt' => [
+        // 算法类型 HS256、HS384、HS512、RS256、RS384、RS512、ES256、ES384、Ed25519
+        'algorithms' => 'HS256',
+        // access令牌秘钥
+        'access_secret_key' => '2022d3d3LmJq',
+        // access令牌过期时间,单位:秒。默认 2 小时
+        'access_exp' => 7200,
+        // refresh令牌秘钥
+        'refresh_secret_key' => '2022KTxigxc9o50c',
+        // refresh令牌过期时间,单位:秒。默认 7 天
+        'refresh_exp' => 604800,
+        // refresh 令牌是否禁用,默认不禁用 false
+        'refresh_disable' => false,
+        // 令牌签发者
+        'iss' => 'webman.tinywan.cn',
+        // 时钟偏差冗余时间,单位秒。建议这个余地应该不大于几分钟。
+        'leeway' => 60,
+        // 单设备登录
+        'is_single_device' => false,
+        // 缓存令牌时间,单位:秒。默认 7 天
+        'cache_token_ttl' => 604800,
+        // 缓存令牌前缀
+        'cache_token_pre' => 'JWT:TOKEN:',
+        // 用户信息模型
+        'user_model' => function($uid){
+            return [];
+        },
+
+        /**
+         * access令牌私钥
+         */
+        'access_private_key' => <<<EOD
+-----BEGIN RSA PRIVATE KEY-----
+...
+-----END RSA PRIVATE KEY-----
+EOD,
+
+        /**
+         * access令牌公钥
+         */
+        'access_public_key' => <<<EOD
+-----BEGIN PUBLIC KEY-----
+...
+-----END PUBLIC KEY-----
+EOD,
+
+        /**
+         * refresh令牌私钥
+         */
+        'refresh_private_key' => <<<EOD
+-----BEGIN RSA PRIVATE KEY-----
+...
+-----END RSA PRIVATE KEY-----
+EOD,
+
+        /**
+         * refresh令牌公钥
+         */
+        'refresh_public_key' => <<<EOD
+-----BEGIN PUBLIC KEY-----
+...
+-----END PUBLIC KEY-----
+EOD,
+    ],
+];

+ 18 - 0
webman/config/plugin/webman/console/app.php

@@ -0,0 +1,18 @@
+<?php
+return [
+    'enable'            => true,
+
+    'phar_file_output_dir'    => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
+
+    'phar_filename'     => 'webman.phar',
+
+    'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
+
+    'private_key_file'  => '', // The file path for certificate or OpenSSL private key file.
+
+    //'exclude_pattern'   => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
+
+    'exclude_files'     => [
+        '.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
+    ]
+];

+ 4 - 0
webman/config/plugin/webman/log/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => false,
+];

+ 21 - 0
webman/config/plugin/webman/log/middleware.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Webman\Log\Middleware;
+
+return [
+    '' => [
+        Middleware::class
+    ]
+];

+ 4 - 0
webman/config/plugin/webman/redis-queue/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => true,
+];

+ 7 - 0
webman/config/plugin/webman/redis-queue/command.php

@@ -0,0 +1,7 @@
+<?php
+
+use Webman\RedisQueue\Command\MakeConsumerCommand;
+
+return [
+    MakeConsumerCommand::class
+];

+ 11 - 0
webman/config/plugin/webman/redis-queue/process.php

@@ -0,0 +1,11 @@
+<?php
+return [
+    'consumer'  => [
+        'handler'     => Webman\RedisQueue\Process\Consumer::class,
+        'count'       => 16, // 可以设置多进程同时消费
+        'constructor' => [
+            // 消费者类目录
+            'consumer_dir' => app_path() . '/queue/redis'
+        ]
+    ]
+];

+ 13 - 0
webman/config/plugin/webman/redis-queue/redis.php

@@ -0,0 +1,13 @@
+<?php
+return [
+    'default' => [
+        'host' => 'redis://127.0.0.1:6379',
+        'options' => [
+            'auth' => null,       // 密码,字符串类型,可选参数
+            'db' => 0,            // 数据库
+            'prefix' => '',       // key 前缀
+            'max_attempts'  => 3, // 消费失败后,重试次数
+            'retry_seconds' => 3, // 重试间隔,单位秒
+        ]
+    ],
+];

+ 40 - 0
webman/config/process.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+
+return [
+    // File update detection and automatic reload
+    'monitor' => [
+        'handler' => process\Monitor::class,
+        'reloadable' => false,
+        'constructor' => [
+            // Monitor these directories
+            'monitor_dir' => [
+                app_path(),
+                config_path(),
+                base_path() . '/process',
+                base_path() . '/support',
+                base_path() . '/resource',
+                base_path() . '/.env',
+            ],
+            // Files with these suffixes will be monitored
+            'monitor_extensions' => [
+                'php', 'html', 'htm', 'env'
+            ]
+        ]
+    ],
+    'cron' => [
+        'handler'  => process\Task::class
+    ]
+];

+ 0 - 0
webman/config/redis.php


部分文件因文件數量過多而無法顯示