SHA256
Добавить импорт архивов с доверенных серверов
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import { createTopBar } from '../components/topbar.js';
|
||||
import { authService, state } from '../state.js';
|
||||
|
||||
export const pageMeta = { id: 'blockchain-archive-view', title: 'Архив блокчейна' };
|
||||
|
||||
function text(value) {
|
||||
return String(value == null ? '' : value).trim();
|
||||
}
|
||||
|
||||
function buildViewerUrl(location, blockchainName, channelName, messageNumber) {
|
||||
const url = new URL('/Blockchain-Viewer.html', window.location.origin);
|
||||
url.searchParams.set('tx', text(location.arweaveTxId));
|
||||
url.searchParams.set('offset', String(location.chunkOffset));
|
||||
url.searchParams.set('size', String(location.chunkSize));
|
||||
url.searchParams.set('blockchain', blockchainName);
|
||||
const channel = text(channelName);
|
||||
if (channel) url.searchParams.set('channel', channel);
|
||||
const message = text(messageNumber);
|
||||
if (message) url.searchParams.set('message', message);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
async function copyText(value) {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(value);
|
||||
return;
|
||||
}
|
||||
const area = document.createElement('textarea');
|
||||
area.value = value;
|
||||
document.body.appendChild(area);
|
||||
area.select();
|
||||
document.execCommand('copy');
|
||||
area.remove();
|
||||
}
|
||||
|
||||
export function render({ navigate, chrome }) {
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'stack';
|
||||
chrome?.setTopbar(createTopBar({
|
||||
title: 'Архив блокчейна',
|
||||
back: { label: '←', onClick: () => navigate('settings-view') },
|
||||
}));
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card stack';
|
||||
card.innerHTML = `
|
||||
<div class="stack" style="gap:.35rem;">
|
||||
<strong>Последний архивный блок</strong>
|
||||
<div id="archive-status" class="meta-muted">Загружаю...</div>
|
||||
</div>
|
||||
<label class="field">
|
||||
<span>Блокчейн</span>
|
||||
<input id="archive-blockchain" type="text" readonly>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Канал (необязательно)</span>
|
||||
<input id="archive-channel" type="text" placeholder="Название канала">
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Номер сообщения / блока (необязательно)</span>
|
||||
<input id="archive-message" type="number" min="0" step="1" placeholder="Например, 125">
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Ссылка</span>
|
||||
<textarea id="archive-link" rows="5" readonly style="resize:vertical;"></textarea>
|
||||
</label>
|
||||
<div style="display:flex; gap:.6rem; flex-wrap:wrap;">
|
||||
<button id="archive-copy" class="shine-btn" type="button" disabled>Копировать ссылку</button>
|
||||
<button id="archive-open" class="shine-btn" type="button" disabled>Открыть Viewer</button>
|
||||
</div>
|
||||
<details>
|
||||
<summary>Технические данные</summary>
|
||||
<pre id="archive-tech" style="white-space:pre-wrap; word-break:break-all;"></pre>
|
||||
</details>
|
||||
`;
|
||||
screen.appendChild(card);
|
||||
|
||||
const status = card.querySelector('#archive-status');
|
||||
const blockchainInput = card.querySelector('#archive-blockchain');
|
||||
const channelInput = card.querySelector('#archive-channel');
|
||||
const messageInput = card.querySelector('#archive-message');
|
||||
const linkInput = card.querySelector('#archive-link');
|
||||
const copyButton = card.querySelector('#archive-copy');
|
||||
const openButton = card.querySelector('#archive-open');
|
||||
const tech = card.querySelector('#archive-tech');
|
||||
|
||||
let location = null;
|
||||
let blockchainName = '';
|
||||
|
||||
function refreshLink() {
|
||||
if (!location || !blockchainName) {
|
||||
linkInput.value = '';
|
||||
copyButton.disabled = true;
|
||||
openButton.disabled = true;
|
||||
return;
|
||||
}
|
||||
linkInput.value = buildViewerUrl(location, blockchainName, channelInput.value, messageInput.value);
|
||||
copyButton.disabled = false;
|
||||
openButton.disabled = false;
|
||||
}
|
||||
|
||||
channelInput.addEventListener('input', refreshLink);
|
||||
messageInput.addEventListener('input', refreshLink);
|
||||
copyButton.addEventListener('click', async () => {
|
||||
if (!linkInput.value) return;
|
||||
await copyText(linkInput.value);
|
||||
status.textContent = 'Ссылка скопирована.';
|
||||
});
|
||||
openButton.addEventListener('click', () => {
|
||||
if (linkInput.value) window.open(linkInput.value, '_blank', 'noopener,noreferrer');
|
||||
});
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
const login = text(state.session.login);
|
||||
if (!login) throw new Error('Нет активного пользователя');
|
||||
const user = await authService.getUser(login);
|
||||
blockchainName = text(user.blockchainName);
|
||||
if (!blockchainName) throw new Error('У пользователя не найден blockchainName');
|
||||
blockchainInput.value = blockchainName;
|
||||
location = await authService.getArchiveBlockchainLocation(blockchainName);
|
||||
if (!text(location.arweaveTxId) || !Number.isFinite(Number(location.chunkOffset)) || !Number.isFinite(Number(location.chunkSize))) {
|
||||
throw new Error('Сервер вернул неполную архивную ссылку');
|
||||
}
|
||||
status.textContent = `Известна архивная история до блока ${location.sourceLastBlockNumber ?? '—'}.`;
|
||||
tech.textContent = [
|
||||
`publisher: ${text(location.publisherLogin) || '—'}`,
|
||||
`archive big block: ${location.bigBlockNumber ?? '—'}`,
|
||||
`Arweave TX: ${text(location.arweaveTxId)}`,
|
||||
`archive hash: ${text(location.archiveHash) || '—'}`,
|
||||
`chunk offset: ${location.chunkOffset}`,
|
||||
`chunk size: ${location.chunkSize}`,
|
||||
`source last block: ${location.sourceLastBlockNumber ?? '—'}`,
|
||||
].join('\n');
|
||||
refreshLink();
|
||||
} catch (error) {
|
||||
status.textContent = `Архивная ссылка пока недоступна: ${error?.message || error}`;
|
||||
tech.textContent = '';
|
||||
refreshLink();
|
||||
}
|
||||
})();
|
||||
|
||||
return screen;
|
||||
}
|
||||
Reference in New Issue
Block a user