mirror of
https://github.com/VirtualHotBar/NetMount.git
synced 2026-06-08 07:32:23 +08:00
Merge branch 'main' into dev-tauri2.0
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "netmount-gui",
|
||||
"private": true,
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -85,7 +85,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "app"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"anyhow-tauri",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "app"
|
||||
description = "NetMount"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
authors = ["VirtualHotBar"]
|
||||
license = ""
|
||||
repository = ""
|
||||
|
||||
@@ -485,5 +485,8 @@
|
||||
"description.lark": "Lark Drive lets you save and manage all your content in cloud storage anytime, anywhere, on any device.",
|
||||
"description.neteasemusic": "NetEase Cloud Music is a music product focused on discovering and sharing.",
|
||||
"description.thunderx": "Thunder X",
|
||||
"description.thunderxexpert": "Thunder X Expert Edition"
|
||||
"description.thunderxexpert": "Thunder X Expert Edition",
|
||||
|
||||
"restartself_to_take_effect": "Restart to take effect",
|
||||
"unable_to_obtain_transmission_speed":"The specific transmission speed may not be available at present, but the transmission is still in progress."
|
||||
}
|
||||
@@ -554,5 +554,8 @@
|
||||
"description.lark": "Lark Drive允许您随时随地在任何设备上保存和管理云存储中的所有内容。",
|
||||
"description.neteasemusic":"网易云音乐是一款专注于发现与分享的音乐产品。",
|
||||
"description.thunderx": "迅雷X",
|
||||
"description.thunderxexpert": "迅雷X专家版"
|
||||
"description.thunderxexpert": "迅雷X专家版",
|
||||
|
||||
"restartself_to_take_effect": "重启软件以使更改生效",
|
||||
"unable_to_obtain_transmission_speed":"当前可能无法获取具体传输速度,但传输仍在进行。"
|
||||
}
|
||||
@@ -554,6 +554,8 @@
|
||||
"description.lark": "Lark Drive讓您隨時隨地在任何裝置上保存和管理雲端儲存的所有內容。",
|
||||
"description.neteasemusic": "網易雲音樂是一款專注於發現與分享的音樂產品。",
|
||||
"description.thunderx": "迅雷X",
|
||||
"description.thunderxexpert": "迅雷X專家版"
|
||||
"description.thunderxexpert": "迅雷X專家版",
|
||||
|
||||
"restartself_to_take_effect": "更改設定需要重新啟動程式才能生效。",
|
||||
"unable_to_obtain_transmission_speed":"當前可能無法獲取具體傳送速率,但傳輸仍在進行。"
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ use app::init;
|
||||
|
||||
fn main(){
|
||||
init()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,19 @@ use std::fs;
|
||||
use std::io::{self, Write};
|
||||
//use tauri::AppHandle;
|
||||
|
||||
|
||||
|
||||
pub fn get_available_ports(count: usize) -> Vec<u16> {
|
||||
use std::net::TcpListener;
|
||||
let mut ports = Vec::new();
|
||||
for _ in 0..count {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").expect("无法绑定端口");
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
ports.push(port);
|
||||
}
|
||||
ports
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn set_window_shadow<R: Runtime>(app: &tauri::App<R>) {
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ async function reupStats() {
|
||||
|
||||
rcloneInfo.stats = {
|
||||
...stats,
|
||||
realSpeed: realSpeed
|
||||
realSpeed: realSpeed||0/* stats.speed */
|
||||
}
|
||||
|
||||
//历史状态
|
||||
|
||||
@@ -7,7 +7,7 @@ import { app } from "@tauri-apps/api";
|
||||
import { nmConfig, osInfo, roConfig } from "../services/config";
|
||||
import { Aria2 } from "../utils/aria2/aria2";
|
||||
import { checkUpdate } from "./update/update";
|
||||
import { getWinFspInstallState, installWinFsp, showPathInExplorer } from "../utils/utils";
|
||||
import { getAvailablePorts, getWinFspInstallState, installWinFsp, showPathInExplorer } from "../utils/utils";
|
||||
import { t } from "i18next";
|
||||
import { FilterType, StorageInfoType, StorageParamItemType } from "../type/controller/storage/info";
|
||||
import { storageInfoList, updateStorageInfoList } from "./storage/allList";
|
||||
@@ -17,6 +17,7 @@ import { alistInfo } from "../services/alist";
|
||||
import { addAlistInRclone } from "../utils/alist/alist";
|
||||
import { restartRclone } from "../utils/rclone/process";
|
||||
import { restartAlist } from "../utils/alist/process";
|
||||
import { exit } from "./main";
|
||||
|
||||
export async function Test() {
|
||||
console.log(nmConfig);
|
||||
@@ -26,6 +27,10 @@ export async function Test() {
|
||||
console.log(await rclone_api_post('/options/get'));
|
||||
console.log(await rclone_api_post('/rc/list'),);
|
||||
|
||||
console.log((await getAvailablePorts(2))[1]);
|
||||
|
||||
//exit(true)
|
||||
|
||||
/* console.log(await rclone_api_post('/operations/publiclink',{
|
||||
fs: convertStoragePath('S3_new',undefined,undefined,undefined,true),
|
||||
remote :convertStoragePath('S3_new','Package/HotPE-V2.7.240201.7z',undefined,true,false),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Alert, Button, Grid, Message, Space, Table, TableColumnProps, Typography } from '@arco-design/web-react'
|
||||
import { Alert, Button, Grid, Message, Modal, Space, Table, TableColumnProps, Typography } from '@arco-design/web-react'
|
||||
import React, { useEffect, useReducer, useState } from 'react'
|
||||
import { rcloneInfo } from '../../services/rclone'
|
||||
import { delMountStorage, isMounted, mountStorage, reupMount, unmountStorage } from '../../controller/storage/mount/mount'
|
||||
@@ -14,6 +14,13 @@ import { restartRclone } from '../../utils/rclone/process'
|
||||
const Row = Grid.Row;
|
||||
const Col = Grid.Col;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function Mount_page() {
|
||||
const { t } = useTranslation()
|
||||
const [ignored, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件
|
||||
@@ -31,7 +38,7 @@ function Mount_page() {
|
||||
{
|
||||
title: t('storage_name'),
|
||||
dataIndex: 'storageName',
|
||||
width:'10rem',
|
||||
width: '10rem',
|
||||
ellipsis: true,
|
||||
render: (text) => {
|
||||
return <Typography.Ellipsis>{text}</Typography.Ellipsis>
|
||||
@@ -40,13 +47,13 @@ function Mount_page() {
|
||||
{
|
||||
title: t('mount_status'),
|
||||
dataIndex: 'mounted',
|
||||
width:'5.5rem',
|
||||
width: '5.5rem',
|
||||
},
|
||||
{
|
||||
title: t('actions'),
|
||||
dataIndex: 'actions',
|
||||
align: 'right',
|
||||
width:'14.3rem'
|
||||
width: '14.3rem'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -86,8 +93,18 @@ function Mount_page() {
|
||||
<Button type='primary' onClick={async () => {
|
||||
setWinFspInstalling(true)
|
||||
if (await installWinFsp()) {
|
||||
await restartRclone()
|
||||
Message.success(t('install_success'))
|
||||
//await restartRclone()
|
||||
Modal.success({
|
||||
title: t('install_success'),
|
||||
simple: true,
|
||||
maskClosable: false,
|
||||
escToExit: false,
|
||||
content: t('restartself_to_take_effect'),
|
||||
onOk: () => {
|
||||
exit(true);
|
||||
},
|
||||
});
|
||||
|
||||
/* Message.info(t('about_to_restart_self'))
|
||||
setTimeout(() => {
|
||||
exit(true)
|
||||
@@ -95,8 +112,8 @@ function Mount_page() {
|
||||
} else {
|
||||
Message.error(t('install_failed'))
|
||||
}
|
||||
setWinFspInstalling(false)
|
||||
await getWinFspState()
|
||||
setWinFspInstalling(false)
|
||||
}} loading={winFspInstalling}>{t('install')}</Button>
|
||||
</>} />
|
||||
<br />
|
||||
@@ -114,14 +131,14 @@ function Mount_page() {
|
||||
mounted: mounted ? t('mounted') : t('unmounted'),
|
||||
actions: <Space>
|
||||
{
|
||||
mounted ? <>
|
||||
mounted ? <>
|
||||
<Button onClick={() => { unmountStorage(item.mountPath) }} status='danger' >{t('unmount')}</Button>
|
||||
</> :
|
||||
<>
|
||||
<Button onClick={() => { delMountStorage(item.mountPath) }} status='danger' >{t('delete')}</Button>
|
||||
<Button onClick={() => { navigate('./add?edit=true&mountPath='+item.mountPath) }} >{t('edit')}</Button>
|
||||
<Button onClick={() => { navigate('./add?edit=true&mountPath=' + item.mountPath) }} >{t('edit')}</Button>
|
||||
<Button onClick={() => { mountStorage(item) }} type='primary' >{t('mount')}</Button>
|
||||
</>
|
||||
</>
|
||||
}
|
||||
</Space>
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'
|
||||
import { rcloneInfo, rcloneStatsHistory } from '../../services/rclone'
|
||||
import { hooks } from '../../services/hook'
|
||||
import { RcloneTransferItem } from '../../type/rclone/stats'
|
||||
import { Card, Descriptions, List, Progress, Space, Statistic, Grid, Typography } from '@arco-design/web-react'
|
||||
import { Card, Descriptions, List, Progress, Space, Statistic, Grid, Typography, Alert } from '@arco-design/web-react'
|
||||
import { formatETA, formatSize } from '../../utils/utils'
|
||||
import { Area } from '@ant-design/charts'
|
||||
import { NoData_module } from '../other/noData'
|
||||
@@ -32,7 +32,17 @@ function Transmit_page() {
|
||||
title={t('overview')}
|
||||
bordered={false}
|
||||
>
|
||||
|
||||
<Space direction='vertical' style={{ width: '100%' }}>
|
||||
{
|
||||
transmitList.length > 0 && rcloneInfo.stats.realSpeed === 0 &&
|
||||
<Alert
|
||||
style={{ margin: '0.1rem' }}
|
||||
type='info'
|
||||
content={t('unable_to_obtain_transmission_speed')}
|
||||
/>
|
||||
}
|
||||
|
||||
|
||||
{rcloneInfo.stats.bytes > 0 && <Progress percent={~~(rcloneInfo.stats.bytes / rcloneInfo.stats.totalBytes * 100)} />}
|
||||
<Descriptions colon=' :' data={[
|
||||
@@ -81,11 +91,11 @@ function Transmit_page() {
|
||||
{
|
||||
transmitList.map((item, index) => {
|
||||
return <List.Item key={index}>
|
||||
<div style={{ width: '100%' ,display: 'flex' }}>
|
||||
<div style={{width:'5rem'}}>
|
||||
<div style={{ width: '100%', display: 'flex' }}>
|
||||
<div style={{ width: '5rem' }}>
|
||||
<Progress type={'circle'} percent={item.percentage} style={{ marginTop: '0.5rem' }} size='small' />
|
||||
</div>
|
||||
<div style={{width:'calc(100% - 5rem)',overflow:'auto'}}>
|
||||
<div style={{ width: 'calc(100% - 5rem)', overflow: 'auto' }}>
|
||||
<Typography.Ellipsis >{item.name}</Typography.Ellipsis>
|
||||
<Descriptions
|
||||
size='small'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { Command } from "@tauri-apps/plugin-shell";
|
||||
import { rcloneInfo } from "../../services/rclone";
|
||||
import { formatPath, randomString, sleep } from "../utils";
|
||||
import { formatPath, getAvailablePorts, randomString, sleep } from "../utils";
|
||||
import { alistInfo } from "../../services/alist";
|
||||
import { homeDir } from "@tauri-apps/api/path";
|
||||
import { nmConfig, osInfo, roConfig } from "../../services/config";
|
||||
@@ -21,7 +21,10 @@ const addParams = (): string[] => {
|
||||
|
||||
|
||||
async function startAlist() {
|
||||
alistInfo.endpoint.url='http://localhost:'+(alistInfo.alistConfig.scheme?.http_port||5573)
|
||||
//自动分配端口
|
||||
alistInfo.alistConfig.scheme!.http_port != (await getAvailablePorts(2))[1]
|
||||
|
||||
alistInfo.endpoint.url = 'http://localhost:' + (alistInfo.alistConfig.scheme?.http_port || 5573)
|
||||
await setAlistPass(nmConfig.framework.alist.password)
|
||||
|
||||
alistInfo.endpoint.auth.token = await getAlistToken()
|
||||
@@ -46,7 +49,7 @@ async function startAlist() {
|
||||
|
||||
while (true) {
|
||||
await sleep(500)
|
||||
if (await alist_api_ping()&&alistInfo.process.log.includes('start HTTP server')) {
|
||||
if (await alist_api_ping() && alistInfo.process.log.includes('start HTTP server')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -56,9 +59,9 @@ async function stopAlist() {
|
||||
alistInfo.process.child && await alistInfo.process.child.kill()
|
||||
}
|
||||
|
||||
async function restartAlist() {
|
||||
async function restartAlist() {
|
||||
await stopAlist()
|
||||
await startAlist()
|
||||
}
|
||||
|
||||
export { addParams, startAlist, stopAlist, alistDataDir ,restartAlist}
|
||||
export { addParams, startAlist, stopAlist, alistDataDir, restartAlist }
|
||||
|
||||
@@ -2,7 +2,7 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
import { Command } from "@tauri-apps/plugin-shell";
|
||||
import { rcloneInfo } from "../../services/rclone";
|
||||
import { rclone_api_noop, rclone_api_post } from "./request";
|
||||
import { formatPath, randomString, sleep } from "../utils";
|
||||
import { formatPath, getAvailablePorts, randomString, sleep } from "../utils";
|
||||
import { alistInfo } from "../../services/alist";
|
||||
import { delStorage } from "../../controller/storage/storage";
|
||||
import { nmConfig, osInfo, roConfig } from "../../services/config";
|
||||
@@ -21,6 +21,9 @@ async function startRclone() {
|
||||
rcloneInfo.endpoint.auth.pass = randomString(128)
|
||||
} */
|
||||
|
||||
//自动分配端口
|
||||
rcloneInfo.endpoint.localhost.port = (await getAvailablePorts(2))[1]
|
||||
|
||||
rcloneInfo.endpoint.url = 'http://localhost:' + rcloneInfo.endpoint.localhost.port.toString()
|
||||
|
||||
let args: string[] = [
|
||||
|
||||
@@ -212,4 +212,9 @@ export async function showPathInExplorer(path: string, isDir?: boolean) {
|
||||
|
||||
export async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
|
||||
export async function getAvailablePorts(count: number = 1) {
|
||||
return await invoke('get_available_ports',{count:count}) as number[]
|
||||
}
|
||||
Reference in New Issue
Block a user