diff --git a/go.php b/go.php new file mode 100644 index 0000000..76ccbaf --- /dev/null +++ b/go.php @@ -0,0 +1,135 @@ + 0, + 'cacheHit' => 0, + 'apiCall' => 0, + 'cacheCall' => 0, + 'cacheReadError' => 0, + 'fetchApiError' => 0, + 'fetchApiWarning' => 0, +]; + +// Ensure cache directory exists +if (!is_dir($cacheDir)) { + mkdir($cacheDir, 0777, true); +} + +Swoole\Coroutine\run(function () use ($port, $apiEndpoint, $cacheDir, &$pathIndex, &$viewsInfo) { + $server = new Server('0.0.0.0', $port, false); + + $server->set([ + 'daemonize' => true, + ]); + + $server->handle('/', function ($request, $response) use ($apiEndpoint, $cacheDir, &$pathIndex, &$viewsInfo) { + $viewsInfo['request']++; + + $uri = $request->server['request_uri']; + $parsedUrl = parse_url($uri); + parse_str($parsedUrl['query'] ?? '', $query); + + $reqPath = explode('/', trim($parsedUrl['path'], '/'))[0] ?? ''; + $token = implode('/', array_slice(explode('/', trim($parsedUrl['path'], '/')), 1)); + + if ($reqPath === 'endpoint') { + return sendJsonResponse($response, [ + 'code' => 200, + 'data' => [ + 'api' => $apiEndpoint, + 'port' => $port, + 'cacheDir' => $cacheDir, + 'pathIndexCount' => count($pathIndex), + 'viewsInfo' => $viewsInfo, + ], + ]); + } + + if (empty($token) || $token === 'undefined') { + $token = $reqPath; + $reqPath = 'go'; + } + + if (!in_array($reqPath, ['avatar', 'go', 'bbs', 'www', 'url', 'thumb'])) { + return sendErrorResponse($response, 404, 'Not Found'); + } + + if (!$token) { + return sendErrorResponse($response, 400, 'Bad Request: Missing Token or path'); + } + + $uniqidhex = md5($reqPath . $token . ($query['sign'] ?? '')); + + if (isset($pathIndex[$uniqidhex]) && isCacheValid($cacheDir, $pathIndex[$uniqidhex])) { + $viewsInfo['cacheHit']++; + return serveFromCache($cacheDir, $pathIndex[$uniqidhex], $response); + } + + $viewsInfo['apiCall']++; + fetchApiData($apiEndpoint, $reqPath, $token, $query['sign'] ?? '', function ($apiData) use ($cacheDir, &$pathIndex, $uniqidhex, $response) { + if ($apiData['code'] === 200 && isset($apiData['data']['url'])) { + $pathIndex[$uniqidhex] = $uniqidhex; + file_put_contents("$cacheDir/$uniqidhex.meta", json_encode($apiData['data'])); + file_put_contents("$cacheDir/$uniqidhex.content", file_get_contents($apiData['data']['url'])); + + serveFromCache($cacheDir, $uniqidhex, $response); + } else { + sendErrorResponse($response, 502, 'Bad Gateway: ' . json_encode($apiData)); + } + }); + }); + + + $server->start(); +}); + +function isCacheValid($cacheDir, $cacheFile) { + return file_exists("$cacheDir/$cacheFile.meta") && file_exists("$cacheDir/$cacheFile.content"); +} + +function serveFromCache($cacheDir, $cacheFile, $response) { + $cacheData = json_decode(file_get_contents("$cacheDir/$cacheFile.meta"), true); + $response->header('Content-Type', $cacheData['headers']['Content-Type'] ?? 'application/octet-stream'); + $response->header('Cloud-Type', $cacheData['cloudtype']); + $response->header('Cloud-Expiration', $cacheData['expiration']); + $response->header('ETag', $cacheData['uniqid'] ?? ''); + $response->header('Cache-Control', 'public, max-age=31536000'); + $response->header('Expires', gmdate('D, d M Y H:i:s', time() + 31536000000) . ' GMT'); + $response->header('Accept-Ranges', 'bytes'); + $response->header('Connection', 'keep-alive'); + $response->header('Date', gmdate('D, d M Y H:i:s') . ' GMT'); + $response->header('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); + $response->end(file_get_contents("$cacheDir/$cacheFile.content")); +} + +function fetchApiData($apiEndpoint, $reqPath, $token, $sign, $callback) { + Coroutine::create(function () use ($apiEndpoint, $reqPath, $token, $sign, $callback) { + $client = new Client(parse_url($apiEndpoint, PHP_URL_HOST), 443, true); + $client->setHeaders([ + 'Accept' => 'application/json', + 'User-Agent' => 'Swoole-Client', + 'token' => $token, + ]); + $client->get(parse_url($apiEndpoint, PHP_URL_PATH) . "?type=$reqPath&sign=$sign"); + $callback(json_decode($client->body, true)); + $client->close(); + }); +} + +function sendJsonResponse($response, $data) { + $response->header('Content-Type', 'application/json'); + $response->end(json_encode($data)); +} + +function sendErrorResponse($response, $status, $message) { + $response->status($status); + $response->end($message); +}