117 lines
3.9 KiB
Dart
117 lines
3.9 KiB
Dart
|
|
import 'dart:io';
|
|||
|
|
import 'package:dio/dio.dart';
|
|||
|
|
import 'package:hiddify/core/telegram_config.dart';
|
|||
|
|
import 'package:hiddify/utils/utils.dart';
|
|||
|
|
|
|||
|
|
/// Сервис для анонимной отправки логов в Telegram
|
|||
|
|
class TelegramLogger with InfraLogger {
|
|||
|
|
static const int maxLogSize = 4096; // Telegram ограничение на текст сообщения
|
|||
|
|
static const int maxFileSize = 50 * 1024 * 1024; // 50MB максимум для файла
|
|||
|
|
|
|||
|
|
final Dio _dio = Dio(
|
|||
|
|
BaseOptions(
|
|||
|
|
connectTimeout: const Duration(seconds: 10),
|
|||
|
|
receiveTimeout: const Duration(seconds: 10),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/// Отправить логи как текстовое сообщение (для коротких логов)
|
|||
|
|
Future<bool> sendLogsAsText(String logs, {String? deviceInfo}) async {
|
|||
|
|
if (!TelegramConfig.isConfigured) {
|
|||
|
|
loggy.warning('Telegram not configured');
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
final message = _formatMessage(logs, deviceInfo);
|
|||
|
|
|
|||
|
|
final response = await _dio.post(
|
|||
|
|
'https://api.telegram.org/bot${TelegramConfig.botToken}/sendMessage',
|
|||
|
|
data: {
|
|||
|
|
'chat_id': TelegramConfig.chatId,
|
|||
|
|
'text': message,
|
|||
|
|
'parse_mode': 'HTML',
|
|||
|
|
},
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return response.statusCode == 200;
|
|||
|
|
} catch (e) {
|
|||
|
|
loggy.error('Failed to send logs to Telegram', e);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Отправить файл логов (для больших логов)
|
|||
|
|
Future<bool> sendLogsAsFile(File logFile, {String? deviceInfo}) async {
|
|||
|
|
if (!TelegramConfig.isConfigured) {
|
|||
|
|
loggy.warning('Telegram not configured');
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// Проверка размера файла
|
|||
|
|
final fileSize = await logFile.length();
|
|||
|
|
if (fileSize > maxFileSize) {
|
|||
|
|
loggy.warning('Log file too large: $fileSize bytes');
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
final fileName = logFile.path.split('/').last;
|
|||
|
|
final caption = deviceInfo != null ? '📱 Device: $deviceInfo\n📅 ${DateTime.now().toIso8601String()}' : '📅 ${DateTime.now().toIso8601String()}';
|
|||
|
|
|
|||
|
|
final formData = FormData.fromMap({
|
|||
|
|
'chat_id': TelegramConfig.chatId,
|
|||
|
|
'document': await MultipartFile.fromFile(
|
|||
|
|
logFile.path,
|
|||
|
|
filename: fileName,
|
|||
|
|
),
|
|||
|
|
'caption': caption,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
final response = await _dio.post(
|
|||
|
|
'https://api.telegram.org/bot${TelegramConfig.botToken}/sendDocument',
|
|||
|
|
data: formData,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return response.statusCode == 200;
|
|||
|
|
} catch (e) {
|
|||
|
|
loggy.error('Failed to send log file to Telegram', e);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
String _formatMessage(String logs, String? deviceInfo) {
|
|||
|
|
final header = deviceInfo != null ? '📱 <b>Umbrix Logs</b>\nDevice: $deviceInfo\n' : '📱 <b>Umbrix Logs</b>\n';
|
|||
|
|
|
|||
|
|
final timestamp = '📅 ${DateTime.now().toIso8601String()}\n';
|
|||
|
|
const separator = '━━━━━━━━━━━━━━━━\n';
|
|||
|
|
|
|||
|
|
// Обрезаем логи если они слишком длинные
|
|||
|
|
var logContent = logs;
|
|||
|
|
final maxContentSize = maxLogSize - header.length - timestamp.length - separator.length - 50;
|
|||
|
|
|
|||
|
|
if (logContent.length > maxContentSize) {
|
|||
|
|
logContent = '${logContent.substring(0, maxContentSize)}\n\n... (truncated)';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return '$header$timestamp$separator$logContent';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить информацию об устройстве для логов (анонимно)
|
|||
|
|
static String getAnonymousDeviceInfo() {
|
|||
|
|
// Только общая информация без идентификаторов
|
|||
|
|
if (Platform.isAndroid) {
|
|||
|
|
return 'Android ${Platform.operatingSystemVersion}';
|
|||
|
|
} else if (Platform.isIOS) {
|
|||
|
|
return 'iOS ${Platform.operatingSystemVersion}';
|
|||
|
|
} else if (Platform.isWindows) {
|
|||
|
|
return 'Windows';
|
|||
|
|
} else if (Platform.isMacOS) {
|
|||
|
|
return 'macOS';
|
|||
|
|
} else if (Platform.isLinux) {
|
|||
|
|
return 'Linux';
|
|||
|
|
}
|
|||
|
|
return 'Unknown OS';
|
|||
|
|
}
|
|||
|
|
}
|