refactor improve data hosting

This commit is contained in:
zeppi 2022-02-08 17:16:22 -05:00 committed by jessopb
parent bbea2887f2
commit 92ed44c0f2
6 changed files with 230 additions and 160 deletions

View file

@ -2280,5 +2280,10 @@
"Shuffle is off.": "Shuffle is off.",
"Loop is on.": "Loop is on.",
"Loop is off.": "Loop is off.",
"View History Hosting lets you choose how much storage to use helping content you've consumed.": "View History Hosting lets you choose how much storage to use helping content you've consumed.",
"Clean Now": "Clean Now",
"Enable Automatic Hosting": "Enable Automatic Hosting",
"Download and serve arbitrary data on the network.": "Download and serve arbitrary data on the network.",
"View History Hosting": "View History Hosting",
"--end--": "--end--"
}

View file

@ -0,0 +1,17 @@
import { connect } from 'react-redux';
import { doSetDaemonSetting, doGetDaemonStatus, doCleanBlobs } from 'redux/actions/settings';
import { selectDaemonStatus, selectDaemonSettings } from 'redux/selectors/settings';
import SettingWalletServer from './view';
const select = (state) => ({
daemonSettings: selectDaemonSettings(state),
daemonStatus: selectDaemonStatus(state),
});
const perform = (dispatch) => ({
getDaemonStatus: () => dispatch(doGetDaemonStatus()),
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
cleanBlobs: () => dispatch(doCleanBlobs()),
});
export default connect(select, perform)(SettingWalletServer);

View file

