mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-15 11:18:05 +02:00
feat: Implement core server application with API routing, streaming, and static content serving.
This commit is contained in:
1 parent
1dd77bd87a
commit
755367018a
3 files changed
+55
-52
No files matched your search
+30
-30
@@ -108,41 +108,41 @@ class ProxyHandler {
|
||||
final proxyHeaders = {
|
||||
'User-Agent': 'VLC/3.0.18 LibVLC/3.0.18',
|
||||
'Accept': '*/*',
|
||||
'Accept-Encoding': 'identity',
|
||||
'Connection': 'keep-alive',
|
||||
'Accept-Encoding': 'identity', // Explicitly request non-chunked
|
||||
'Connection': 'close', // Don't keep-alive to avoid chunked issues
|
||||
};
|
||||
|
||||
final client = http.Client();
|
||||
final proxyRequest = http.Request(request.method, targetUrl);
|
||||
proxyRequest.headers.addAll(proxyHeaders);
|
||||
|
||||
// Forward body if POST
|
||||
if (request.method == 'POST') {
|
||||
final bodyBytes = await request.read().toList();
|
||||
proxyRequest.bodyBytes = bodyBytes.expand((i) => i).toList();
|
||||
try {
|
||||
// Use simple GET/POST instead of streaming to avoid chunked encoding issues
|
||||
http.Response response;
|
||||
if (request.method == 'POST') {
|
||||
final bodyBytes = await request.read().toList();
|
||||
final body = bodyBytes.expand((i) => i).toList();
|
||||
response = await client.post(targetUrl, headers: proxyHeaders, body: body);
|
||||
} else {
|
||||
response = await client.get(targetUrl, headers: proxyHeaders);
|
||||
}
|
||||
|
||||
// Build response headers
|
||||
final responseHeaders = <String, String>{
|
||||
'access-control-allow-origin': '*',
|
||||
'content-type': response.headers['content-type'] ?? 'application/json',
|
||||
};
|
||||
|
||||
if (response.headers['content-length'] != null) {
|
||||
responseHeaders['content-length'] = response.headers['content-length']!;
|
||||
}
|
||||
|
||||
return Response(
|
||||
response.statusCode,
|
||||
body: response.bodyBytes,
|
||||
headers: responseHeaders,
|
||||
);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
|
||||
// Streaming Response
|
||||
final streamedResponse = await client.send(proxyRequest);
|
||||
|
||||
// Filter headers
|
||||
final responseHeaders = <String, String>{
|
||||
'access-control-allow-origin': '*',
|
||||
};
|
||||
|
||||
streamedResponse.headers.forEach((key, value) {
|
||||
if (_allowedHeaders.contains(key.toLowerCase())) {
|
||||
responseHeaders[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Pipe the stream directly to the response
|
||||
return Response(
|
||||
streamedResponse.statusCode,
|
||||
body: streamedResponse.stream,
|
||||
headers: responseHeaders,
|
||||
);
|
||||
|
||||
} catch (e, stackTrace) {
|
||||
print('Proxy error: $e');
|
||||
print(stackTrace);
|
||||
|
||||
+7
-7
@@ -46,24 +46,23 @@ void main(List<String> args) async {
|
||||
final user = request.context['user'] as User?;
|
||||
// If we have a user from auth middleware, prefer their playlists
|
||||
if (user != null) {
|
||||
print('[getPlaylist] User from context: ${user.username}');
|
||||
final playlists = db.getPlaylists(user.id);
|
||||
if (playlists.isNotEmpty) playlist = playlists.first;
|
||||
} else {
|
||||
// Fallback: This leg should effectively be unreachable for /api/xtream if we use authMiddleware,
|
||||
// but might be used by other handlers or if auth is optional somewhere.
|
||||
// For VOD/Live which currently might not have auth (URL tokenizing is complex), we keep fallback?
|
||||
// WAIT: The plan said "Secure /api/xtream using authMiddleware".
|
||||
// If we do that, user is GUARANTEED for proxy.
|
||||
// But for /api/live and /api/vod, we might need a different strategy (token in URL).
|
||||
// For now, let's keep the fallback logic for non-proxy parts if any.
|
||||
// Fallback for proxy: get first user's first playlist
|
||||
print('[getPlaylist] No user in context, using fallback');
|
||||
final users = db.getAllUsers();
|
||||
print('[getPlaylist] Total users in DB: ${users.length}');
|
||||
if (users.isNotEmpty) {
|
||||
final playlists = db.getPlaylists(users[0].id);
|
||||
print('[getPlaylist] User ${users[0].username} has ${playlists.length} playlists');
|
||||
if (playlists.isNotEmpty) playlist = playlists.first;
|
||||
}
|
||||
}
|
||||
|
||||
if (playlist != null) {
|
||||
print('[getPlaylist] Returning playlist: ${playlist.name} (DNS: ${playlist.serverUrl})');
|
||||
return PlaylistConfig(
|
||||
id: playlist.id,
|
||||
name: playlist.name,
|
||||
@@ -74,6 +73,7 @@ void main(List<String> args) async {
|
||||
isActive: true,
|
||||
);
|
||||
}
|
||||
print('[getPlaylist] WARNING: No playlist found, returning null');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
# Fix Docker Database & Proxy Issues
|
||||
# Fix Docker & Proxy Issues
|
||||
|
||||
## Context
|
||||
## Completed
|
||||
|
||||
1. SQLite database read-only error on login (permissions)
|
||||
2. Xtream proxy 401 Unauthorized errors
|
||||
- [x] Database permissions (`entrypoint.sh` + `Dockerfile`)
|
||||
- [x] Proxy 401 errors (removed broken mount in `server.dart`)
|
||||
- [x] Proxy chunked encoding error (buffered response in `proxy_handler.dart`)
|
||||
|
||||
## Master Plan
|
||||
## Changes
|
||||
|
||||
- [x] Analyze database readonly error → volume permissions mismatch
|
||||
- [x] Create `entrypoint.sh` with gosu for privilege drop
|
||||
- [x] Update `Dockerfile` to use entrypoint
|
||||
- [x] Analyze proxy 401 errors → broken mount in apiRouter
|
||||
- [x] Remove duplicate `/api/xtream` mount from `server.dart`
|
||||
- [ ] Rebuild and deploy
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `entrypoint.sh` | NEW - fixes /app/data permissions, runs as xtremuser via gosu |
|
||||
| `Dockerfile` | Added gosu, ENTRYPOINT |
|
||||
| `bin/server.dart` | Removed broken /api/xtream mount, added logging |
|
||||
| `bin/api/proxy_handler.dart` | Changed from streaming to buffered response |
|
||||
|
||||
## Changes Made
|
||||
## Deploy
|
||||
|
||||
- `entrypoint.sh`: Fixes /app/data permissions at startup, then runs as xtremuser
|
||||
- `Dockerfile`: Added gosu, ENTRYPOINT, removed USER directive
|
||||
- `server.dart`: Removed broken /api/xtream mount that was blocking proxy
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "fix: database permissions + proxy errors"
|
||||
git push && docker compose up --build -d
|
||||
```
|
||||
Reference in new issue
Block a user