diff --git a/frontend/components.d.ts b/frontend/components.d.ts index fd69015..1fe9ff8 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -56,6 +56,7 @@ declare module 'vue' { ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElIcon: typeof import('element-plus/es')['ElIcon'] + ElImage: typeof import('element-plus/es')['ElImage'] ElInput: typeof import('element-plus/es')['ElInput'] ElLink: typeof import('element-plus/es')['ElLink'] ElOption: typeof import('element-plus/es')['ElOption'] diff --git a/frontend/src/components/builtin/FileList.vue b/frontend/src/components/builtin/FileList.vue index db34348..868b598 100644 --- a/frontend/src/components/builtin/FileList.vue +++ b/frontend/src/components/builtin/FileList.vue @@ -77,7 +77,6 @@ import { throttle } from '@/util/debounce'; import { dealSize } from '@/util/file'; import { Menu } from '@/system/menu/Menu'; import { useChooseStore } from "@/stores/choose"; -import { log } from 'console'; const { openPropsWindow, copyFile, createLink, deleteFile } = useContextMenu(); const sys = useSystem(); const { startDrag, folderDrop } = useFileDrag(sys); @@ -124,8 +123,16 @@ function getName(item: any) { } } function handleOnOpen(item: OsFileWithoutContent) { + // props.onOpen(item); + // emitEvent('desktop.app.open'); + chosenIndexs.value = []; + if (choose.ifShow && !item.isDirectory) { + choose.path.push(item.path) + choose.close() + } else { props.onOpen(item); emitEvent('desktop.app.open'); + } } function hadnleDrop(mouse: DragEvent, path: string) { hoverIndex.value = -1; @@ -170,10 +177,10 @@ function onEditNameEnd() { newPath ); props.onRefresh(); - if(newPath.indexOf("Desktop") !== -1){ + if (newPath.indexOf("Desktop") !== -1) { sys.refershAppList() } - + } editIndex.value = -1; } @@ -320,8 +327,16 @@ function handleRightClick(mouse: MouseEvent, item: OsFileWithoutContent, index: menuArr.push({ label: "选中发送", click: () => { - choose.path = item.path - choose.close() + const paths: any = [] + chosenIndexs.value.forEach((index) => { + const item = props.fileList[index]; + paths.push(item.path) + }) + if (paths.length > 0) { + choose.path = paths + choose.close() + } + chosenIndexs.value = []; }, }) } diff --git a/frontend/src/components/computer/Computer.vue b/frontend/src/components/computer/Computer.vue index 6a01902..3957ba2 100644 --- a/frontend/src/components/computer/Computer.vue +++ b/frontend/src/components/computer/Computer.vue @@ -248,7 +248,7 @@ async function onTreeOpen(path: string) { if (file) { openFolder(file); } - console.log(path) + //console.log(path) router_url.value = path; } diff --git a/frontend/src/components/localchat/ChatContent.vue b/frontend/src/components/localchat/ChatContent.vue index dd95573..409db3e 100644 --- a/frontend/src/components/localchat/ChatContent.vue +++ b/frontend/src/components/localchat/ChatContent.vue @@ -6,7 +6,7 @@ import { formatChatTime } from "@/util/common"; // import "vditor/dist/index.css"; import { ElScrollbar } from "element-plus"; import { System } from "@/system"; -const sys:any = inject("system"); +const sys: any = inject("system"); const store = useLocalChatStore(); const messageContainerRef = ref>(); const messageInnerRef = ref(); @@ -20,23 +20,23 @@ const scrollToBottom = () => { // messageContainerRef.value!.setScrollTop( // messageInnerRef.value!.clientHeight // ); - messageContainerRef.value.setScrollTop(messageInnerRef.value!.clientHeight); + messageContainerRef.value.setScrollTop(messageInnerRef.value!.clientHeight); } }); }; watch( () => store.msgList, (_) => { - if(!isScrool){ + if (!isScrool) { scrollToBottom(); } - + }, { deep: true, } ); -function replaceIconTags(text:any) { +function replaceIconTags(text: any) { // 定义正则表达式,匹配 {*任意内容*} 的格式 // console.log(text) // text = Vditor.md2html(text); @@ -44,7 +44,7 @@ function replaceIconTags(text:any) { const regex = /\{\-(.*?)\-\}/g; // 使用正则表达式的replace方法进行替换 - const replacedText = text.replace(regex, (_:any, p1:string) => { + const replacedText = text.replace(regex, (_: any, p1: string) => { // p1 是匹配到的内容部分,这里直接构造图片标签 return ``; //return `![avatar](/image/chat/emoji/${p1}.gif)` @@ -64,29 +64,35 @@ async function scroll({ scrollTop }: { scrollTop: number }) { @@ -115,7 +121,7 @@ $win10-light-grey: #f2f2f2; } .message-area { - + height: 420px; } @@ -132,7 +138,7 @@ $win10-light-grey: #f2f2f2; display: flex; margin-bottom: 10px; align-items: flex-end; // 保持底部对齐 - + flex-direction: row; } @@ -178,61 +184,75 @@ $win10-light-grey: #f2f2f2; .mine { // 添加这一行来确保'mine'类的消息整体靠右 justify-content: flex-end; + .content { // 由于'mine'消息块整体靠右,内容区域不需要特别处理对齐 // justify-content: flex-end; 可以移除,因为它会与外部的justify-content冲突 align-items: flex-end; // 保持底部对齐 } - + .message-content { background-color: $win10-blue; color: $win10-light-blue; border-radius: 12px 2px 2px 2px; // 保持原有样式 } - + .avatar-container { - order: 1; + order: 1; margin-left: 10px; - margin-top:-20px; + margin-top: -20px; } } .theirs { - .content { + .content { // 使对方的消息内容靠左对齐 align-items: flex-end; } + .message-content { border-radius: 2px 12px 2px 2px; } } + .no-message-container { - height: 100%; - margin: 120px auto; - text-align: center; - justify-content: center; + height: 100%; + margin: 120px auto; + text-align: center; + justify-content: center; } + .file-bubble { - background-color: #f0f0f0; /* 背景色,可以根据需要调整 */ - border-radius: 10px; /* 圆角,让框看起来更柔和 */ - padding: 10px; /* 内边距,给内容一些空间 */ - margin-bottom: 10px; /* 气泡间的外边距,使它们看起来不紧凑 */ + background-color: #f0f0f0; + /* 背景色,可以根据需要调整 */ + border-radius: 10px; + /* 圆角,让框看起来更柔和 */ + padding: 10px; + /* 内边距,给内容一些空间 */ + margin-bottom: 10px; + /* 气泡间的外边距,使它们看起来不紧凑 */ max-width: 100%; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 添加阴影效果,增强立体感 */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + /* 添加阴影效果,增强立体感 */ } .file-content { display: flex; align-items: center; - height:36px; - line-height:36px; + height: 36px; + line-height: 36px; gap: 3px; } + .file-content:hover { - background-color: #e0e0e0; /* 改变背景色,悬停时更浅或更深,根据设计调整 */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 增强阴影效果,使气泡在悬停时更加突出 */ - transition: all 0.3s ease; /* 添加过渡效果,使变化平滑 */ + background-color: #e0e0e0; + /* 改变背景色,悬停时更浅或更深,根据设计调整 */ + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + /* 增强阴影效果,使气泡在悬停时更加突出 */ + transition: all 0.3s ease; + /* 添加过渡效果,使变化平滑 */ } + .file-icon { width: 18px; height: 18px; diff --git a/frontend/src/components/localchat/ChatEditor.vue b/frontend/src/components/localchat/ChatEditor.vue index 58aa9b0..3d3d4f7 100644 --- a/frontend/src/components/localchat/ChatEditor.vue +++ b/frontend/src/components/localchat/ChatEditor.vue @@ -12,7 +12,7 @@ @keydown.enter="keyDown($event)" v-model="store.sendInfo" /> - + @@ -22,17 +22,18 @@ diff --git a/frontend/src/components/localchat/ChatFoot.vue b/frontend/src/components/localchat/ChatFoot.vue index 735983c..d912a66 100644 --- a/frontend/src/components/localchat/ChatFoot.vue +++ b/frontend/src/components/localchat/ChatFoot.vue @@ -64,16 +64,18 @@ const store = useLocalChatStore(); const choose = useChooseStore(); //const editor = ref(null) const imgExt = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg"]; - +const choosetype = ref('image') // 选择表情 function selectIcon(icon: string) { store.sendInfo += "{-" + icon.replace("/image/chat/emoji/", "").replace(".gif", "") + "-}"; } function selectImg() { + choosetype.value = 'image' choose.select("选择图片", imgExt); } function selectFile() { + choosetype.value = 'applyfile' choose.select("选择文件", "*"); } watch( @@ -82,12 +84,10 @@ watch( //console.log("userList 变化了:", newVal); const paths = toRaw(newVal) if(paths.length > 0){ - store.uploadFile(paths).then(() => { - choose.path = [] - }) + store.sendInfo = paths; + choose.path = [] + store.sendMsg(choosetype.value) } - - }, { deep: true } // 添加deep: true以深度监听数组或对象内部的变化 ); diff --git a/frontend/src/stores/choose.ts b/frontend/src/stores/choose.ts index 44d0a19..81284ad 100644 --- a/frontend/src/stores/choose.ts +++ b/frontend/src/stores/choose.ts @@ -3,7 +3,7 @@ import { BrowserWindow } from "@/system"; import { ref } from 'vue'; export const useChooseStore = defineStore('chooseStore', () => { const win:any = ref() - const path:any = ref("") + const path:any = ref([]) const ifShow = ref(false) const select = (title = '选择文件', fileExt:any) => { win.value = new BrowserWindow({ diff --git a/frontend/src/stores/localchat.ts b/frontend/src/stores/localchat.ts index dac373d..5956d3e 100644 --- a/frontend/src/stores/localchat.ts +++ b/frontend/src/stores/localchat.ts @@ -4,16 +4,15 @@ import { ref, toRaw, inject } from "vue"; import { db } from './db' import { System } from "@/system"; import { getSystemConfig } from "@/system/config"; -import { isBase64, base64ToBuffer } from "@/util/file"; import { isValidIP } from "@/util/common"; import { notifyError, notifySuccess } from "@/util/msg"; export const useLocalChatStore = defineStore('localChatStore', () => { const config = getSystemConfig(); - const sys = inject("system"); + //const sys = inject("system"); const userList: any = ref([]) const msgList: any = ref([]) const contentList: any = ref([]) - const OutUserList: any = ref([]) + //const OutUserList: any = ref([]) const hostInfo: any = ref({}) const showChooseFile = ref(false) const currentPage = ref(1) @@ -23,7 +22,7 @@ export const useLocalChatStore = defineStore('localChatStore', () => { { index: 2, lable: "用户列表", icon: "UserFilled", type: "info" }, ]) const navId = ref(1) - const sendInfo = ref("") + const sendInfo:any = ref() const chatTargetId = ref(0) const chatTargetIp = ref("") const showAddUser = ref(false) @@ -49,6 +48,9 @@ export const useLocalChatStore = defineStore('localChatStore', () => { msg.message = msg.message.replaceAll("\\n", "\n") //console.log(msg) addText(msg) + } + if (msg.type === "image"){ + } if (msg.type === "fileSending"){ @@ -192,8 +194,8 @@ export const useLocalChatStore = defineStore('localChatStore', () => { } } const getUserList = async () => { - const listAll = await db.getAll('chatuser') - const list = [...listAll, ...OutUserList.value] + const list = await db.getAll('chatuser') + //const list = [...listAll, ...OutUserList.value] let uniqueIpMap = new Map(); // 遍历 list 并添加 IP 地址到 Map 中 @@ -338,168 +340,186 @@ export const useLocalChatStore = defineStore('localChatStore', () => { await updateContentList(saveMsg) handleSelect(1) } - const sendMsg = async () => { + const sendMsg = async (type:string) => { if (chatTargetId.value < 1) { return } + const content = toRaw(sendInfo.value) + let saves:any + if (type === 'image') { + const apiUrl = `${config.apiUrl}/localchat/viewimage?img=` + saves = content.map((d: any) => `${apiUrl}${encodeURIComponent(d)}`) + }else{ + saves = content + } const saveMsg: any = { - type: 'text', + type: type, targetId: chatTargetId.value, targetIp: chatTargetIp.value, - content: sendInfo.value.trim(), + content: saves, createdAt: Date.now(), isMe: true, isRead: false, status: 'sending' } - //console.log(saveMsg) const msgId = await db.addOne('chatmsg', saveMsg) //await getMsgList() msgList.value.push(saveMsg) const targetUser = userList.value.find((d: any) => d.ip === chatTargetIp.value) //console.log(targetUser) if (targetUser.isOnline) { - const postUrl = `${config.apiUrl}/localchat/message` + let postUrl = `${config.apiUrl}/localchat/message` + if(type === 'applyfile'){ + postUrl = `${config.apiUrl}/localchat/applyfile` + } + if(type === 'image'){ + postUrl = `${config.apiUrl}/localchat/sendimage` + } const messages = { - type: 'text', - message: saveMsg.content, + type: type, + message: content, ip: saveMsg.targetIp } const completion = await fetch(postUrl, { method: "POST", body: JSON.stringify(messages), }) + //console.log(completion) if (!completion.ok) { console.log(completion) + notifyError("发送失败!") } else { saveMsg.isRead = true saveMsg.status = 'sended' saveMsg.readAt = Date.now() await db.update('chatmsg', msgId, saveMsg) + if(type === 'applyfile'){ + notifySuccess("发送成功!") + } } } sendInfo.value = "" 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) + // 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!"); - } + // 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 + //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 { userList, navList, @@ -514,7 +534,7 @@ export const useLocalChatStore = defineStore('localChatStore', () => { showChooseFile, pageSize, showAddUser, - OutUserList, + //OutUserList, init, setUserList, getUserList, @@ -523,23 +543,11 @@ export const useLocalChatStore = defineStore('localChatStore', () => { sendMsg, addText, addFile, - uploadFile, + //uploadFile, moreMsgList, refreshUserList, clearMsg, - addUser, + //addUser, handlerMessage } -}, { - persist: { - enabled: true, - strategies: [ - { - storage: localStorage, - paths: [ - "OutUserList" - ] - }, // name 字段用localstorage存储 - ], - } }) diff --git a/godo/cmd/main.go b/godo/cmd/main.go index e3a97bc..3110258 100644 --- a/godo/cmd/main.go +++ b/godo/cmd/main.go @@ -106,7 +106,7 @@ func OsStart() { localchatRouter.HandleFunc("/applyfile", localchat.HandlerApplySendFile).Methods(http.MethodPost) localchatRouter.HandleFunc("/accessfile", localchat.HandlerAccessFile).Methods(http.MethodPost) localchatRouter.HandleFunc("/sendimage", localchat.HandlerSendImg).Methods(http.MethodPost) - localchatRouter.HandleFunc("/viewimage", localchat.HandleViewImg).Methods(http.MethodPost) + localchatRouter.HandleFunc("/viewimage", localchat.HandleViewImg).Methods(http.MethodGet) localchatRouter.HandleFunc("/setting", localchat.HandleAddr).Methods(http.MethodPost) localchatRouter.HandleFunc("/getsetting", localchat.HandleGetAddr).Methods(http.MethodGet) // 注册 WebDAV 路由 diff --git a/godo/localchat/addr.go b/godo/localchat/addr.go index 2536e78..9824680 100644 --- a/godo/localchat/addr.go +++ b/godo/localchat/addr.go @@ -22,29 +22,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// MIT License -// -// Copyright (c) 2024 godoos.com -// Email: xpbb@qq.com -// GitHub: github.com/phpk/godoos -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. package localchat import ( diff --git a/godo/localchat/check.go b/godo/localchat/check.go index eb7d1f6..eede7b9 100644 --- a/godo/localchat/check.go +++ b/godo/localchat/check.go @@ -22,29 +22,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// MIT License -// -// Copyright (c) 2024 godoos.com -// Email: xpbb@qq.com -// GitHub: github.com/phpk/godoos -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. package localchat import ( diff --git a/godo/localchat/image.go b/godo/localchat/image.go index 20804eb..a7396e6 100644 --- a/godo/localchat/image.go +++ b/godo/localchat/image.go @@ -25,15 +25,14 @@ package localchat import ( - "bytes" "encoding/json" "fmt" "godo/libs" - "image" "io" "log" "net" "net/http" + "net/url" "os" "path/filepath" "time" @@ -61,21 +60,25 @@ func HandlerSendImg(w http.ResponseWriter, r *http.Request) { log.Printf("GetOsDir error: %v", err) return } - paths, ok := msg.Message.([]string) + log.Printf("send image to %v", msg.Message) + log.Printf("Type of msg.Message: %T", msg.Message) + paths, ok := msg.Message.([]interface{}) + log.Printf("paths: %v", paths) if !ok { - log.Printf("invalid message type") + libs.ErrorMsg(w, "HandleMessage message error") return } - for _, p := range paths { + + for _, v := range paths { + p, ok := v.(string) + if !ok { + continue + } filePath := filepath.Join(basePath, p) // 处理多张图片 if fileInfo, err := os.Stat(filePath); err == nil { if !fileInfo.IsDir() { - if isImage(filePath) { // 检查是否为图片 - sendImage(filePath, toIp, msg) - } else { - log.Printf("文件 %s 不是图片", filePath) - } + sendImage(filePath, toIp, msg) } } else { continue @@ -83,14 +86,7 @@ func HandlerSendImg(w http.ResponseWriter, r *http.Request) { } libs.SuccessMsg(w, nil, "图片发送成功") } -func isImage(filePath string) bool { - data, err := os.ReadFile(filePath) - if err != nil { - return false - } - img, _, err := image.DecodeConfig(bytes.NewReader(data)) - return err == nil && img.Width > 0 && img.Height > 0 -} + func sendImage(filePath string, toIp string, message UdpMessage) { // 打开文件 file, err := os.Open(filePath) @@ -212,15 +208,20 @@ func HandleViewImg(w http.ResponseWriter, r *http.Request) { libs.ErrorMsg(w, "img is empty") return } + decodedImgParam, err := url.QueryUnescape(img) + if err != nil { + log.Fatalf("Error unescaping image parameter: %v", err) + } basePath, err := libs.GetOsDir() if err != nil { log.Printf("GetOsDir error: %v", err) return } - filePath := filepath.Join(basePath, img) + filePath := filepath.Join(basePath, decodedImgParam) + log.Printf("filePath: %s", filePath) // 检查文件是否存在 if _, err := os.Stat(filePath); os.IsNotExist(err) { - http.NotFound(w, r) + libs.ErrorMsg(w, "file not found") return } diff --git a/godo/webdav/auth.go b/godo/webdav/auth.go index 66a1cb7..01081a5 100644 --- a/godo/webdav/auth.go +++ b/godo/webdav/auth.go @@ -47,35 +47,6 @@ type Authorizer interface { AddAuthenticator(key string, fn AuthFactory) } -// An Authenticator implements a specific way to authorize requests. -// Each request is bound to a separate Authenticator instance. -// -// The authentication flow itself is broken down into `Authorize` -// and `Verify` steps. The former method runs before, and the latter -// runs after the `Request` is submitted. -// This makes it easy to encapsulate and control complex -// authentication challenges. -// -// Some authentication flows causing authentication round trips, -// which can be archived by returning the `redo` of the Verify -// method. `True` restarts the authentication process for the -// current action: A new `Request` is spawned, which must be -// authorized, sent, and re-verified again, until the action -// is successfully submitted. -// The preferred way is to handle the authentication ping-pong -// within `Verify`, and then `redo` with fresh credentials. -// -// The result of the `Verify` method can also trigger an -// `Authenticator` change by returning the `ErrAuthChanged` -// as an error. Depending on the `Authorizer` this may trigger -// an `Authenticator` negotiation. -// -// Set the `XInhibitRedirect` header to '1' in the `Authorize` -// method to get control over request redirection. -// Attention! You must handle the incoming request yourself. -// -// To store a shared session state the `Clone` method **must** -// return a new instance, initialized with the shared state. type Authenticator interface { // Authorizes a request. Usually by adding some authorization headers. Authorize(c *http.Client, rq *http.Request, path string) error