Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75de353af6 | |||
| 12ef425b01 | |||
| 34a3a70569 | |||
| b050c36904 | |||
| f96f23360c | |||
| d4cc335fbf |
@@ -16,10 +16,9 @@ type App struct {
|
||||
logChan chan string
|
||||
uploaderCTX context.Context
|
||||
uploaderCancel context.CancelFunc
|
||||
isRun bool
|
||||
}
|
||||
|
||||
var isRun = false
|
||||
|
||||
func NewApp() *App {
|
||||
return &App{}
|
||||
}
|
||||
@@ -33,15 +32,24 @@ func (a *App) startup(ctx context.Context) {
|
||||
go func() {
|
||||
for log := range a.logChan {
|
||||
runtime.EventsEmit(a.ctx, "log", log)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// 后台 goroutine 持续推送运行状态
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
runtime.EventsEmit(a.ctx, "is-run", a.isRun)
|
||||
}
|
||||
}()
|
||||
|
||||
//在程序启动时运行上传程序
|
||||
a.uploaderCTX, a.uploaderCancel = context.WithCancel(a.ctx)
|
||||
if config.APPConfig.IsRunOnStart {
|
||||
time.Sleep(time.Second)
|
||||
isRun = true
|
||||
a.uploaderCTX, a.uploaderCancel = context.WithCancel(a.ctx)
|
||||
go uploader.StartLooking(a.uploaderCTX, &a.logChan, config.APPConfig.CheckDir)
|
||||
a.isRun = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,20 +65,22 @@ func (a *App) GetConfig() config.Config {
|
||||
}
|
||||
|
||||
func (a *App) WriteConfig(key string, value any) {
|
||||
fmt.Println(key, value)
|
||||
config.WriteConfig(key, value)
|
||||
}
|
||||
|
||||
func (a *App) StartUpload() {
|
||||
if isRun {
|
||||
if a.isRun {
|
||||
return
|
||||
}
|
||||
a.uploaderCTX, a.uploaderCancel = context.WithCancel(a.ctx)
|
||||
go uploader.StartLooking(a.uploaderCTX, &a.logChan, config.APPConfig.CheckDir)
|
||||
a.isRun = true
|
||||
}
|
||||
|
||||
func (a *App) StopUpload() {
|
||||
if isRun {
|
||||
if a.isRun {
|
||||
a.uploaderCancel()
|
||||
}
|
||||
a.isRun = false
|
||||
uploader.AddLog(&a.logChan, "上传程序已退出")
|
||||
}
|
||||
|
||||
+38
-20
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import {ref, nextTick, watch} from 'vue'
|
||||
import {ref, nextTick, watch, computed} from 'vue'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {ElMessageBox} from 'element-plus'
|
||||
import {SelectPath, GetConfig, WriteConfig, StartUpload, StopUpload} from '../wailsjs/go/main/App';
|
||||
@@ -12,11 +12,12 @@ const token = ref('')
|
||||
const checkDir = ref('')
|
||||
const concurrentFiles = ref(1)
|
||||
const uploadThreads = ref(1)
|
||||
const autoStart = ref(false)
|
||||
|
||||
const progress = ref(0)
|
||||
const isRunning = ref(false)
|
||||
const logOutput = ref<string[]>([])
|
||||
const logContentRef = ref<HTMLElement>()
|
||||
const logRoll = ref(true)
|
||||
|
||||
interface FileProgress {
|
||||
name: string
|
||||
@@ -29,10 +30,21 @@ const progressList = ref<FileProgress[]>([
|
||||
// {name: '测试文件1.txt', uploaded: 100, total: 500, percentage: 20},
|
||||
])
|
||||
|
||||
const sortedProgressList = computed(() => {
|
||||
return [...progressList.value].sort((a, b) => {
|
||||
const getPriority = (item: FileProgress) => {
|
||||
if (item.percentage === 100) return 2
|
||||
if (item.percentage === 0) return 1
|
||||
return 0
|
||||
}
|
||||
return getPriority(a) - getPriority(b)
|
||||
})
|
||||
})
|
||||
|
||||
const addLog = (msg: string) => {
|
||||
logOutput.value.push(`[${new Date().toLocaleString()}]` + msg)
|
||||
nextTick(() => {
|
||||
if (logContentRef.value) {
|
||||
if (logContentRef.value && logRoll.value) {
|
||||
logContentRef.value.scrollTop = logContentRef.value.scrollHeight
|
||||
}
|
||||
})
|
||||
@@ -58,26 +70,15 @@ const startRun = () => {
|
||||
ElMessage.warning('请选择检测目录')
|
||||
return
|
||||
}
|
||||
isRunning.value = true
|
||||
progress.value = 0
|
||||
addLog("===============================================")
|
||||
// addLog(`开始运行...`)
|
||||
addLog(`服务器: ${serverUrl.value}`)
|
||||
addLog(`检测目录: ${checkDir.value}`)
|
||||
addLog(`同时处理文件数: ${concurrentFiles.value}`)
|
||||
addLog(`单文件上传线程: ${uploadThreads.value}`)
|
||||
addLog("===============================================")
|
||||
|
||||
StartUpload()
|
||||
}
|
||||
|
||||
const stopRun = () => {
|
||||
if (isRunning.value) {
|
||||
isRunning.value = false
|
||||
addLog(`正在停止运行`)
|
||||
StopUpload().then(() => {
|
||||
ElMessage.info('已停止运行')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const clearLog = () => {
|
||||
@@ -100,6 +101,7 @@ try {
|
||||
checkDir.value = config.check_dir
|
||||
concurrentFiles.value = config.handle_file_count
|
||||
uploadThreads.value = config.thread_count
|
||||
autoStart.value = config.is_run_on_start
|
||||
|
||||
LogPrint(`[${new Date().toLocaleString()}] 配置已加载`)
|
||||
})
|
||||
@@ -122,13 +124,19 @@ watch(concurrentFiles, () => {
|
||||
watch(uploadThreads, () => {
|
||||
WriteConfig("thread-count", uploadThreads.value)
|
||||
})
|
||||
watch(autoStart, () => {
|
||||
WriteConfig("is-run-on-start", autoStart.value)
|
||||
})
|
||||
|
||||
EventsOn("log", (msg) => {
|
||||
addLog(msg)
|
||||
EventsOn("is-run", (run) => {
|
||||
isRunning.value = run
|
||||
})
|
||||
EventsOn("progress", (progress) => {
|
||||
progressList.value = progress
|
||||
})
|
||||
EventsOn("log", (msg) => {
|
||||
addLog(msg)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -162,10 +170,14 @@ EventsOn("progress", (progress) => {
|
||||
<el-input-number v-model="uploadThreads" :min="1" :max="100" :disabled="isRunning"/>
|
||||
</div>
|
||||
|
||||
<div class="form-item">
|
||||
<el-checkbox v-model="autoStart" label="运行时自动启动上传" size="large" :disabled="isRunning"/>
|
||||
</div>
|
||||
|
||||
<div class="form-item">
|
||||
<label>上传进度</label>
|
||||
<div class="progress-list">
|
||||
<div v-for="(item, index) in progressList" :key="index" class="progress-item">
|
||||
<div v-for="(item, index) in sortedProgressList" :key="index" class="progress-item">
|
||||
<span class="file-name">{{ item.name }}</span>
|
||||
<el-progress :percentage="item.percentage" :status="item.percentage === 100 ? 'success' : undefined"/>
|
||||
<span class="progress-text">{{ item.uploaded }}/{{ item.total }}</span>
|
||||
@@ -181,7 +193,10 @@ EventsOn("progress", (progress) => {
|
||||
</div>
|
||||
|
||||
<div class="right-panel">
|
||||
<div class="log-header">日志输出</div>
|
||||
<div class="log-header">
|
||||
日志输出
|
||||
<el-checkbox v-model="logRoll" label="开启日志滚动"/>
|
||||
</div>
|
||||
<div class="log-content" ref="logContentRef">
|
||||
<div v-for="(log, index) in logOutput" :key="index" class="log-line">{{ log }}</div>
|
||||
</div>
|
||||
@@ -212,7 +227,6 @@ EventsOn("progress", (progress) => {
|
||||
.form-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.form-item label {
|
||||
@@ -238,6 +252,7 @@ EventsOn("progress", (progress) => {
|
||||
}
|
||||
|
||||
.progress-list {
|
||||
margin-top: 12px;
|
||||
max-height: 160px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
@@ -286,6 +301,9 @@ EventsOn("progress", (progress) => {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
|
||||
+4
-5
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
var httpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 200,
|
||||
MaxIdleConnsPerHost: 200,
|
||||
MaxIdleConns: 500,
|
||||
MaxIdleConnsPerHost: 500,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
},
|
||||
Timeout: 30 * time.Second,
|
||||
@@ -38,9 +38,8 @@ func UploadDataToServer(ctx context.Context, data string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp != nil {
|
||||
_, _ = io.Copy(io.Discard, resp.Body)
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,6 +18,15 @@ type Config struct {
|
||||
|
||||
var APPConfig Config
|
||||
|
||||
const (
|
||||
Url = "url"
|
||||
Token = "token"
|
||||
ThreadCount = "thread-count"
|
||||
HandleFileCount = "handle-file-count"
|
||||
IsRunOnStart = "is-run-on-start"
|
||||
CheckDir = "check-dir"
|
||||
)
|
||||
|
||||
func InitConfig() {
|
||||
// 设置默认配置
|
||||
defaultConfig := Config{
|
||||
@@ -28,12 +37,12 @@ func InitConfig() {
|
||||
IsRunOnStart: false,
|
||||
CheckDir: "",
|
||||
}
|
||||
viper.SetDefault("url", defaultConfig.Url)
|
||||
viper.SetDefault("token", defaultConfig.Token)
|
||||
viper.SetDefault("thread-count", defaultConfig.ThreadCount)
|
||||
viper.SetDefault("handle-file-count", defaultConfig.HandleFileCount)
|
||||
viper.SetDefault("is-run-on-start", defaultConfig.IsRunOnStart)
|
||||
viper.SetDefault("looking-path", defaultConfig.CheckDir)
|
||||
viper.SetDefault(Url, defaultConfig.Url)
|
||||
viper.SetDefault(Token, defaultConfig.Token)
|
||||
viper.SetDefault(ThreadCount, defaultConfig.ThreadCount)
|
||||
viper.SetDefault(HandleFileCount, defaultConfig.HandleFileCount)
|
||||
viper.SetDefault(IsRunOnStart, defaultConfig.IsRunOnStart)
|
||||
viper.SetDefault(CheckDir, defaultConfig.CheckDir)
|
||||
|
||||
//设置配置文件名和路径 ./config.toml
|
||||
viper.AddConfigPath(".")
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -33,9 +34,23 @@ type Progress struct {
|
||||
}
|
||||
|
||||
func StartLooking(ctx context.Context, logChan *chan string, lookingPath string) {
|
||||
AddLog(logChan, "===============================================")
|
||||
AddLog(logChan, `服务器: `+config.APPConfig.Url)
|
||||
AddLog(logChan, `Token: `+config.APPConfig.Token)
|
||||
AddLog(logChan, `检测目录: `+config.APPConfig.CheckDir)
|
||||
AddLog(logChan, `同时处理文件数: `+strconv.Itoa(config.APPConfig.HandleFileCount))
|
||||
AddLog(logChan, `单文件上传线程: `+strconv.Itoa(config.APPConfig.ThreadCount))
|
||||
AddLog(logChan, "===============================================")
|
||||
|
||||
progress.Clear()
|
||||
//推送上传进度
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
var pg []Progress
|
||||
progress.Range(func(key, value any) bool {
|
||||
@@ -45,6 +60,7 @@ func StartLooking(ctx context.Context, logChan *chan string, lookingPath string)
|
||||
})
|
||||
runtime.EventsEmit(ctx, "progress", pg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
@@ -52,7 +68,6 @@ func StartLooking(ctx context.Context, logChan *chan string, lookingPath string)
|
||||
select {
|
||||
case <-time.After(time.Minute):
|
||||
case <-ctx.Done():
|
||||
AddLog(logChan, "上传程序已退出")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -103,6 +118,7 @@ func uploadData(ctx context.Context, logChan *chan string, lookingPath string) {
|
||||
fileLines[filepath.Base(filePath)] = lineCount
|
||||
isAllEmpty = false
|
||||
AddLog(logChan, fmt.Sprintf("%s 文件行数:%v", filepath.Base(filePath), lineCount))
|
||||
progress.Store(filepath.Base(filePath), Progress{FileName: filepath.Base(filePath), Total: lineCount, Uploaded: 0, Percentage: 0})
|
||||
}
|
||||
}
|
||||
if isAllEmpty {
|
||||
@@ -121,6 +137,10 @@ func uploadData(ctx context.Context, logChan *chan string, lookingPath string) {
|
||||
g.SetLimit(config.APPConfig.HandleFileCount) // 设置同时处理文件数
|
||||
// 执行所有任务
|
||||
for _, task := range tasks {
|
||||
select {
|
||||
case <-egctx.Done():
|
||||
return
|
||||
default:
|
||||
g.Go(func() error {
|
||||
select {
|
||||
case <-egctx.Done():
|
||||
@@ -130,6 +150,10 @@ func uploadData(ctx context.Context, logChan *chan string, lookingPath string) {
|
||||
|
||||
processFile(egctx, logChan, task.FilePath, task.FileLines)
|
||||
|
||||
select {
|
||||
case <-egctx.Done():
|
||||
return egctx.Err()
|
||||
default:
|
||||
//上传完成,清空文件
|
||||
err := os.Truncate(task.FilePath, 0)
|
||||
if err != nil {
|
||||
@@ -137,9 +161,15 @@ func uploadData(ctx context.Context, logChan *chan string, lookingPath string) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
// 等待所有任务完成
|
||||
if err := g.Wait(); err != nil {
|
||||
AddLog(logChan, fmt.Sprintf("任务执行出错: %v", err))
|
||||
@@ -149,6 +179,7 @@ func uploadData(ctx context.Context, logChan *chan string, lookingPath string) {
|
||||
|
||||
AddLog(logChan, fmt.Sprintf("上传完成,耗时:%s", time.Since(start).String()))
|
||||
progress.Clear()
|
||||
}
|
||||
}
|
||||
|
||||
// 获取目录中的所有txt文件
|
||||
@@ -189,10 +220,15 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
|
||||
var countLine int32 = 0
|
||||
// 创建指定个worker同时处理文件上传
|
||||
for i := 0; i < config.APPConfig.ThreadCount; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
wg.Go(func() {
|
||||
processLines(ctx, logChan, &lines, i, filePath, &countLine)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 读取文件并发送到通道
|
||||
scanner := bufio.NewScanner(file)
|
||||
@@ -211,6 +247,7 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
close(lines)
|
||||
wg.Wait()
|
||||
return
|
||||
default:
|
||||
progress.Store(filepath.Base(filePath),
|
||||
@@ -230,7 +267,7 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
|
||||
return
|
||||
}
|
||||
|
||||
AddLog(logChan, fmt.Sprintf("文件【%s】处理完成,共处理 %d 行数据", filePath, countLine))
|
||||
AddLog(logChan, fmt.Sprintf("文件【%s】处理完成,共处理 %d 行数据", filepath.Base(filePath), countLine))
|
||||
}
|
||||
|
||||
func processLines(ctx context.Context, logChan *chan string, lines *chan string, workerID int, filePath string, countLine *int32) {
|
||||
@@ -245,13 +282,14 @@ func processLines(ctx context.Context, logChan *chan string, lines *chan string,
|
||||
}
|
||||
// 上传数据
|
||||
if err := api.UploadDataToServer(ctx, line); err != nil {
|
||||
AddLog(logChan, fmt.Sprintf("Worker %d (文件 %s): 上传失败: %v", workerID, filePath, err))
|
||||
AddLog(logChan, fmt.Sprintf("Worker %d (文件 %s): 上传失败: %v", workerID, filepath.Base(filePath), err))
|
||||
}
|
||||
atomic.AddInt32(countLine, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddLog 添加日志
|
||||
func AddLog(logChan *chan string, message string) {
|
||||
*logChan <- message
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user