Исправить read-state каналов и импорт Solana PDA

This commit is contained in:
AidarKC
2026-09-17 21:10:48 +03:00
parent 1be1d56599
commit 7b81d140ec
3 changed files with 67 additions and 41 deletions
@@ -28,6 +28,7 @@ public final class SolanaUserPdaImportService {
private static final HttpClient HTTP = HttpClient.newHttpClient(); private static final HttpClient HTTP = HttpClient.newHttpClient();
private static final String MAGIC = "SHiNE"; private static final String MAGIC = "SHiNE";
private static final int MAX_EFFECTIVE_ACCESS_SERVERS = 1; private static final int MAX_EFFECTIVE_ACCESS_SERVERS = 1;
private static final int ARCHIVE_HEAD_PAYLOAD_BYTES = 64;
private SolanaUserPdaImportService() {} private SolanaUserPdaImportService() {}
@@ -266,6 +267,8 @@ public final class SolanaUserPdaImportService {
} }
} else if (blockType == 70) { } else if (blockType == 70) {
c += 1; c += 1;
} else if (blockType == 100) {
c += ARCHIVE_HEAD_PAYLOAD_BYTES;
} else { } else {
return null; return null;
} }
@@ -374,6 +377,8 @@ public final class SolanaUserPdaImportService {
} }
} else if (blockType == 70) { } else if (blockType == 70) {
c += 1; c += 1;
} else if (blockType == 100) {
c += ARCHIVE_HEAD_PAYLOAD_BYTES;
} else { } else {
return null; return null;
} }
+2 -2
View File
@@ -1,2 +1,2 @@
client.version=1.12.15 client.version=1.12.16
server.version=1.10.6 server.version=1.10.7
+26 -5
View File
@@ -306,6 +306,7 @@ function createChannelReadTracker({
let persistedSeenCount = safeInitialSeenCount; let persistedSeenCount = safeInitialSeenCount;
let initialPersistPending = !!initializeIfMissing; let initialPersistPending = !!initializeIfMissing;
let inFlight = false; let inFlight = false;
let writeBlocked = false;
let disposed = false; let disposed = false;
let rafId = 0; let rafId = 0;
let timerId = 0; let timerId = 0;
@@ -318,7 +319,7 @@ function createChannelReadTracker({
}; };
const queueFlush = (delayMs = 180) => { const queueFlush = (delayMs = 180) => {
if (disposed || !canWrite) return; if (disposed || writeBlocked || !canWrite) return;
clearTimer(); clearTimer();
timerId = setTimeout(() => { timerId = setTimeout(() => {
timerId = 0; timerId = 0;
@@ -327,7 +328,7 @@ function createChannelReadTracker({
}; };
const flush = async () => { const flush = async () => {
if (disposed || !canWrite) return; if (disposed || writeBlocked || !canWrite) return;
const next = Math.max(safeInitialSeenCount, Math.min(desiredSeenCount, safeMessagesCount)); const next = Math.max(safeInitialSeenCount, Math.min(desiredSeenCount, safeMessagesCount));
if (next <= persistedSeenCount && !initialPersistPending) return; if (next <= persistedSeenCount && !initialPersistPending) return;
if (inFlight) { if (inFlight) {
@@ -358,6 +359,18 @@ function createChannelReadTracker({
}); });
} }
} catch (error) { } catch (error) {
const errorCode = String(error?.code || '').trim().toUpperCase();
if (errorCode === 'CHANNEL_NOT_FOLLOWED') {
// This is a persistent state mismatch, not a transient transport failure.
// Stop writes for the current channel view instead of hammering the server
// after every scroll/resize. A fresh view after subscribe/refresh will create
// a new tracker from the latest subscription state.
writeBlocked = true;
initialPersistPending = false;
clearTimer();
if (typeof onPersistError === 'function') onPersistError(error, { retrying: false });
return;
}
if (typeof onPersistError === 'function') onPersistError(error, { retrying: true }); if (typeof onPersistError === 'function') onPersistError(error, { retrying: true });
queueFlush(800); queueFlush(800);
} finally { } finally {
@@ -2411,12 +2424,19 @@ function renderBody(screen, navigate, routeKey, channelData, handlers) {
? window.setTimeout(() => scrollChannelToUnreadLine(screen, unreadCount, false), 40) ? window.setTimeout(() => scrollChannelToUnreadLine(screen, unreadCount, false), 40)
: 0; : 0;
const tracker = createChannelReadTracker({ const shouldTrackReadState = !!(
channelData.isSubscribed
&& !channelData.isOwnChannel
&& !channelData.isDiary
);
const tracker = shouldTrackReadState
? createChannelReadTracker({
screen, screen,
routeKey, routeKey,
ownerBlockchainName: channelData.channel?.ownerBlockchainName || channelData.selector?.ownerBlockchainName, ownerBlockchainName: channelData.channel?.ownerBlockchainName || channelData.selector?.ownerBlockchainName,
channelName: channelData.channel?.name || channelData.channel?.channelName, channelName: channelData.channel?.name || channelData.channel?.channelName,
initializeIfMissing: !!(channelData.isSubscribed && !channelData.readStateInitialized), initializeIfMissing: !!(!channelData.readStateInitialized),
unreadCount, unreadCount,
messagesCount, messagesCount,
initialSeenCount: readCount, initialSeenCount: readCount,
@@ -2450,7 +2470,8 @@ function renderBody(screen, navigate, routeKey, channelData, handlers) {
} }
showStatus(''); showStatus('');
}, },
}); })
: { cleanup() {}, measure() {} };
return () => { return () => {
if (pendingScrollTimer) window.clearTimeout(pendingScrollTimer); if (pendingScrollTimer) window.clearTimeout(pendingScrollTimer);