120 lines
4.1 KiB
JavaScript
120 lines
4.1 KiB
JavaScript
export function connectionAction({ connected, selectedTag, configExists }) {
|
|
if (connected) return { type: 'stop' };
|
|
if (selectedTag) return { type: 'apply', selectedTag };
|
|
if (configExists) return { type: 'restart' };
|
|
return null;
|
|
}
|
|
|
|
export function formatConnectionDuration(startedAt, now = Date.now()) {
|
|
const { totalHours, minutes, seconds } = connectionDurationParts(startedAt, now);
|
|
|
|
return [totalHours, minutes.value, seconds.value]
|
|
.map((part) => String(part).padStart(2, '0'))
|
|
.join(':');
|
|
}
|
|
|
|
function durationLabel(value, forms) {
|
|
const mod10 = value % 10;
|
|
const mod100 = value % 100;
|
|
return mod10 === 1 && mod100 !== 11
|
|
? forms[0]
|
|
: mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14) ? forms[1] : forms[2];
|
|
}
|
|
|
|
export function connectionDurationParts(startedAt, now = Date.now()) {
|
|
const started = Date.parse(startedAt);
|
|
const totalSeconds = Number.isFinite(started)
|
|
? Math.max(0, Math.floor((now - started) / 1000))
|
|
: 0;
|
|
const days = Math.floor(totalSeconds / 86_400);
|
|
const totalHours = Math.floor(totalSeconds / 3600);
|
|
const hours = Math.floor((totalSeconds % 86_400) / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
|
|
return {
|
|
totalHours,
|
|
days: { value: days, label: durationLabel(days, ['день', 'дня', 'дней']) },
|
|
hours: { value: hours, label: durationLabel(hours, ['час', 'часа', 'часов']) },
|
|
minutes: { value: minutes, label: durationLabel(minutes, ['минута', 'минуты', 'минут']) },
|
|
seconds: { value: seconds, label: durationLabel(seconds, ['секунда', 'секунды', 'секунд']) },
|
|
};
|
|
}
|
|
|
|
export function formatConnectionDurationWords(startedAt, now = Date.now()) {
|
|
const { days, hours, minutes, seconds } = connectionDurationParts(startedAt, now);
|
|
|
|
return [
|
|
days.value && `${days.value} ${days.label}`,
|
|
hours.value && `${hours.value} ${hours.label}`,
|
|
minutes.value && `${minutes.value} ${minutes.label}`,
|
|
`${seconds.value} ${seconds.label}`,
|
|
].filter(Boolean).join(' ');
|
|
}
|
|
|
|
export function subscriptionDomain(subscriptionHost) {
|
|
const value = String(subscriptionHost || '');
|
|
try {
|
|
return new URL(value).host;
|
|
} catch {
|
|
return value.split('/')[0];
|
|
}
|
|
}
|
|
|
|
export function localProxyUrls(port = 8082, host = '127.0.0.1') {
|
|
const urlHost = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
|
|
return {
|
|
socks5: `socks5://${urlHost}:${port}`,
|
|
http: `http://${urlHost}:${port}`,
|
|
};
|
|
}
|
|
|
|
export async function copyText(text, options = {}) {
|
|
const clipboard = options.clipboard ?? globalThis.navigator?.clipboard;
|
|
const documentRef = options.documentRef ?? globalThis.document;
|
|
|
|
if (documentRef?.execCommand) {
|
|
const textarea = documentRef.createElement('textarea');
|
|
textarea.value = text;
|
|
textarea.setAttribute('readonly', '');
|
|
textarea.style.position = 'fixed';
|
|
textarea.style.opacity = '0';
|
|
documentRef.body.append(textarea);
|
|
textarea.select();
|
|
const copied = documentRef.execCommand('copy');
|
|
textarea.remove();
|
|
if (copied) return;
|
|
}
|
|
|
|
if (!clipboard?.writeText) throw new Error('Copy failed');
|
|
await clipboard.writeText(text);
|
|
}
|
|
|
|
export function subscriptionUsage(userInfo = {}) {
|
|
const upload = Math.max(0, Number(userInfo.upload) || 0);
|
|
const download = Math.max(0, Number(userInfo.download) || 0);
|
|
const total = Math.max(0, Number(userInfo.total) || 0);
|
|
const used = upload + download;
|
|
|
|
return {
|
|
upload,
|
|
download,
|
|
total,
|
|
used,
|
|
percent: total ? Math.min(100, (used / total) * 100) : null,
|
|
expiresAt: userInfo.expire ? new Date(Number(userInfo.expire) * 1000) : null,
|
|
};
|
|
}
|
|
|
|
export function subscriptionDaysLeft(expiresAt, now = Date.now()) {
|
|
const days = Math.ceil((expiresAt?.getTime() - now) / 86_400_000);
|
|
if (!Number.isFinite(days)) return '';
|
|
if (days <= 0) return 'срок истёк';
|
|
const mod10 = days % 10;
|
|
const mod100 = days % 100;
|
|
const unit = mod10 === 1 && mod100 !== 11
|
|
? 'день'
|
|
: mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14) ? 'дня' : 'дней';
|
|
return `${days === 1 ? 'остался' : 'осталось'} ${days} ${unit}`;
|
|
}
|