Skip to content

Commit 2bf4901

Browse files
authored
Merge pull request 4x99#40 from 4x99/develop
1.2.0
2 parents fe319f1 + a091a3d commit 2bf4901

File tree

12 files changed

+154
-113
lines changed

12 files changed

+154
-113
lines changed

app/Console/Commands/JobRunCommand.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace App\Console\Commands;
44

55
use Exception;
6-
use Github\Client;
76
use App\Models\CodeFragment;
87
use App\Models\CodeLeak;
98
use App\Models\ConfigJob;
@@ -48,7 +47,7 @@ class JobRunCommand extends Command
4847
/**
4948
* GitHub Service
5049
*
51-
* @var Client
50+
* @var GitHubService
5251
*/
5352
protected $service;
5453

@@ -72,11 +71,6 @@ public function handle()
7271
$this->log = Log::channel($this->signature);
7372
$this->log->info('Start job');
7473

75-
if (!QueueJob::count()) {
76-
$this->log->info('The queue is empty');
77-
exit;
78-
}
79-
8074
$this->createGitHubService();
8175
$this->whitelist = ConfigWhitelist::all()->keyBy('value');
8276

app/Console/Commands/TokenCheckCommand.php

Lines changed: 0 additions & 71 deletions
This file was deleted.

app/Console/Kernel.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ class Kernel extends ConsoleKernel
2424
*/
2525
protected function schedule(Schedule $schedule)
2626
{
27-
$schedule->command('code6:token-check')->everyMinute()->withoutOverlapping()->runInBackground();
2827
$schedule->command('code6:job-add')->everyMinute();
2928
$schedule->command('code6:job-run')->everyMinute()->withoutOverlapping();
3029
}

