Browse Source

change send image

master
godo 9 months ago
parent
commit
42769022ea
  1. 118
      frontend/src/stores/localchat.ts
  2. 56
      godo/localchat/file.go
  3. 184
      godo/localchat/image.go
  4. 2
      godo/localchat/server.go

118
frontend/src/stores/localchat.ts

@ -50,7 +50,7 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
addText(msg) addText(msg)
} }
if (msg.type === "image"){ if (msg.type === "image"){
console.log(msg)
} }
if (msg.type === "fileSending"){ if (msg.type === "fileSending"){
@ -403,123 +403,7 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
await updateContentList(saveMsg) await updateContentList(saveMsg)
} }
//上传文件资源
// async function uploadFile(paths: any) {
// if (chatTargetId.value < 1) {
// return
// }
// const targetUser = userList.value.find((d: any) => d.ip === chatTargetIp.value)
// if (!targetUser.isOnline) {
// notifyError("The user is not online!");
// return;
// }
// if (!hostInfo.value || !hostInfo.value.ip) {
// notifyError("Please wait for a moment");
// return;
// }
// //console.log(paths)
// const formData = new FormData();
// const errstr: any = []
// const files: any = []
// for (let i = 0; i < paths.length; i++) {
// const content = await sys?.fs.readFile(paths[i]);
// let blobContent;
// if (!content || content == '') {
// errstr.push(paths[i] + " is empty")
// continue
// }
// if (content instanceof ArrayBuffer) {
// blobContent = new Blob([content]);
// }
// else if (typeof content === 'string') {
// if (isBase64(content)) {
// const base64 = base64ToBuffer(content);
// blobContent = new Blob([base64]);
// } else {
// blobContent = new Blob([content], { type: "text/plain;charset=utf-8" });
// }
// }
// else {
// errstr.push(paths[i] + " type is error")
// continue
// }
// const fileName = paths[i].split("/").pop()
// files.push({
// name: fileName,
// path: paths[i],
// ext: fileName.split(".").pop(),
// })
// //files.push(blobContent);
// formData.append(`files`, blobContent, fileName);
// }
// if (errstr.length > 0) {
// errstr.forEach((d: any) => {
// notifyError(d);
// })
// return
// }
// //formData.append("files", files);
// formData.append("ip", hostInfo.value.ip);
// formData.append("hostname", hostInfo.value.hostname);
// //console.log(formData)
// const postUrl = `http://${targetUser.ip}:56780/localchat/upload`
// const res = await fetch(postUrl, {
// method: "POST",
// body: formData,
// });
// if (!res.ok) {
// console.log(res);
// notifyError("Upload error!");
// return;
// }
// const saveMsg: any = {
// type: 'file',
// targetId: targetUser.id,
// targetIp: targetUser.ip,
// content: files,
// reciperInfo: toRaw(targetUser),
// createdAt: Date.now(),
// isMe: false,
// isRead: true,
// status: 'reciped'
// }
// //console.log(saveMsg)
// await db.addOne('chatmsg', saveMsg)
// msgList.value.push(saveMsg)
// notifySuccess("upload success!");
// }
//async function addUser(ip: string) {
// if (!isValidIP(ip)) {
// notifyError("请输入正确的IP地址");
// return
// }
// const postUrl = `http://${ip}:56780/localchat/check`
// const completion = await fetch(postUrl)
// if (!completion.ok) {
// notifyError('用户不在线')
// } else {
// const res = await completion.json()
// const data = res.data
// data.createdAt = Date.now()
// data.updatedAt = Date.now()
// data.isOnline = true
// data.username = data.hostname
// if(ip != data.ip){
// notifyError(`IP地址不一致,可能会存在不通的问题`)
// }
// data.ip = ip
// if (!OutUserList.value.some((item: any) => item.ip === data.ip)) {
// OutUserList.value.push(data);
// await getUserList()
// }
// showAddUser.value = false
// }
//}
return { return {
userList, userList,
navList, navList,

56
godo/localchat/file.go

@ -33,6 +33,7 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"sync"
"time" "time"
) )
@ -46,6 +47,7 @@ type FileChunk struct {
Checksum uint32 `json:"checksum"` Checksum uint32 `json:"checksum"`
Timestamp time.Time `json:"timestamp"` Timestamp time.Time `json:"timestamp"`
Filename string `json:"filename"` Filename string `json:"filename"`
Filesize int64 `json:"filesize"`
} }
func HandlerApplySendFile(w http.ResponseWriter, r *http.Request) { func HandlerApplySendFile(w http.ResponseWriter, r *http.Request) {
@ -146,7 +148,7 @@ func handleFile(filePath string, toIp string, message UdpMessage) {
numChunks := (fileSize + fileSize - 1) / fileSize numChunks := (fileSize + fileSize - 1) / fileSize
// 发送文件 // 发送文件
SendFile(file, int(numChunks), toIp, message) SendFile(file, int(numChunks), toIp, fileSize, message)
} }
func handleDirectory(dirPath string, toIp string, message UdpMessage) { func handleDirectory(dirPath string, toIp string, message UdpMessage) {
@ -163,9 +165,16 @@ func handleDirectory(dirPath string, toIp string, message UdpMessage) {
log.Fatalf("Failed to walk directory: %v", err) log.Fatalf("Failed to walk directory: %v", err)
} }
} }
func SendFile(file *os.File, numChunks int, toIp string, message UdpMessage) { func SendFile(file *os.File, numChunks int, toIp string, fSize int64, message UdpMessage) {
var wg sync.WaitGroup
mu := &sync.Mutex{}
// 逐块读取文件并发送 // 逐块读取文件并发送
for i := 0; i < numChunks; i++ { for i := 0; i < numChunks; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
var chunkData [fileSize]byte var chunkData [fileSize]byte
n, err := file.Read(chunkData[:]) n, err := file.Read(chunkData[:])
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
@ -174,13 +183,15 @@ func SendFile(file *os.File, numChunks int, toIp string, message UdpMessage) {
// 创建文件块 // 创建文件块
chunk := FileChunk{ chunk := FileChunk{
ChunkIndex: i, ChunkIndex: index,
Data: chunkData[:n], Data: chunkData[:n],
Checksum: calculateChecksum(chunkData[:n]), Checksum: calculateChecksum(chunkData[:n]),
Timestamp: time.Now(), Timestamp: time.Now(),
Filename: filepath.Base(file.Name()), Filename: filepath.Base(file.Name()),
Filesize: fSize,
} }
message.Message = chunk message.Message = chunk
// 将文件块转换为 JSON 格式 // 将文件块转换为 JSON 格式
data, err := json.Marshal(message) data, err := json.Marshal(message)
if err != nil { if err != nil {
@ -188,7 +199,6 @@ func SendFile(file *os.File, numChunks int, toIp string, message UdpMessage) {
} }
// 发送文件块 // 发送文件块
//addr, err := net.ResolveUDPAddr("udp4", toIp+":56780")
port := "56780" port := "56780"
addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port)) addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port))
if err != nil { if err != nil {
@ -206,32 +216,38 @@ func SendFile(file *os.File, numChunks int, toIp string, message UdpMessage) {
log.Printf("Failed to write data: %v", err) log.Printf("Failed to write data: %v", err)
} }
fmt.Printf("发送文件块 %d 到 %s 成功\n", i, toIp) mu.Lock()
fmt.Printf("发送文件块 %d 到 %s 成功\n", index, toIp)
mu.Unlock()
}(i)
} }
wg.Wait()
} }
func ReceiveFile(msg UdpMessage) { func ReceiveFile(msg UdpMessage) (string, error) {
chunk := msg.Message.(FileChunk) chunk := msg.Message.(FileChunk)
// 验证校验和 // 验证校验和
calculatedChecksum := calculateChecksum(chunk.Data) calculatedChecksum := calculateChecksum(chunk.Data)
if calculatedChecksum != chunk.Checksum { if calculatedChecksum != chunk.Checksum {
fmt.Printf("Checksum mismatch for chunk %d from %s\n", chunk.ChunkIndex, msg.IP) fmt.Printf("Checksum mismatch for chunk %d from %s\n", chunk.ChunkIndex, msg.IP)
return return "", fmt.Errorf("checksum mismatch")
} }
baseDir, err := libs.GetOsDir() baseDir, err := libs.GetOsDir()
if err != nil { if err != nil {
log.Printf("Failed to get OS directory: %v", err) log.Printf("Failed to get OS directory: %v", err)
return return "", fmt.Errorf("failed to get OS directory")
} }
// 创建接收文件的目录 // 创建接收文件的目录
receiveDir := filepath.Join(baseDir, "C", "Users", "Reciv", time.Now().Format("2006-01-02")) resPath := filepath.Join("C", "Users", "Reciv", time.Now().Format("2006-01-02"))
receiveDir := filepath.Join(baseDir, resPath)
if !libs.PathExists(receiveDir) { if !libs.PathExists(receiveDir) {
err := os.MkdirAll(receiveDir, 0755) err := os.MkdirAll(receiveDir, 0755)
if err != nil { if err != nil {
log.Printf("Failed to create receive directory: %v", err) log.Printf("Failed to create receive directory: %v", err)
return return "", fmt.Errorf("failed to create receive directory")
} }
} }
@ -243,7 +259,7 @@ func ReceiveFile(msg UdpMessage) {
file, err := os.Create(filePath) file, err := os.Create(filePath)
if err != nil { if err != nil {
log.Printf("Failed to create file: %v", err) log.Printf("Failed to create file: %v", err)
return return "", fmt.Errorf("failed to create file")
} }
defer file.Close() defer file.Close()
} }
@ -252,7 +268,7 @@ func ReceiveFile(msg UdpMessage) {
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644) file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil { if err != nil {
log.Printf("Failed to open file: %v", err) log.Printf("Failed to open file: %v", err)
return return "", fmt.Errorf("failed to open file")
} }
defer file.Close() defer file.Close()
@ -260,10 +276,20 @@ func ReceiveFile(msg UdpMessage) {
_, err = file.Write(chunk.Data) _, err = file.Write(chunk.Data)
if err != nil { if err != nil {
log.Printf("Failed to write data to file: %v", err) log.Printf("Failed to write data to file: %v", err)
return return "", fmt.Errorf("failed to write data to file")
}
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() == chunk.Filesize {
fmt.Println("文件接收完成且大小一致")
return filePath, nil
} else {
fmt.Println("文件大小不一致")
return "", fmt.Errorf("file size mismatch")
} }
fmt.Printf("接收到文件块 %d 从 %s 成功\n", chunk.ChunkIndex, msg.IP)
} }
func calculateChecksum(data []byte) uint32 { func calculateChecksum(data []byte) uint32 {
checksum := uint32(0) checksum := uint32(0)

184
godo/localchat/image.go

@ -26,11 +26,9 @@ package localchat
import ( import (
"encoding/json" "encoding/json"
"fmt"
"godo/libs" "godo/libs"
"io" "io"
"log" "log"
"net"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -60,10 +58,10 @@ func HandlerSendImg(w http.ResponseWriter, r *http.Request) {
log.Printf("GetOsDir error: %v", err) log.Printf("GetOsDir error: %v", err)
return return
} }
log.Printf("send image to %v", msg.Message) // log.Printf("send image to %v", msg.Message)
log.Printf("Type of msg.Message: %T", msg.Message) // log.Printf("Type of msg.Message: %T", msg.Message)
paths, ok := msg.Message.([]interface{}) paths, ok := msg.Message.([]interface{})
log.Printf("paths: %v", paths) //log.Printf("paths: %v", paths)
if !ok { if !ok {
libs.ErrorMsg(w, "HandleMessage message error") libs.ErrorMsg(w, "HandleMessage message error")
return return
@ -78,7 +76,7 @@ func HandlerSendImg(w http.ResponseWriter, r *http.Request) {
// 处理多张图片 // 处理多张图片
if fileInfo, err := os.Stat(filePath); err == nil { if fileInfo, err := os.Stat(filePath); err == nil {
if !fileInfo.IsDir() { if !fileInfo.IsDir() {
sendImage(filePath, toIp, msg) handleFile(filePath, toIp, msg)
} }
} else { } else {
continue continue
@ -87,121 +85,65 @@ func HandlerSendImg(w http.ResponseWriter, r *http.Request) {
libs.SuccessMsg(w, nil, "图片发送成功") libs.SuccessMsg(w, nil, "图片发送成功")
} }
func sendImage(filePath string, toIp string, message UdpMessage) { // func ReceiveImg(msg UdpMessage) (string, error) {
// 打开文件 // chunk := msg.Message.(FileChunk)
file, err := os.Open(filePath)
if err != nil { // // 验证校验和
log.Fatalf("Failed to open file: %v", err) // calculatedChecksum := calculateChecksum(chunk.Data)
} // if calculatedChecksum != chunk.Checksum {
defer file.Close() // fmt.Printf("Checksum mismatch for image from %s\n", msg.IP)
// return "", fmt.Errorf("checksum mismatch")
// 获取文件大小 // }
fileInfo, err := file.Stat()
if err != nil { // baseDir, err := libs.GetOsDir()
log.Fatalf("Failed to get file info: %v", err) // if err != nil {
} // log.Printf("Failed to get OS directory: %v", err)
fileSize := fileInfo.Size() // return "", err
// }
// 读取整个文件
data := make([]byte, fileSize) // // 创建接收文件的目录
_, err = file.Read(data) // resPath := filepath.Join("C", "Users", "Reciv", time.Now().Format("2006-01-02"))
if err != nil { // receiveDir := filepath.Join(baseDir, resPath)
log.Fatalf("Failed to read file: %v", err) // if !libs.PathExists(receiveDir) {
} // err := os.MkdirAll(receiveDir, 0755)
// if err != nil {
// 创建文件块 // log.Printf("Failed to create receive directory: %v", err)
chunk := FileChunk{ // return "", err
Data: data, // }
Checksum: calculateChecksum(data), // }
Timestamp: time.Now(),
Filename: filepath.Base(file.Name()), // // 确定文件路径
} // filePath := filepath.Join(receiveDir, chunk.Filename)
message.Message = chunk
// 将文件块转换为 JSON 格式 // // 如果文件不存在,则创建新文件
data, err = json.Marshal(message) // if _, err := os.Stat(filePath); os.IsNotExist(err) {
if err != nil { // file, err := os.Create(filePath)
log.Fatalf("Failed to marshal chunk: %v", err) // if err != nil {
} // log.Printf("Failed to create file: %v", err)
// return "", err
// 发送文件块 // }
port := "56780" // defer file.Close()
addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port)) // }
if err != nil {
log.Fatalf("Failed to resolve UDP address: %v", err) // // 打开或追加到现有文件
} // file, err := os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
conn, err := net.DialUDP("udp4", nil, addr) // log.Printf("Failed to open file: %v", err)
if err != nil { // return "", err
log.Fatalf("Failed to dial UDP address: %v", err) // }
} // defer file.Close()
defer conn.Close()
// // 写入数据
_, err = conn.Write(data) // _, err = file.Write(chunk.Data)
if err != nil { // if err != nil {
log.Printf("Failed to write data: %v", err) // log.Printf("Failed to write data to file: %v", err)
} // return "", err
// }
fmt.Printf("发送图片 %s 到 %s 成功\n", filePath, toIp)
} // fmt.Printf("接收到图片 %s 从 %s 成功\n", filePath, msg.IP)
func ReceiveImg(msg UdpMessage) (string, error) { // resFilePath := filepath.Join(resPath, chunk.Filename)
chunk := msg.Message.(FileChunk) // return resFilePath, nil
// }
// 验证校验和
calculatedChecksum := calculateChecksum(chunk.Data)
if calculatedChecksum != chunk.Checksum {
fmt.Printf("Checksum mismatch for image from %s\n", msg.IP)
return "", fmt.Errorf("checksum mismatch")
}
baseDir, err := libs.GetOsDir()
if err != nil {
log.Printf("Failed to get OS directory: %v", err)
return "", err
}
// 创建接收文件的目录
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 "", err
}
}
// 确定文件路径
filePath := filepath.Join(receiveDir, chunk.Filename)
// 如果文件不存在,则创建新文件
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 "", err
}
defer file.Close()
}
// 打开或追加到现有文件
file, err := os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Printf("Failed to open file: %v", err)
return "", err
}
defer file.Close()
// 写入数据
_, err = file.Write(chunk.Data)
if err != nil {
log.Printf("Failed to write data to file: %v", err)
return "", err
}
fmt.Printf("接收到图片 %s 从 %s 成功\n", filePath, msg.IP)
resFilePath := filepath.Join(resPath, chunk.Filename)
return resFilePath, nil
}
func HandleViewImg(w http.ResponseWriter, r *http.Request) { func HandleViewImg(w http.ResponseWriter, r *http.Request) {
img := r.URL.Query().Get("img") img := r.URL.Query().Get("img")
if img == "" { if img == "" {

2
godo/localchat/server.go

@ -118,7 +118,7 @@ func UdpServer() {
continue continue
} }
if udpMsg.Type == "image" { if udpMsg.Type == "image" {
filePath, err := ReceiveImg(udpMsg) filePath, err := ReceiveFile(udpMsg)
if err != nil { if err != nil {
log.Printf("error receiving image: %v", err) log.Printf("error receiving image: %v", err)
continue continue

Loading…
Cancel
Save