Browse Source

change files

master
godo 9 months ago
parent
commit
7d9e9165e7
  1. 8
      frontend/src/components/localchat/ChatContent.vue
  2. 73
      frontend/src/stores/localchat.ts
  3. 389
      godo/localchat/file.go
  4. 8
      godo/localchat/server.go

8
frontend/src/components/localchat/ChatContent.vue

@ -111,7 +111,7 @@ async function scroll({ scrollTop }: { scrollTop: number }) {
<span v-if="item.content.status === 'accessing'">
接收中
</span>
<span v-if="item.content.status === 'accessed'">
<span v-if="item.content.status === 'confirm'">
已接收
</span>
</template>
@ -129,10 +129,10 @@ async function scroll({ scrollTop }: { scrollTop: number }) {
</div>
<template #footer>
<span v-if="item.content.status === 'apply'">对方确认中</span>
<span v-if="item.content.status === 'confirm'">
对方已接收
<span v-if="item.content.status === 'fileAccessed'">
对方已确认
</span>
<span v-if="item.content.status === 'cannel'">
<span v-if="item.content.status === 'fileCannel'">
对方已拒绝
</span>
</template>

73
frontend/src/stores/localchat.ts

@ -57,7 +57,7 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
else if (msg.type === "fileSending"){
addText(msg)
}
else if( msg.type === "fileCannel") {
else if( msg.type === "fileCannel" || msg.type === "fileAccessed") {
changeMsg(msg)
}
})
@ -261,42 +261,6 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
}
await getUserList()
}
const addFile = async (data: any) => {
const targetUser: any = await getTargetUser(data)
const files: any = []
data.fileList.forEach((d: any) => {
d.save_path = d.save_path.replace(/\\/g, "/");
files.push({
name: d.name,
path: d.save_path,
ext: d.save_path.split('.').pop(),
content: d.content
})
})
const saveMsg: any = {
type: 'file',
targetId: targetUser.id,
targetIp: targetUser.ip,
content: files,
reciperInfo: data.senderInfo,
createdAt: Date.now(),
isMe: false,
isRead: false,
status: 'reciped'
}
if (targetUser.id === chatTargetId.value) {
saveMsg.readAt = Date.now()
saveMsg.isRead = true
msgList.value.push(saveMsg)
}
//console.log(saveMsg)
await db.addOne('chatmsg', saveMsg)
//await getMsgList()
await updateContentList(saveMsg)
handleSelect(1)
}
const getTargetUser = async (data: any) => {
let targetUser: any = userList.value.find((d: any) => d.ip === data.ip)
@ -432,21 +396,42 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
notifyError("确认失败!")
} else {
item.content.status = 'cannel'
await db.update('chatmsg', item.id, item)
console.log(item)
await db.update('chatmsg', item.id, toRaw(item))
await updateContentList(item)
notifySuccess("确认成功!")
}
}
async function changeMsg(msg:any){
console.log(msg)
//console.log(msg)
const msgId = msg.message
const item = await db.getOne('chatmsg', msgId)
item.content.status = 'cannel'
//console.log(item)
item.content.status = msg.type
await db.update('chatmsg', item.id, item)
await updateContentList(item)
await getMsgList()
}
async function accessFile(item:any){
const messages = {
type: 'accessFile',
message: item.content,
ip: item.targetIp
}
const postUrl = `${config.apiUrl}/localchat/accessfile`
const coms = await fetch(postUrl, {
method: "POST",
body: JSON.stringify(messages),
})
if (!coms.ok) {
//console.log(coms)
notifyError("确认失败!")
} else {
item.content.status = 'accessing'
//console.log(item)
await db.update('chatmsg', item.id, toRaw(item))
await getMsgList()
//notifySuccess("确认成功!")
}
}
return {
@ -463,7 +448,6 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
showChooseFile,
pageSize,
showAddUser,
//OutUserList,
init,
setUserList,
getUserList,
@ -471,12 +455,9 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
setChatId,
sendMsg,
addText,
addFile,
//uploadFile,
moreMsgList,
refreshUserList,
clearMsg,
//addUser,
handlerMessage,
cannelFile,
accessFile

389
godo/localchat/file.go

@ -24,19 +24,10 @@
package localchat
import (
"encoding/binary"
"encoding/json"
"fmt"
"godo/libs"
"io"
"log"
"net"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)
@ -108,213 +99,223 @@ func HandlerAccessFile(w http.ResponseWriter, r *http.Request) {
msg.Time = time.Now()
msg.Type = "fileAccessed"
SendToIP(msg)
libs.SuccessMsg(w, nil, "请求文件发送成功")
}
func HandlerSendFile(msg UdpMessage) {
toIp := msg.IP
hostname, err := os.Hostname()
err = downloadFiles(msg)
if err != nil {
log.Printf("HandleMessage error: %v", err)
return
}
msg.Hostname = hostname
msg.Time = time.Now()
msg.Type = "file"
basePath, err := libs.GetOsDir()
if err != nil {
log.Printf("GetOsDir error: %v", err)
return
}
paths, ok := msg.Message.([]string)
if !ok {
log.Printf("invalid message type")
libs.ErrorMsg(w, "HandleMessage error")
return
}
for _, p := range paths {
filePath := filepath.Join(basePath, p)
// 处理单个文件或整个文件夹
if fileInfo, err := os.Stat(filePath); err == nil {
if fileInfo.IsDir() {
handleDirectory(filePath, toIp, msg)
} else {
handleFile(filePath, toIp, msg)
}
} else {
continue
}
}
msg.Type = "fileSended"
msg.Message = ""
msg.Time = time.Now()
SendToIP(msg)
libs.SuccessMsg(w, msg.Message, "接收文件中")
}
func downloadFiles(msg UdpMessage) error {
func handleFile(filePath string, toIp string, message UdpMessage) {
// 打开文件
file, err := os.Open(filePath)
if err != nil {
log.Fatalf("Failed to open file: %v", err)
}
defer file.Close()
return nil
}
// 获取文件大小
fileInfo, err := file.Stat()
if err != nil {
log.Fatalf("Failed to get file info: %v", err)
}
fileSize := fileInfo.Size()
// func HandlerSendFile(msg UdpMessage) {
// toIp := msg.IP
// hostname, err := os.Hostname()
// if err != nil {
// log.Printf("HandleMessage error: %v", err)
// return
// }
// msg.Hostname = hostname
// msg.Time = time.Now()
// msg.Type = "file"
// basePath, err := libs.GetOsDir()
// if err != nil {
// log.Printf("GetOsDir error: %v", err)
// return
// }
// paths, ok := msg.Message.([]string)
// if !ok {
// log.Printf("invalid message type")
// return
// }
// for _, p := range paths {
// filePath := filepath.Join(basePath, p)
// // 处理单个文件或整个文件夹
// if fileInfo, err := os.Stat(filePath); err == nil {
// if fileInfo.IsDir() {
// handleDirectory(filePath, toIp, msg)
// } else {
// handleFile(filePath, toIp, msg)
// }
// } else {
// continue
// }
// }
// msg.Type = "fileSended"
// msg.Message = ""
// msg.Time = time.Now()
// SendToIP(msg)
// }
// 计算需要发送的数据包数量
numChunks := fileSize / GlobalfileSize
if fileSize%GlobalfileSize != 0 {
numChunks++
}
// 发送文件
SendFile(file, int(numChunks), toIp, fileSize, message)
}
// func handleFile(filePath string, toIp string, message UdpMessage) {
// // 打开文件
// file, err := os.Open(filePath)
// if err != nil {
// log.Fatalf("Failed to open file: %v", err)
// }
// defer file.Close()
func handleDirectory(dirPath string, toIp string, message UdpMessage) {
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
handleFile(path, toIp, message)
}
return nil
})
if err != nil {
log.Fatalf("Failed to walk directory: %v", err)
}
}
func SendFile(file *os.File, numChunks int, toIp string, fSize int64, message UdpMessage) {
var wg sync.WaitGroup
// // 获取文件大小
// fileInfo, err := file.Stat()
// if err != nil {
// log.Fatalf("Failed to get file info: %v", err)
// }
// fileSize := fileInfo.Size()
// 逐块读取文件并发送
for i := 0; i < numChunks; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
idStr := message.Type + "@" + message.Hostname + "@" + filepath.Base(file.Name()) + "@" + fmt.Sprintf("%d", fSize) + "@"
chunkData := make([]byte, GlobalfileSize)
n, err := file.Read(chunkData[:])
if err != nil && err != io.EOF {
log.Fatalf("Failed to read file chunk: %v", err)
}
sendBinaryData(idStr, chunkData[:n], toIp)
fmt.Printf("发送文件块 %d 到 %s 成功\n", index, toIp)
}(i)
}
// // 计算需要发送的数据包数量
// numChunks := fileSize / GlobalfileSize
// if fileSize%GlobalfileSize != 0 {
// numChunks++
// }
// // 发送文件
// SendFile(file, int(numChunks), toIp, fileSize, message)
// }
wg.Wait()
}
func sendBinaryData(idStr string, data []byte, toIp string) {
port := "56780"
addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port))
if err != nil {
log.Fatalf("Failed to resolve UDP address: %v", err)
}
// func handleDirectory(dirPath string, toIp string, message UdpMessage) {
// err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
// if err != nil {
// return err
// }
// if !info.IsDir() {
// handleFile(path, toIp, message)
// }
// return nil
// })
// if err != nil {
// log.Fatalf("Failed to walk directory: %v", err)
// }
// }
// func SendFile(file *os.File, numChunks int, toIp string, fSize int64, message UdpMessage) {
// var wg sync.WaitGroup
conn, err := net.DialUDP("udp4", nil, addr)
if err != nil {
log.Fatalf("Failed to dial UDP address: %v", err)
}
defer conn.Close()
// // 逐块读取文件并发送
// for i := 0; i < numChunks; i++ {
// wg.Add(1)
// go func(index int) {
// defer wg.Done()
// idStr := message.Type + "@" + message.Hostname + "@" + filepath.Base(file.Name()) + "@" + fmt.Sprintf("%d", fSize) + "@"
// chunkData := make([]byte, GlobalfileSize)
// n, err := file.Read(chunkData[:])
// if err != nil && err != io.EOF {
// log.Fatalf("Failed to read file chunk: %v", err)
// }
// sendBinaryData(idStr, chunkData[:n], toIp)
// fmt.Printf("发送文件块 %d 到 %s 成功\n", index, toIp)
// }(i)
// }
// 添加长度前缀
identifier := []byte(idStr)
lengthPrefix := make([]byte, 4)
binary.BigEndian.PutUint32(lengthPrefix, uint32(len(data)))
// wg.Wait()
// }
// func sendBinaryData(idStr string, data []byte, toIp string) {
// port := "56780"
// addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port))
// if err != nil {
// log.Fatalf("Failed to resolve UDP address: %v", err)
// }
// 发送长度前缀和数据
_, err = conn.Write(append(append(identifier, lengthPrefix...), data...))
if err != nil {
log.Printf("Failed to write data: %v", err)
}
}
// conn, err := net.DialUDP("udp4", nil, addr)
// if err != nil {
// log.Fatalf("Failed to dial UDP address: %v", err)
// }
// defer conn.Close()
var fileLocks = make(map[string]*sync.Mutex)
// // 添加长度前缀
// identifier := []byte(idStr)
// lengthPrefix := make([]byte, 4)
// binary.BigEndian.PutUint32(lengthPrefix, uint32(len(data)))
func ReceiveFiles(parts []string) (string, error) {
fileName := parts[2]
fileSize, err := strconv.ParseInt(parts[3], 10, 64)
if err != nil {
return "", fmt.Errorf("failed to parse file size: %v", err)
}
// // 发送长度前缀和数据
// _, err = conn.Write(append(append(identifier, lengthPrefix...), data...))
// if err != nil {
// log.Printf("Failed to write data: %v", err)
// }
// }
// 创建接收文件的目录
baseDir, err := libs.GetOsDir()
if err != nil {
log.Printf("Failed to get OS directory: %v", err)
return "", fmt.Errorf("failed to get OS directory")
}
// var fileLocks = make(map[string]*sync.Mutex)
resPath := filepath.Join("C", "Users", "Reciv", time.Now().Format("2006-01-02"))
receiveDir := filepath.Join(baseDir, resPath)
if !libs.PathExists(receiveDir) {
err := os.MkdirAll(receiveDir, 0755)
if err != nil {
log.Printf("Failed to create receive directory: %v", err)
return "", fmt.Errorf("failed to create receive directory")
}
}
// func ReceiveFiles(parts []string) (string, error) {
// fileName := parts[2]
// fileSize, err := strconv.ParseInt(parts[3], 10, 64)
// if err != nil {
// return "", fmt.Errorf("failed to parse file size: %v", err)
// }
// 确定文件路径
filePath := filepath.Join(receiveDir, fileName)
// // 创建接收文件的目录
// baseDir, err := libs.GetOsDir()
// if err != nil {
// log.Printf("Failed to get OS directory: %v", err)
// return "", fmt.Errorf("failed to get OS directory")
// }
// 如果文件不存在,则创建新文件
if _, err := os.Stat(filePath); os.IsNotExist(err) {
file, err := os.Create(filePath)
if err != nil {
log.Printf("Failed to create file: %v", err)
return "", fmt.Errorf("failed to create file")
}
defer file.Close()
}
// resPath := filepath.Join("C", "Users", "Reciv", time.Now().Format("2006-01-02"))
// receiveDir := filepath.Join(baseDir, resPath)
// if !libs.PathExists(receiveDir) {
// err := os.MkdirAll(receiveDir, 0755)
// if err != nil {
// log.Printf("Failed to create receive directory: %v", err)
// return "", fmt.Errorf("failed to create receive directory")
// }
// }
// 锁定文件
lock, ok := fileLocks[fileName]
if !ok {
lock = &sync.Mutex{}
fileLocks[fileName] = lock
}
lock.Lock()
defer lock.Unlock()
// // 确定文件路径
// filePath := filepath.Join(receiveDir, fileName)
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Printf("Failed to open file: %v", err)
return "", fmt.Errorf("failed to open file")
}
defer file.Close()
// // 如果文件不存在,则创建新文件
// if _, err := os.Stat(filePath); os.IsNotExist(err) {
// file, err := os.Create(filePath)
// if err != nil {
// log.Printf("Failed to create file: %v", err)
// return "", fmt.Errorf("failed to create file")
// }
// defer file.Close()
// }
// 提取实际数据
data := strings.Join(parts[4:], "")
if len(data) < 1 {
return "", fmt.Errorf("empty data")
}
// // 锁定文件
// lock, ok := fileLocks[fileName]
// if !ok {
// lock = &sync.Mutex{}
// fileLocks[fileName] = lock
// }
// lock.Lock()
// defer lock.Unlock()
n, err := file.Write([]byte(data))
if err != nil {
log.Printf("Failed to write data to file: %v", err)
return "", fmt.Errorf("failed to write data to file")
}
if n != len(data) {
log.Printf("Incomplete write: wrote %d bytes, expected %d bytes", n, len(data))
return "", fmt.Errorf("incomplete write")
}
// file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
// log.Printf("Failed to open file: %v", err)
// return "", fmt.Errorf("failed to open file")
// }
// defer file.Close()
fileInfo, err := os.Stat(filePath)
if err != nil {
log.Printf("Failed to stat file: %v", err)
return "", fmt.Errorf("failed to stat file")
}
// // 提取实际数据
// data := strings.Join(parts[4:], "")
// if len(data) < 1 {
// return "", fmt.Errorf("empty data")
// }
if fileInfo.Size() == fileSize {
fmt.Println("文件接收完成且大小一致")
return filePath, nil
} else {
fmt.Printf("文件大小不一致,发送大小为%d,接收大小为%d\n", fileSize, fileInfo.Size())
return "", fmt.Errorf("file size mismatch")
}
}
// n, err := file.Write([]byte(data))
// if err != nil {
// log.Printf("Failed to write data to file: %v", err)
// return "", fmt.Errorf("failed to write data to file")
// }
// if n != len(data) {
// log.Printf("Incomplete write: wrote %d bytes, expected %d bytes", n, len(data))
// return "", fmt.Errorf("incomplete write")
// }
// fileInfo, err := os.Stat(filePath)
// if err != nil {
// log.Printf("Failed to stat file: %v", err)
// return "", fmt.Errorf("failed to stat file")
// }
// if fileInfo.Size() == fileSize {
// fmt.Println("文件接收完成且大小一致")
// return filePath, nil
// } else {
// fmt.Printf("文件大小不一致,发送大小为%d,接收大小为%d\n", fileSize, fileInfo.Size())
// return "", fmt.Errorf("file size mismatch")
// }
// }

8
godo/localchat/server.go

@ -117,10 +117,10 @@ func UdpServer() {
// ReceiveFile(udpMsg)
// continue
// }
if udpMsg.Type == "fileAccessed" {
HandlerSendFile(udpMsg)
continue
}
// if udpMsg.Type == "fileAccessed" {
// HandlerSendFile(udpMsg)
// continue
// }
if udpMsg.Type == "image" {
filePath, err := ReceiveImg(udpMsg)
if err != nil {

Loading…
Cancel
Save