Files
2023-08-18 11:55:54 +08:00

254 lines
5.5 KiB
Go

package task
import (
"bufio"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)
type Task struct {
Path string
FileMutex *sync.Mutex
TaskFunc func(string, *Task)
RuningTaskPath map[string]int
}
func NewTask(path string) *Task {
var fileMutex sync.Mutex
return &Task{
Path: path,
FileMutex: &fileMutex,
TaskFunc: nil,
RuningTaskPath: make(map[string]int),
}
}
func (task *Task) SetTaskFunc(f func(string, *Task)) {
task.TaskFunc = f
}
func (task *Task) LogTask(msg string) error {
task.FileMutex.Lock()
defer task.FileMutex.Unlock()
path := task.Path
task.checkOrCreatePath(path)
currentTime := time.Now().Unix()
filePath := path + "/" + strconv.FormatInt(currentTime, 10) + ".log" // 目标文件路径
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Println("打开task文件失败:", err)
return err
}
defer file.Close()
// 写入内容到文件
_, err = file.WriteString(msg + "\n")
if err != nil {
log.Println("写入task文件失败:", err)
return err
}
return nil
}
func (task *Task) LogFailTask(msg string) error {
task.FileMutex.Lock()
defer task.FileMutex.Unlock()
path := task.Path + "/fail/"
task.checkOrCreatePath(path)
currentTime := time.Now()
currentHour := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), currentTime.Hour(), 0, 0, 0, currentTime.Location())
timestamp := currentHour.Unix()
filePath := path + strconv.FormatInt(timestamp, 10) + ".log" // 目标文件路径
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Println("打开task文件失败:", err)
return err
}
defer file.Close()
// 写入内容到文件
_, err = file.WriteString(msg + "\n")
if err != nil {
log.Println("写入task文件失败:", err)
return err
}
return nil
}
func (task *Task) checkOrCreatePath(path string) {
dir := path
// 检查任务目录是否存在
_, err := os.Stat(dir)
if os.IsNotExist(err) {
// 任务目录不存在,创建任务目录
err := os.MkdirAll(dir, 0755)
if err != nil {
log.Println(task.Path+" 目录创建失败:", err)
return
}
log.Println(task.Path + " 目录创建成功")
}
}
func (task *Task) TaskServer() {
// 扫描接收文件协程
go func() {
task.ScanTask()
}()
}
func (task *Task) ScanTask() {
path := task.Path
log.Println("扫描任务目录: " + path)
for {
currentTime := time.Now().Unix()
dirRead, err := os.Open(path)
if err != nil {
time.Sleep(1 * time.Second)
continue
}
for {
files, err := dirRead.Readdir(10) // 每次读取10个文件
if err != nil && len(files) == 0 {
// 读取完所有文件或发生错误
time.Sleep(500 * time.Microsecond)
break
}
for _, file := range files {
fileName := file.Name()
ext := filepath.Ext(fileName)
fileNameWithoutExt := strings.TrimSuffix(fileName, ext)
fileTime, err := strconv.ParseInt(fileNameWithoutExt, 10, 64)
if err != nil {
continue // 跳过无法转换为时间戳的文件名
}
if ext == ".log" {
if fileTime < currentTime-1 {
filePath := path + "/" + fileName
log.Println("扫描到文件: " + filePath)
newFilePath := path + "/" + fileNameWithoutExt + ".scanned"
err := os.Rename(filePath, newFilePath)
if err != nil {
log.Println(filePath + " 文件重命名失败: " + err.Error())
}
task.HandleTask(path + "/" + fileNameWithoutExt)
}
}
if ext == ".scanned" {
if fileTime < currentTime-600 {
filePath := path + "/" + fileName
// 非执行中的十分钟前未处理的重新处理
if _, exists := task.RuningTaskPath[filePath]; !exists {
log.Println("扫描到超时scanned需重新执行文件: " + filePath)
task.HandleTask(path + "/" + fileNameWithoutExt)
}
}
}
}
}
dirRead.Close()
}
}
func (task *Task) HandleTask(path string) {
filePath := path + ".scanned"
task.RuningTaskPath[path] = 1
log.Println("开始处理文件: " + filePath)
// 判断文件是否存在
_, err := os.Stat(filePath)
if os.IsNotExist(err) {
log.Println(filePath + " 文件不存在")
return
}
// 打开文件
file, err := os.Open(filePath)
if err != nil {
log.Println(filePath + " 文件打开失败: " + err.Error())
return
}
// 自定义缓冲区大小为 20 * 1MB
const bufferSize = 20 * 1024 * 1024
// 逐行读取文件内容
scanner := bufio.NewScanner(file)
// 设置缓冲区大小
buf := make([]byte, bufferSize)
scanner.Buffer(buf, bufferSize)
i := 0 // 消息数计数器
wg := sync.WaitGroup{}
lineLimitChan := make(chan bool, 10) // 限制协程数量
for scanner.Scan() {
lineLimitChan <- true
line := scanner.Text()
if task.TaskFunc != nil {
wg.Add(1)
go func() {
task.TaskFunc(line, task)
<-lineLimitChan
wg.Done()
}()
}
i = i + 1
}
wg.Wait()
if err := scanner.Err(); err != nil {
err := os.Rename(filePath, path+".error")
if err != nil {
log.Println(filePath + " 文件重命名失败: " + err.Error())
}
log.Println(filePath + " 文件扫描出错: " + err.Error())
return
}
// 文件扫描完毕
file.Close()
log.Printf(filePath+" 文件处理完毕, 共处理[%d]条信息", i)
err = os.Remove(filePath)
if err != nil {
log.Println(filePath + " 文件删除失败: " + err.Error())
return
}
log.Println(filePath + " 文件处理完成后删除")
delete(task.RuningTaskPath, path)
}