Showing
3 changed files
with
121 additions
and
1 deletions
| @@ -7,7 +7,8 @@ | @@ -7,7 +7,8 @@ | ||
| 7 | "php": ">=8.0", | 7 | "php": ">=8.0", |
| 8 | "workerman/workerman": "^4.1", | 8 | "workerman/workerman": "^4.1", |
| 9 | "firebase/php-jwt": "^6.10", | 9 | "firebase/php-jwt": "^6.10", |
| 10 | - "predis/predis": "^2.3" | 10 | + "predis/predis": "^2.3", |
| 11 | + "volcengine/ve-tos-php-sdk": "^2.0" | ||
| 11 | }, | 12 | }, |
| 12 | "autoload": { | 13 | "autoload": { |
| 13 | "psr-4": { | 14 | "psr-4": { |
docker-compose.prod.yml
0 → 100644
| 1 | +services: | ||
| 2 | + relay: | ||
| 3 | + image: moltbot-relay:latest | ||
| 4 | + container_name: moltbot-relay | ||
| 5 | + ports: | ||
| 6 | + - "8888:8888" | ||
| 7 | + - "8889:8889" | ||
| 8 | + env_file: | ||
| 9 | + - .env | ||
| 10 | + environment: | ||
| 11 | + - REDIS_HOST=redis | ||
| 12 | + - REDIS_PORT=6379 | ||
| 13 | + | ||
| 14 | + redis: | ||
| 15 | + image: redis:alpine | ||
| 16 | + container_name: moltbot-redis | ||
| 17 | + ports: | ||
| 18 | + - "6379:6379" |
| 1 | <?php | 1 | <?php |
| 2 | use Workerman\Worker; | 2 | use Workerman\Worker; |
| 3 | use Workerman\Timer; | 3 | use Workerman\Timer; |
| 4 | +use Tos\TosClient; | ||
| 5 | +use Tos\Exception\TosClientException; | ||
| 6 | +use Tos\Exception\TosServerException; | ||
| 7 | +use Tos\Model\PutObjectInput; | ||
| 4 | 8 | ||
| 5 | require_once __DIR__ . '/vendor/autoload.php'; | 9 | require_once __DIR__ . '/vendor/autoload.php'; |
| 6 | 10 | ||
| @@ -146,4 +150,101 @@ $ws_worker->onClose = function ($connection) use (&$clients, &$devices) { | @@ -146,4 +150,101 @@ $ws_worker->onClose = function ($connection) use (&$clients, &$devices) { | ||
| 146 | } | 150 | } |
| 147 | }; | 151 | }; |
| 148 | 152 | ||
| 153 | +// --------------------------------------------------------- | ||
| 154 | +// [New] HTTP Server for file uploads and static serving | ||
| 155 | +// --------------------------------------------------------- | ||
| 156 | +$http_worker = new Worker("http://0.0.0.0:8889"); | ||
| 157 | +$http_worker->count = 1; // Single process for uploads | ||
| 158 | +$http_worker->onMessage = function ($connection, $request) { | ||
| 159 | + // 1. Static File Serving (Simple implementation) | ||
| 160 | + $path = $request->path(); | ||
| 161 | + if (strpos($path, '/uploads/') === 0) { | ||
| 162 | + $file = __DIR__ . $path; | ||
| 163 | + if (is_file($file)) { | ||
| 164 | + $connection->send(new \Workerman\Protocols\Http\Response( | ||
| 165 | + 200, | ||
| 166 | + ['Content-Type' => mime_content_type($file)], | ||
| 167 | + file_get_contents($file) | ||
| 168 | + )); | ||
| 169 | + return; | ||
| 170 | + } | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + // 2. Upload Handler | ||
| 174 | + if ($path === '/upload') { | ||
| 175 | + $files = $request->file(); | ||
| 176 | + | ||
| 177 | + if (empty($files['file'])) { | ||
| 178 | + $connection->send(new \Workerman\Protocols\Http\Response(400, [], json_encode(['ok' => false, 'error' => 'No file']))); | ||
| 179 | + return; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + $file = $files['file']; | ||
| 183 | + | ||
| 184 | + // Validate Size (50MB) | ||
| 185 | + if ($file['size'] > 50 * 1024 * 1024) { | ||
| 186 | + $connection->send(new \Workerman\Protocols\Http\Response(400, [], json_encode(['ok' => false, 'error' => 'File too large (Max 50MB)']))); | ||
| 187 | + return; | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + // Validate Extension | ||
| 191 | + $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); | ||
| 192 | + // Supported: PDF, Excel, Image, Video | ||
| 193 | + $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'mp4', 'pdf', 'xls', 'xlsx']; | ||
| 194 | + if (!in_array($ext, $allowed)) { | ||
| 195 | + $connection->send(new \Workerman\Protocols\Http\Response(400, [], json_encode(['ok' => false, 'error' => 'File type not allowed']))); | ||
| 196 | + return; | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + // TOS Configuration (Keys from hsobs.php) | ||
| 200 | + $ak = 'AKLTZjkyMzliYjQ5N2IyNDFjNDliMTBiY2E2ZmU5ODhjNTM'; | ||
| 201 | + $sk = 'WldKbE5XUmpPRGxqWmpZM05EUTBObUpqTTJSa01qVTNNMkprWmpsbU9Uaw=='; | ||
| 202 | + $endpoint = 'tos-cn-shanghai.volces.com'; | ||
| 203 | + $region = 'cn-shanghai'; | ||
| 204 | + $bucket = 'ocxun'; | ||
| 205 | + | ||
| 206 | + try { | ||
| 207 | + $client = new TosClient([ | ||
| 208 | + 'region' => $region, | ||
| 209 | + 'endpoint' => $endpoint, | ||
| 210 | + 'ak' => $ak, | ||
| 211 | + 'sk' => $sk, | ||
| 212 | + ]); | ||
| 213 | + | ||
| 214 | + // Generate Key | ||
| 215 | + $uuid = bin2hex(random_bytes(8)); | ||
| 216 | + // TODO: 暂时使用 'guest',等待后续对接用户手机号功能 | ||
| 217 | + $userPhone = 'guest'; | ||
| 218 | + $objectKey = "clawdbot/{$userPhone}/{$uuid}.{$ext}"; | ||
| 219 | + | ||
| 220 | + // Read file content | ||
| 221 | + $contentFn = fopen($file['tmp_name'], 'r'); | ||
| 222 | + | ||
| 223 | + // Upload using Object Input | ||
| 224 | + $input = new PutObjectInput($bucket, $objectKey, $contentFn); | ||
| 225 | + $input->setACL('public-read'); | ||
| 226 | + | ||
| 227 | + $client->putObject($input); | ||
| 228 | + | ||
| 229 | + if (is_resource($contentFn)) { | ||
| 230 | + fclose($contentFn); | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + // Generate URL | ||
| 234 | + $url = "https://{$bucket}.{$endpoint}/{$objectKey}"; | ||
| 235 | + | ||
| 236 | + $connection->send(json_encode([ | ||
| 237 | + 'ok' => true, | ||
| 238 | + 'url' => $url | ||
| 239 | + ])); | ||
| 240 | + | ||
| 241 | + } catch (Exception $e) { | ||
| 242 | + $connection->send(new \Workerman\Protocols\Http\Response(500, [], json_encode(['ok' => false, 'error' => 'Upload failed: ' . $e->getMessage()]))); | ||
| 243 | + } | ||
| 244 | + return; | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + $connection->send("Moltbot Relay HTTP Server"); | ||
| 248 | +}; | ||
| 249 | + | ||
| 149 | Worker::runAll(); | 250 | Worker::runAll(); |
Please
register
or
login
to post a comment