@ -0,0 +1,195 @@
// @flow
import React from 'react';
import { FormField } from 'component/common/form';
import Button from 'component/button';
import * as DAEMON_SETTINGS from 'constants/daemon_settings';
import { formatBytes } from 'util/format-bytes';
const BYTES_PER_MB = 1048576;
const ENABLE_AUTOMATIC_HOSTING = false;
type Price = {
currency: string,
amount: number,
};
type DaemonStatus = {
disk_space: {
content_blobs_storage_used_mb: string,
published_blobs_storage_used_mb: string,
running: true,
seed_blobs_storage_used_mb: string,
total_used_mb: string,
},
};
type SetDaemonSettingArg = boolean | string | number | Price;
type DaemonSettings = {
download_dir: string,
share_usage_data: boolean,
max_key_fee?: Price,
max_connections_per_download?: number,
save_files: boolean,
save_blobs: boolean,
ffmpeg_path: string,
};
type Props = {
// --- select ---
daemonSettings: DaemonSettings,
daemonStatus: DaemonStatus,
// --- perform ---
setDaemonSetting: (string, ?SetDaemonSettingArg) => void,
cleanBlobs: () => void,
};
function SettingWalletServer(props: Props) {
const { daemonSettings, daemonStatus, setDaemonSetting, cleanBlobs } = props;
const { disk_space } = daemonStatus;
const contentSpaceUsed = Number(disk_space.content_blobs_storage_used_mb);
const networkSpaceUsed = Number(disk_space.seed_blobs_storage_used_mb);
const blobLimitSetting = daemonSettings[DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB];
const networkLimitSetting = daemonSettings[DAEMON_SETTINGS.NETWORK_STORAGE_LIMIT_MB];
const [contentBlobSpaceLimitGB, setContentBlobSpaceLimit] = React.useState(
blobLimitSetting ? blobLimitSetting / 1024 : 0
);
const [networkBlobSpaceLimitGB, setNetworkBlobSpaceLimit] = React.useState(
networkLimitSetting ? networkLimitSetting / 1024 : 0
);
const [limitSpace, setLimitSpace] = React.useState(Boolean(blobLimitSetting));
function updateContentBlobLimitField(gb) {
if (gb === 0) {
setContentBlobSpaceLimit(0);
} else if (!gb || !isNaN(gb)) {
setContentBlobSpaceLimit(gb);
}
}
function updateNetworkBlobLimitField(gb) {
if (gb === 0) {
setNetworkBlobSpaceLimit(0);
} else if (!gb || !isNaN(gb)) {
setNetworkBlobSpaceLimit(gb);
}
}
function handleLimitSpace(value) {
setLimitSpace(value);
if (!value) {
setDaemonSetting(DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB, String(0));
} else {
const spaceLimitMB = contentBlobSpaceLimitGB * 1024;
setDaemonSetting(DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB, String(spaceLimitMB));
}
}
function handleSetContentBlobSpaceLimit() {
const spaceLimitMB = contentBlobSpaceLimitGB * 1024;
if (!isNaN(spaceLimitMB) && blobLimitSetting !== spaceLimitMB * 1024) {
setDaemonSetting(DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB, String(spaceLimitMB));
}
}
function handleSetNetworkBlobSpaceLimit() {
const spaceLimitMB = networkBlobSpaceLimitGB * 1024;
if (!isNaN(spaceLimitMB) && blobLimitSetting !== spaceLimitMB * 1024) {
setDaemonSetting(DAEMON_SETTINGS.NETWORK_STORAGE_LIMIT_MB, String(spaceLimitMB));
}
}
return (
<>
<fieldset-section>
<FormField
type="checkbox"
name="save_blobs"
onChange={() => setDaemonSetting('save_blobs', !daemonSettings.save_blobs)}
checked={daemonSettings.save_blobs}
label={__('Enable Data Hosting')}
/>
</fieldset-section>
{daemonSettings.save_blobs && (
<fieldset-section>
<div className={'settings__row-section-title'}>{__('View History Hosting')}</div>
<div className={'help'}>
{`View History Hosting using ${formatBytes(contentSpaceUsed * BYTES_PER_MB)} of ${
daemonSettings[DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB]
? formatBytes(daemonSettings[DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB] * BYTES_PER_MB)
: 'Unlimited'
}`}
</div>
</fieldset-section>
)}
{daemonSettings.save_blobs && (
<fieldset-section>
<FormField
type="checkbox"
name="limit_space_used"
onChange={() => handleLimitSpace(!limitSpace)}
checked={limitSpace}
label={__('Limit Hosting of Content History')}
/>
</fieldset-section>
)}
{daemonSettings.save_blobs && limitSpace && (
<FormField
name="content_blob_limit_gb"
type="text"
label={__(`Limit (GB)`)}
disabled={!daemonSettings.save_blobs}
onChange={(e) => updateContentBlobLimitField(e.target.value)}
value={contentBlobSpaceLimitGB}
inputButton={
<Button
disabled={isNaN(contentBlobSpaceLimitGB)}
button="primary"
label={__('Apply')}
onClick={handleSetContentBlobSpaceLimit}
/>
}
/>
)}
<fieldset-section>
<Button type="button" button="inverse" onClick={cleanBlobs} label={__('Clean Now')} />
</fieldset-section>
{/* Automatic Hosting Section */}
{daemonSettings.save_blobs && ENABLE_AUTOMATIC_HOSTING && (
<fieldset-section>
<div className={'settings__row-section-title'}>{__('Automatic Hosting - Experimental')}</div>
<p className={'help'}>
{`Automatic Hosting using ${formatBytes(networkSpaceUsed * BYTES_PER_MB)} of ${formatBytes(
daemonSettings[DAEMON_SETTINGS.NETWORK_STORAGE_LIMIT_MB] * BYTES_PER_MB
)}`}
</p>
</fieldset-section>
)}
{daemonSettings.save_blobs && ENABLE_AUTOMATIC_HOSTING && (
<>
<FormField
name="network_blob_limit_gb"
type="text"
label={__(`Allow (GB)`)}
disabled={!daemonSettings.save_blobs}
onChange={(e) => updateNetworkBlobLimitField(e.target.value)}
value={networkBlobSpaceLimitGB}
inputButton={
<Button
disabled={isNaN(networkBlobSpaceLimitGB)}
button="primary"
label={__('Apply')}
onClick={handleSetNetworkBlobSpaceLimit}
/>
}
/>
<div className="form-field__help">{__('Download and serve arbitrary data on the network.')}</div>
</>
)}
</>
);
}
export default SettingWalletServer;

View file

