116 lines
3.8 KiB
Dart
116 lines
3.8 KiB
Dart
// Backend API endpoints:
|
|
// POST /auth/login body: {"username":"...","secret":"..."}
|
|
// → {"access_token":"...","token_type":"bearer"}
|
|
// GET /groups/me header: Authorization: Bearer TOKEN
|
|
// → [{"id":"uuid","name":"...","description":"...","is_active":true}]
|
|
//
|
|
// LiveKit token از طریق WebSocket دریافت میشود:
|
|
// WS /ws/groups/{id}?token={jwt}
|
|
|
|
import 'dart:convert';
|
|
import 'package:http/http.dart' as http;
|
|
import '../config/app_config.dart';
|
|
import '../models/channel.dart';
|
|
import 'auth_service.dart';
|
|
|
|
// ── Fake data (only used when AppConfig.debug == true) ────────────────────
|
|
const _fakeChannels = [
|
|
{'id': '1', 'name': 'تیم آلفا'},
|
|
{'id': '2', 'name': 'پشتیبانی میدانی'},
|
|
{'id': '3', 'name': 'فرماندهی'},
|
|
{'id': '4', 'name': 'گروه لجستیک'},
|
|
{'id': '5', 'name': 'واحد امنیت'},
|
|
];
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
|
|
class ApiService {
|
|
final AuthService _auth;
|
|
|
|
ApiService(this._auth);
|
|
|
|
Future<Map<String, String>> _headers() async {
|
|
final token = await _auth.getToken();
|
|
return {
|
|
'Content-Type': 'application/json',
|
|
if (token != null) 'Authorization': 'Bearer $token',
|
|
};
|
|
}
|
|
|
|
// استخراج user_id از JWT token (بدون نیاز به کتابخانه)
|
|
String? _extractUserIdFromJwt(String token) {
|
|
try {
|
|
final parts = token.split('.');
|
|
if (parts.length < 2) return null;
|
|
// base64url decode payload
|
|
var payload = parts[1];
|
|
// اضافه کردن padding اگه لازمه
|
|
while (payload.length % 4 != 0) {
|
|
payload += '=';
|
|
}
|
|
final decoded = utf8.decode(base64Url.decode(payload));
|
|
final map = jsonDecode(decoded) as Map<String, dynamic>;
|
|
return map['sub']?.toString();
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<bool> login(String username, String secret) async {
|
|
if (AppConfig.debug) {
|
|
await Future.delayed(const Duration(milliseconds: 600));
|
|
await _auth.saveAuth(token: 'debug_jwt', userId: 'debug_user');
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
final res = await http
|
|
.post(
|
|
Uri.parse('${AppConfig.baseUrl}/auth/login'),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'username': username, 'secret': secret}),
|
|
)
|
|
.timeout(const Duration(seconds: 10));
|
|
|
|
if (res.statusCode == 200) {
|
|
final data = jsonDecode(res.body) as Map<String, dynamic>;
|
|
final accessToken = data['access_token'] as String?;
|
|
if (accessToken == null) return false;
|
|
final userId = _extractUserIdFromJwt(accessToken);
|
|
await _auth.saveAuth(token: accessToken, userId: userId);
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<List<Channel>> getChannels() async {
|
|
if (AppConfig.debug) {
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
return _fakeChannels
|
|
.map((e) => Channel.fromJson(e as Map<String, dynamic>))
|
|
.toList();
|
|
}
|
|
|
|
try {
|
|
final res = await http
|
|
.get(
|
|
Uri.parse('${AppConfig.baseUrl}/users/me/groups'),
|
|
headers: await _headers(),
|
|
)
|
|
.timeout(const Duration(seconds: 10));
|
|
|
|
if (res.statusCode == 200) {
|
|
final list = jsonDecode(res.body) as List;
|
|
return list
|
|
.map((e) => Channel.fromJson(e as Map<String, dynamic>))
|
|
.toList();
|
|
}
|
|
return [];
|
|
} catch (_) {
|
|
return [];
|
|
}
|
|
}
|
|
}
|