d
This commit is contained in:
parent
c3a6f5ff37
commit
4c4e767ec6
73 changed files with 3502 additions and 741 deletions
115
api-bridge.php
Normal file
115
api-bridge.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
function fail_json(int $status, string $message): never {
|
||||
http_response_code($status);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-store');
|
||||
echo json_encode(['error' => $message, 'serverTime' => (int) round(microtime(true) * 1000)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
$portFile = __DIR__ . DIRECTORY_SEPARATOR . '.linkfield-port';
|
||||
if (!is_file($portFile)) {
|
||||
fail_json(503, 'LinkField server is not running. Run npm start in this directory.');
|
||||
}
|
||||
$portText = trim((string) @file_get_contents($portFile));
|
||||
$port = filter_var($portText, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 65535]]);
|
||||
if ($port === false) {
|
||||
fail_json(503, 'LinkField server port information is invalid. Restart npm start.');
|
||||
}
|
||||
|
||||
$targetPath = isset($_GET['path']) ? (string) $_GET['path'] : '';
|
||||
if (!preg_match('#^/api/(?:cloud|player|realtime)(?:/|$)#', $targetPath)) {
|
||||
fail_json(400, 'Invalid LinkField API path.');
|
||||
}
|
||||
$query = $_GET;
|
||||
unset($query['path']);
|
||||
if ($query) {
|
||||
$targetPath .= '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
|
||||
$method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
|
||||
if (!in_array($method, ['GET', 'POST', 'HEAD'], true)) {
|
||||
fail_json(405, 'Method not allowed.');
|
||||
}
|
||||
$body = file_get_contents('php://input');
|
||||
if ($body === false) $body = '';
|
||||
if (strlen($body) > 64 * 1024 * 1024) {
|
||||
fail_json(413, 'Request body is too large.');
|
||||
}
|
||||
|
||||
$authorization = '';
|
||||
if (function_exists('getallheaders')) {
|
||||
$headers = getallheaders();
|
||||
if (is_array($headers)) {
|
||||
foreach ($headers as $name => $value) {
|
||||
if (strcasecmp((string) $name, 'Authorization') === 0) $authorization = (string) $value;
|
||||
if (strcasecmp((string) $name, 'X-LinkField-Authorization') === 0 && $authorization === '') $authorization = (string) $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($authorization === '') {
|
||||
$authorization = (string) ($_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? $_SERVER['HTTP_X_LINKFIELD_AUTHORIZATION'] ?? '');
|
||||
}
|
||||
|
||||
$socket = @stream_socket_client(
|
||||
'tcp://127.0.0.1:' . $port,
|
||||
$errorNumber,
|
||||
$errorMessage,
|
||||
3,
|
||||
STREAM_CLIENT_CONNECT
|
||||
);
|
||||
if (!is_resource($socket)) {
|
||||
fail_json(502, 'LinkField server is not reachable on its local port. Restart npm start.');
|
||||
}
|
||||
stream_set_timeout($socket, 15);
|
||||
|
||||
$requestHeaders = [
|
||||
$method . ' ' . $targetPath . " HTTP/1.1",
|
||||
'Host: 127.0.0.1:' . $port,
|
||||
'Connection: close',
|
||||
'Accept: application/json',
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($body),
|
||||
];
|
||||
if ($authorization !== '') $requestHeaders[] = 'Authorization: ' . str_replace(["\r", "\n"], '', $authorization);
|
||||
$request = implode("\r\n", $requestHeaders) . "\r\n\r\n" . $body;
|
||||
$written = 0;
|
||||
$length = strlen($request);
|
||||
while ($written < $length) {
|
||||
$result = fwrite($socket, substr($request, $written));
|
||||
if ($result === false || $result === 0) {
|
||||
fclose($socket);
|
||||
fail_json(502, 'Failed to send the request to the LinkField server.');
|
||||
}
|
||||
$written += $result;
|
||||
}
|
||||
$response = stream_get_contents($socket);
|
||||
$meta = stream_get_meta_data($socket);
|
||||
fclose($socket);
|
||||
if ($response === false || $response === '' || !empty($meta['timed_out'])) {
|
||||
fail_json(504, 'LinkField server did not respond in time.');
|
||||
}
|
||||
|
||||
$separator = strpos($response, "\r\n\r\n");
|
||||
if ($separator === false) fail_json(502, 'Invalid response from the LinkField server.');
|
||||
$headerText = substr($response, 0, $separator);
|
||||
$responseBody = substr($response, $separator + 4);
|
||||
$headerLines = explode("\r\n", $headerText);
|
||||
$statusLine = array_shift($headerLines);
|
||||
if (!preg_match('#^HTTP/\d(?:\.\d)?\s+(\d{3})#', (string) $statusLine, $statusMatch)) {
|
||||
fail_json(502, 'Invalid status from the LinkField server.');
|
||||
}
|
||||
http_response_code((int) $statusMatch[1]);
|
||||
foreach ($headerLines as $line) {
|
||||
$colon = strpos($line, ':');
|
||||
if ($colon === false) continue;
|
||||
$name = trim(substr($line, 0, $colon));
|
||||
$value = trim(substr($line, $colon + 1));
|
||||
if (in_array(strtolower($name), ['content-type', 'cache-control', 'x-content-type-options'], true)) {
|
||||
header($name . ': ' . $value, true);
|
||||
}
|
||||
}
|
||||
header('X-LinkField-Bridge: php', true);
|
||||
if ($method !== 'HEAD') echo $responseBody;
|
||||
Loading…
Add table
Add a link
Reference in a new issue