@ -12,7 +12,6 @@ import { doSetDaemonSetting, doClearDaemonSetting, doFindFFmpeg } from 'redux/ac
import { selectAllowAnalytics } from 'redux/selectors/app';
import {
selectDaemonSettings,
selectDaemonStatus,
selectFfmpegStatus,
selectFindingFFmpeg,
selectLanguage,
@ -29,7 +28,6 @@ const select = (state) => ({
isAuthenticated: selectUserVerifiedEmail(state),
allowAnalytics: selectAllowAnalytics(state),
language: selectLanguage(state),
daemonStatus: selectDaemonStatus(state),
});
const perform = (dispatch) => ({

View file

@ -10,17 +10,16 @@ import I18nMessage from 'component/i18nMessage';
import SettingAutoLaunch from 'component/settingAutoLaunch';
import SettingClosingBehavior from 'component/settingClosingBehavior';
import SettingCommentsServer from 'component/settingCommentsServer';
import SettingDataHosting from 'component/settingDataHosting';
import SettingShareUrl from 'component/settingShareUrl';
import SettingsRow from 'component/settingsRow';
import SettingWalletServer from 'component/settingWalletServer';
import Spinner from 'component/spinner';
import { getPasswordFromCookie } from 'util/saved-passwords';
import * as DAEMON_SETTINGS from 'constants/daemon_settings';
import { formatBytes } from 'util/format-bytes';
import SettingEnablePrereleases from 'component/settingEnablePrereleases';
const IS_MAC = process.platform === 'darwin';
const BYTES_PER_MB = 1048576;
type Price = {
currency: string,
@ -39,16 +38,6 @@ type DaemonSettings = {
ffmpeg_path: string,
};
type DaemonStatus = {
disk_space: {
content_blobs_storage_used_mb: string,
published_blobs_storage_used_mb: string,
running: true,
seed_blobs_storage_used_mb: string,
total_used_mb: string,
},
};
type Props = {
// --- select ---
daemonSettings: DaemonSettings,
@ -67,7 +56,6 @@ type Props = {
updateWalletStatus: () => void,
confirmForgetPassword: ({}) => void,
toggle3PAnalytics: (boolean) => void,
daemonStatus: DaemonStatus,
};
export default function SettingSystem(props: Props) {
@ -87,23 +75,10 @@ export default function SettingSystem(props: Props) {
updateWalletStatus,
confirmForgetPassword,
toggle3PAnalytics,
daemonStatus,
} = props;
const [clearingCache, setClearingCache] = React.useState(false);
const [storedPassword, setStoredPassword] = React.useState(false);
const { disk_space } = daemonStatus;
const contentSpaceUsed = Number(disk_space.content_blobs_storage_used_mb);
const networkSpaceUsed = Number(disk_space.seed_blobs_storage_used_mb);
const blobLimitSetting = daemonSettings[DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB];
const networkLimitSetting = daemonSettings[DAEMON_SETTINGS.NETWORK_STORAGE_LIMIT_MB];
const [contentBlobSpaceLimitGB, setContentBlobSpaceLimit] = React.useState(
blobLimitSetting ? blobLimitSetting / 1024 : 0
);
const [networkBlobSpaceLimitGB, setNetworkBlobSpaceLimit] = React.useState(
networkLimitSetting ? networkLimitSetting / 1024 : 0
);
const [limitSpace, setLimitSpace] = React.useState(Boolean(blobLimitSetting));
const { available: ffmpegAvailable, which: ffmpegPath } = ffmpegStatus;
function onChangeEncryptWallet() {
@ -118,46 +93,6 @@ export default function SettingSystem(props: Props) {
confirmForgetPassword({ callback: () => setStoredPassword(false) });
}
function updateContentBlobLimitField(gb) {
if (gb === 0) {
setContentBlobSpaceLimit(0);
} else if (!gb || !isNaN(gb)) {
setContentBlobSpaceLimit(gb);
}
}
function updateNetworkBlobLimitField(gb) {
if (gb === 0) {
setNetworkBlobSpaceLimit(0);
} else if (!gb || !isNaN(gb)) {
setNetworkBlobSpaceLimit(gb);
}
}
function handleLimitSpace(value) {
setLimitSpace(value);
if (!value) {
setDaemonSetting(DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB, String(0));
} else {
const spaceLimitMB = contentBlobSpaceLimitGB * 1024;
setDaemonSetting(DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB, String(spaceLimitMB));
}
}
function handleSetContentBlobSpaceLimit() {
const spaceLimitMB = contentBlobSpaceLimitGB * 1024;
if (!isNaN(spaceLimitMB) && blobLimitSetting !== spaceLimitMB * 1024) {
setDaemonSetting(DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB, String(spaceLimitMB));
}
}
function handleSetNetworkBlobSpaceLimit() {
const spaceLimitMB = networkBlobSpaceLimitGB * 1024;
if (!isNaN(spaceLimitMB) && blobLimitSetting !== spaceLimitMB * 1024) {
setDaemonSetting(DAEMON_SETTINGS.NETWORK_STORAGE_LIMIT_MB, String(spaceLimitMB));
}
}
// Update ffmpeg variables
React.useEffect(() => {
const { available } = ffmpegStatus;
@ -221,95 +156,17 @@ export default function SettingSystem(props: Props) {
subtitle={
<React.Fragment>
{__('Help improve the P2P data network (and make LBRY happy) by hosting data.')}{' '}
{__("History Hosting lets you choose how much storage to use helping content you've consumed.")}{' '}
{__(
'Automatic Hosting lets you delegate some amount of storage for the network to automatically download and host.'
)}{' '}
{__("View History Hosting lets you choose how much storage to use helping content you've consumed.")}{' '}
{/* {__( */}
{/* 'Automatic Hosting lets you delegate some amount of storage for the network to automatically download and host.' */}
{/* )}{' '} */}
{__('Playing videos may exceed your history hosting limit until cleanup runs every 30 minutes.')}
<br />
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/host-content" />
</React.Fragment>
}
>
<fieldset-section>
<FormField
type="checkbox"
name="save_blobs"
onChange={() => setDaemonSetting('save_blobs', !daemonSettings.save_blobs)}
checked={daemonSettings.save_blobs}
label={__('Enable Data Hosting')}
/>
</fieldset-section>
{daemonSettings.save_blobs && (
<fieldset-section>
<div className={'settings__row-section-title'}>{__('History Hosting')}</div>
<p className={'help'}>
{`History Hosting using ${formatBytes(contentSpaceUsed * BYTES_PER_MB)} of ${
daemonSettings[DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB]
? formatBytes(daemonSettings[DAEMON_SETTINGS.BLOB_STORAGE_LIMIT_MB] * BYTES_PER_MB)
: 'Unlimited'
}`}
</p>
</fieldset-section>
)}
{daemonSettings.save_blobs && (
<fieldset-section>
<FormField
type="checkbox"
name="limit_space_used"
onChange={() => handleLimitSpace(!limitSpace)}
checked={limitSpace}
label={__('Limit Hosting of Content History')}
/>
</fieldset-section>
)}
{daemonSettings.save_blobs && limitSpace && (
<FormField
name="content_blob_limit_gb"
type="text"
label={__(`Limit (GB)`)}
disabled={!daemonSettings.save_blobs}
onChange={(e) => updateContentBlobLimitField(e.target.value)}
value={contentBlobSpaceLimitGB}
inputButton={
<Button
disabled={isNaN(contentBlobSpaceLimitGB)}
button="primary"
label={__('Apply')}
onClick={handleSetContentBlobSpaceLimit}
/>
}
/>
)}
{daemonSettings.save_blobs && (
<fieldset-section>
<div className={'settings__row-section-title'}>{__('Automatic Hosting')}</div>
<p className={'help'}>
{`Automatic Hosting using ${formatBytes(networkSpaceUsed * BYTES_PER_MB)} of ${formatBytes(
daemonSettings[DAEMON_SETTINGS.NETWORK_STORAGE_LIMIT_MB] * BYTES_PER_MB
)}`}
</p>
</fieldset-section>
)}
{daemonSettings.save_blobs && (
<FormField
name="network_blob_limit_gb"
type="text"
label={__(`Allow (GB)`)}
disabled={!daemonSettings.save_blobs}
onChange={(e) => updateNetworkBlobLimitField(e.target.value)}
value={networkBlobSpaceLimitGB}
inputButton={
<Button
disabled={isNaN(networkBlobSpaceLimitGB)}
button="primary"
label={__('Apply')}
onClick={handleSetNetworkBlobSpaceLimit}
/>
}
/>
)}
<SettingDataHosting />
</SettingsRow>
<SettingsRow
title={__('Share usage and diagnostic data')}

View file

@ -126,15 +126,13 @@ export function doSetDaemonSetting(key, value, doNotDispatch = false) {
// todo: add sdk reloadsettings() (or it happens automagically?)
}
});
Lbry.settings_get().then((settings) => {
analytics.toggleInternal(settings.share_usage_data);
dispatch({
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
data: {
settings,
},
});
});
dispatch(doFetchDaemonSettings());
};
}
export function doCleanBlobs() {
return (dispatch) => {
Lbry.blob_clean().then(dispatch(doFetchDaemonSettings()));
};
}