app/Http/Controllers/HomeController.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public function metric()
3030
{
3131
$data = [
3232
'codeLeakCount' => CodeLeak::count(),
33-
'codeLeakPending' => CodeLeak::where('status', 0)->count(),
34-
'codeLeakSolved' => CodeLeak::where('status', 3)->count(),
33+
'codeLeakPending' => CodeLeak::where('status', CodeLeak::STATUS_PENDING)->count(),
34+
'codeLeakSolved' => CodeLeak::where('status', CodeLeak::STATUS_SOLVED)->count(),
3535
'queueJobCount' => QueueJob::count(),
3636
];
3737
return ['success' => true, 'data' => $data];
@@ -88,8 +88,8 @@ public function memory()
8888
public function tokenQuota()
8989
{
9090
try {
91-
$total = ConfigToken::where('status', 1)->sum('api_limit');
92-
$remaining = ConfigToken::where('status', 1)->sum('api_remaining');
91+
$total = ConfigToken::where('status', ConfigToken::STATUS_NORMAL)->sum('api_limit');
92+
$remaining = ConfigToken::where('status', ConfigToken::STATUS_NORMAL)->sum('api_remaining');
9393
$used = $total - $remaining;
9494
$data = [
9595
[

app/Models/CodeLeak.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
class CodeLeak extends ModelBase
66
{
7+
const STATUS_PENDING = 0;
8+
const STATUS_FALSE = 1;
9+
const STATUS_ABNORMAL = 2;
10+
const STATUS_SOLVED = 3;
711
protected $table = 'code_leak';
812
protected $fillable = [
913
'uuid',

app/Models/ConfigToken.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
class ConfigToken extends ModelBase
66
{
7+
const STATUS_UNKNOWN = 0;
8+
const STATUS_NORMAL = 1;
9+
const STATUS_ABNORMAL = 2;
710
protected $table = 'config_token';
811
protected $fillable = ['token', 'description'];
912
}

app/Services/GitHubService.php

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,37 @@
22

33
namespace App\Services;
44

5+
use Closure;
56
use Exception;
6-
use App\Models\ConfigToken;
77
use Github\Client;
8+
use App\Models\ConfigToken;
9+
use Illuminate\Support\Arr;
810
use Github\HttpClient\Builder;
911
use Illuminate\Support\Facades\Log;
10-
use Http\Adapter\Guzzle6\Client AS GuzzleClient;
12+
use Http\Adapter\Guzzle6\Client as GuzzleClient;
13+
use GuzzleHttp\Handler\CurlHandler;
14+
use GuzzleHttp\HandlerStack;
15+
use GuzzleHttp\Middleware;
16+
use GuzzleHttp\Psr7\Request;
17+
use GuzzleHttp\Psr7\Response;
18+
use GuzzleHttp\Exception\RequestException;
1119

1220
class GitHubService
1321
{
22+
const HTTP_TIMEOUT = 30;
23+
const HTTP_DELAY = 2000;
24+
const HTTP_MAX_RETRIES = 5;
1425
const GET_CLIENT_TIMEOUT = 1800;
26+
const HTTP_CODE_UNAUTHORIZED = 401;
27+
const RATE_LIMIT_UNAUTHENTICATED = 10; // 未授权限制请求频率:10 次 / 分钟
28+
1529
public $clients = [];
30+
private $userAgent = 'Code6';
1631
private $currentKey = -1;
1732

1833
public function __construct()
1934
{
35+
$this->userAgent = config('app.name');
2036
$this->createClients();
2137
}
2238

@@ -40,18 +56,19 @@ public function getClient()
4056
$client = &$this->clients[$this->currentKey];
4157

4258
// 更新接口配额
43-
if (time() >= $client['reset']) {
59+
if (time() >= $client['api_reset_at']) {
4460
$this->updateClient($client);
4561
}
4662

4763
// 当前客户端配额是否耗尽
48-
if ($client['remaining'] <= 0) {
64+
if ($client['api_remaining'] <= 0) {
4965
sleep(1);
5066
continue;
5167
}
5268

5369
// 返回客户端
54-
$client['remaining']--;
70+
$client['api_remaining']--;
71+
$this->updateConfigToken($client);
5572
return $client['client'];
5673
}
5774
}
@@ -63,8 +80,15 @@ private function createClients()
6380
{
6481
$tokens = ConfigToken::inRandomOrder()->get()->pluck('token');
6582
foreach ($tokens as $token) {
83+
$handlerStack = HandlerStack::create(new CurlHandler());
84+
$handlerStack->push(Middleware::retry($this->retryDecider()));
85+
$builder = new Builder(GuzzleClient::createWithConfig([
86+
'timeout' => self::HTTP_TIMEOUT,
87+
'delay' => self::HTTP_DELAY,
88+
'headers' => ['User-Agent' => $this->userAgent],
89+
'handler' => $handlerStack,
90+
]));
6691
$client = ['token' => $token];
67-
$builder = new Builder(GuzzleClient::createWithConfig(['timeout' => 30]));
6892
$client['client'] = new Client($builder, 'v3.text-match');
6993
$client['client']->authenticate($token, null, Client::AUTH_HTTP_TOKEN);
7094
if ($this->updateClient($client)) {
@@ -81,17 +105,60 @@ private function createClients()
81105
*/
82106
private function updateClient(&$client)
83107
{
108+
$code = $resource = null;
84109
try {
85-
if (!$resource = $client['client']->api('rate_limit')->getResource('search')) {
110+
$resource = $client['client']->api('rate_limit')->getResource('search');
111+
} catch (Exception $e) {
112+
$code = $e->getCode();
113+
Log::debug($e->getMessage(), ['token' => $client['token']]);
114+
}
115+
116+
$client['api_limit'] = $resource ? $resource->getLimit() : 0;
117+
$client['api_reset_at'] = $resource ? $resource->getReset() : null;
118+
$client['api_remaining'] = $resource ? $resource->getRemaining() : 0;
119+
if ($code == self::HTTP_CODE_UNAUTHORIZED || $client['api_limit'] == self::RATE_LIMIT_UNAUTHENTICATED) {
120+
$client['status'] = ConfigToken::STATUS_ABNORMAL;
121+
} else {
122+
$client['status'] = $resource ? ConfigToken::STATUS_NORMAL : ConfigToken::STATUS_UNKNOWN;
123+
}
124+
125+
$this->updateConfigToken($client);
126+
return $client['status'] == ConfigToken::STATUS_NORMAL;
127+
}
128+
129+
/**
130+
* 更新数据库
131+
*
132+
* @param $client
133+
* @return mixed
134+
*/
135+
private function updateConfigToken($client)
136+
{
137+
$data = Arr::only($client, ['status', 'api_limit', 'api_remaining']);
138+
$data['api_reset_at'] = $client['api_reset_at'] ? date('Y-m-d H:i:s', $client['api_reset_at']) : null;
139+
return ConfigToken::where('token', $client['token'])->update($data);
140+
}
141+
142+
/**
143+
* 决定是否重试请求
144+
*
145+
* @return Closure (true:重试 false:不重试)
146+
*/
147+
protected function retryDecider()
148+
{
149+
return function ($retries, Request $request, Response $response = null, RequestException $exception = null) {
150+
// 最大次数
151+
if ($retries >= self::HTTP_MAX_RETRIES) {
86152
return false;
87153
}
88-
$client['limit'] = $resource->getLimit();
89-
$client['reset'] = $resource->getReset();
90-
$client['remaining'] = $resource->getRemaining();
91-
} catch (Exception $e) {
92-
Log::warning($e->getMessage(), ['token' => $client['token']]);
154+
155+
// 请求失败
156+
if (!is_null($exception)) {
157+
Log::debug('Retry request', ['exception' => $exception->getMessage()]);
158+
return true;
159+
}
160+
93161
return false;
94-
}
95-
return true;
162+
};
96163
}
97164
}

config/logging.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@
5151
'days' => 7,
5252
],
5353

54-
'code6:token-check' => [
55-
'driver' => 'daily',
56-
'path' => storage_path('logs/token-check.log'),
57-
'level' => 'info',
58-
'days' => 7,
59-
],
60-
6154
'code6:job-run' => [
6255
'driver' => 'daily',
6356
'path' => storage_path('logs/job-run.log'),
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
use Illuminate\Support\Facades\DB;
7+
8+
class ChangeStatusToConfigTokenTable extends Migration
9+
{
10+
/**
11+
* Run the migrations.
12+
*
13+
* @return void
14+
*/
15+
public function up()
16+
{
17+
Schema::table('config_token', function (Blueprint $table) {
18+
DB::statement("ALTER TABLE `config_token` CHANGE `status` `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0:Unknown 1:Normal 2:Abnormal'");
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*
25+
* @return void
26+
*/
27+
public function down()
28+
{
29+
Schema::table('config_token', function (Blueprint $table) {
30+
DB::statement("ALTER TABLE `config_token` CHANGE `status` `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '0:Abnormal 1:Normal'");
31+
});
32+
}
33+
}

resources/views/codeLeak/index.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@
351351
},
352352
{
353353
text: '更多',
354-
iconCls: 'icon-bullet-orange',
354+
iconCls: 'icon-bullet-blue',
355355
margin: '0 0 0 10',
356356
menu: {
357357
items: [

0 commit comments

Comments
 (0)