feat: payload для /start в ботах.

This commit is contained in:
Jganenokk
2026-07-30 18:39:31 +07:00
parent 8f42692708
commit f6de41f11d
13 changed files with 483 additions and 38 deletions
+31
View File
@@ -3,6 +3,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
import '../../backend/api.dart';
import '../../models/bot_info.dart';
import '../../models/chat_info.dart';
import '../../models/contact_info.dart';
import '../protocol/opcode_map.dart';
@@ -279,6 +280,36 @@ class PresenceFetch {
}
}
class BotInfoFetch {
static final _cache = InfoCache<BotInfo>(
ttl: const Duration(minutes: 30),
fetcher: _fetch,
);
static Future<BotInfo?> get(int botId, {bool forceRefresh = false}) =>
_cache.get(botId, forceRefresh: forceRefresh);
static BotInfo? peek(int botId) => _cache.peek(botId);
static List<BotCommand> commandsOf(int botId) =>
_cache.peek(botId)?.commands ?? const [];
static void invalidate(int botId) => _cache.invalidate(botId);
static void clear() => _cache.clear();
static Future<BotInfo?> _fetch(int botId) async {
final api = _api;
if (api == null || api.state != SessionState.online) return null;
final resp = await api.sendRequest(Opcode.botInfo, {'botId': botId});
final data = resp.payload;
if (data is! Map) return null;
final info = BotInfo.fromPayload(botId, Map<String, dynamic>.from(data));
final contact = info.contact;
if (contact != null) ContactInfoFetch.putContact(botId, contact.raw);
return info;
}
}
class ChatInfoFetch {
static final _cache = InfoCache<ChatInfo>(
ttl: const Duration(minutes: 5),
+19 -3
View File
@@ -3,8 +3,11 @@ enum MaxLinkKind { call, invite, user, content, public, auth, stickerSet }
class MaxLink {
final MaxLinkKind kind;
final String url;
final String baseUrl;
final String? startPayload;
const MaxLink(this.kind, this.url);
const MaxLink(this.kind, this.url, {String? baseUrl, this.startPayload})
: baseUrl = baseUrl ?? url;
static final RegExp _host = RegExp(
r'^https?://(?:www\.)?max\.ru/(.+)$',
@@ -33,7 +36,8 @@ class MaxLink {
final match = _host.firstMatch(url);
if (match == null) return null;
final path = match.group(1)!.split('?').first.split('#').first;
final rest = match.group(1)!;
final path = rest.split('?').first.split('#').first;
final segments = path
.split('/')
.where((s) => s.isNotEmpty)
@@ -59,6 +63,18 @@ class MaxLink {
if (_reserved.contains(segments.first.toLowerCase())) return null;
if (!_segment.hasMatch(segments.first)) return null;
return MaxLink(MaxLinkKind.public, url);
return MaxLink(
MaxLinkKind.public,
url,
baseUrl: 'https://max.ru/${segments.join('/')}',
startPayload: _startPayload(rest),
);
}
static String? _startPayload(String rest) {
final parts = rest.split('#').first.split('?');
if (parts.length < 2) return null;
final value = Uri.splitQueryString(parts[1])['start']?.trim();
return (value == null || value.isEmpty) ? null : value;
}
}