|
- /**
- * 模拟客户端back server
- * 目前还不知道back的API及具体实现,暂时先抑制代码报错
- */
- import { fetchApi, wrapErrorHint } from '@/utils/request';
- import { notify, firstCharToUpperCase } from '@/utils/tool';
- import { identity } from 'lodash';
- import Vue from 'vue';
-
- export const isClient = !!global.electron; // process.env.IS_CLIENT;
-
- const MAX_UPLOAD_ENQUEUE = 5;
- const MAX_DOWNLOAD_ENQUEUE = 5;
- let uploadingQueue = [];
- let uploadQueue = [];
- let downloadingQueue = [];
- let downloadQueue = [];
-
- const clearTaskQueue = () => {
- uploadingQueue = [];
- uploadQueue = [];
- downloadingQueue = [];
- downloadQueue = [];
- }
-
- let socket;
- const noop = () => {};
-
- const io = (path) => {
- const sk = new WebSocket(`ws://127.0.0.1:7777/${path}`);
- sk.on = sk.addEventListener;
- return sk;
- }
-
- const requestBySocket = (socketIns, message) => new Promise((resolve, reject) => {
- socketIns.on('open', () => { socketIns.send(message); });
- socketIns.on('message', e => {resolve(e);socketIns.close();});
- socketIns.on('error', e => reject(e));
- });
-
-
- const safeCall = f => isClient ? f : noop;
- const safeSocket = f => (...args) => socket && f(...args);
-
- const system = {
- isClient,
- init: safeCall(() => {
- console.log('客户端 electron API 检测:', global.electron);
- }),
- // initialSocket: () => {
- // socket = io('ws://10.240.5.17:8000');
- // // socket = io('ws://127.0.0.1:3000');
- // debugger;
- // socket.on('connect', () => { console.log('本地socket服务连接成功') });
- // },
- /**
- * todo
- * 通知登录
- */
- login: () => {
-
- },
- /**
- * todo
- * 通知登出
- */
- logout: () => {
-
- },
- /**
- * 通知系统进入当前的工作空间
- */
- entryProject: safeCall((projName, userId, fileChangeHandler, initHandler, errorHandler = identity) => {
- requestBySocket(io('init'), [userId, projName].join('|'))
- .then(response => initHandler(response.data));
- const watchSocket = io('subscriptionFileChange');
- watchSocket.on('open', () => {
- watchSocket.send(projName);
- });
- watchSocket.on('message', fileChangeHandler);
- watchSocket.on('error', errorHandler);
- return watchSocket;
- }),
- /**
- * todo
- * 离开工作空间时注销socket
- */
- leaveProject: safeCall((watchSocket) => {
- watchSocket.close();
- clearTaskQueue();
- }),
- /**
- * 下载文件到工作空间
- */
- downloadFile: safeCall((fileIpfsId, projectName, fileName, dirName, onProcessHandler, onErrorHandler = identity) => {
-
- const downloadTask = () => {
- const socket = io('download');
- socket.on('open', () => {
- socket.send([fileIpfsId, projectName, fileName, dirName].join('|'));
- });
- socket.on('message', (e) => {
- if(e.data === '-1') {
- //notify.error('文件下载失败,请检查网络。');
- this.$notify({
- message:`${fileName},网络请求失败。`,
- type:['warning','download'],
- title:"文件下载失败"
- })
- onErrorHandler(e);
- return;
- }
- if(e.data === '-2') {
- notify.error('请先关闭本地文件后再下载');
- onErrorHandler(e);
- return;
- }
- onProcessHandler(e, socket);
- });
- socket.on('error', e => {
- onErrorHandler(e);
- });
-
- socket.on('close', () => {
- downloadingQueue = downloadingQueue.filter(iTask => iTask !== downloadTask);
- if(downloadQueue.length) {
- const nextTask = downloadQueue.shift();
- downloadingQueue.push(nextTask);
- nextTask();
- }
- })
- }
-
- if(downloadingQueue.length >= MAX_DOWNLOAD_ENQUEUE) {
- downloadQueue.push(downloadTask);
- } else {
- downloadingQueue.push(downloadTask);
- downloadTask();
- }
-
- }),
- // 解析文件/文件夹路径信息
- // {
- // name: '11-28会议纪要.docx',
- // extension:".docx",
- // relativePath:"协同项目\\分析\\11-28会议纪要.docx",
- // absolutePath:"C:\\Users\\yuan_rh\\easycloud\\332174685636661248\\协同项目\\分析\\11-28会议纪要.docx"
- // }
- analyzeSystemPath: safeCall(async (systemFullpath) => {
- const response = await requestBySocket(io('getFolderFileInfo'), systemFullpath);
- try {
- const obj = JSON.parse(response.data);
- const uploadTasks = Object.values(obj).map((data) => {
- const { name: extensionedFileName, extension: dotExtension, relativePath, absolutePath } = data;
- const extension = dotExtension.indexOf('.') === 0 ? dotExtension.slice(1) : dotExtension;
- const fileName = extensionedFileName.slice(0, -dotExtension.length);
- return {
- fileName,
- extension,
- relativePath: relativePath.split('\\').filter(identity).join('/'),
- fullPath: absolutePath,
- };
- });
- return uploadTasks;
- } catch(e) {
- return [];
- }
- }),
- // 选择文件
- chooseFiles: safeCall(async () => {
- const { ipcRenderer } = global.electron;
- const res = await ipcRenderer.invoke('project-choose-files');
- const { canceled, filePaths } = res;
- if(canceled) return null;
- return filePaths;
- }),
- // 选择文件
- chooseFolders: safeCall(async () => {
- const { ipcRenderer } = global.electron;
- const res = await ipcRenderer.invoke('project-choose-folders');
- const { canceled, filePaths } = res;
- if(canceled) return null;
- return filePaths;
- }),
- /**
- * 上传文件到工作空间
- * 程序步骤:
- * + 用户选择本地文件/文件夹
- * + 文件上传至本地ipfs节点
- * + 将文件的ipfsCid连同文件信息发送到远端服务器
- * @param {params.projectId} 项目Id
- * @param {params.projectName} 项目名称
- * @param {params.folderId} 节点文件夹Id
- * @param {params.folderName} 节点文件夹Id
- * @param {params.folderLevelId} 节点文件夹levelId
- * @param {params.distFileRelativePath} 节点文件夹下的相对路径, 直接在节点文件夹下则为空, 用正斜杠
- * @param {params.sourceFilePath} 上传文件的完整路径
- * @param {params.fileName} 上传文件名
- * @param {params.fileExtension} 上传文件名
- * @param {params.fileList} 用于对比文件名是否重复的文件队列
- * @param {params.onSuccessHandler} 完成上传时的回调
- * @param {params.onProgressHandler} 上传进度反馈的回调
- * @param {params.onErrorHandler} 上传失败的回调
- */
- uploadFile: safeCall(async (params) => {
- const {
- projectId, projectName,
- folderId, folderName, folderLevelId, distFileRelativePath = '',
- fileName, fileExtension, sourceFilePath,
- fileList, onSuccess: onSuccessHandler, onProgress: onProgressHandler = identity, onError: onErrorHandler = identity,
- totalReadyUploadNum
- } = params;
- let {tempNumWrap} = params;//已经完成的上传文件上传数量
-
- const extensionedFileName = fileExtension ? `${fileName}.${fileExtension}`: fileName;
- const distFilePath = `${folderName}${distFileRelativePath ? `/${distFileRelativePath}`: ''}`;
- const maybeFile = fileList.find(iFile => distFileRelativePath === iFile.relativePath && `${iFile.archName}${iFile.extension ? `.${iFile.extension}` : ''}` === extensionedFileName);
- // 检测当前工作目录中是否存在同名文件
- // 考虑到需要批量的环境使用,把这块的逻辑移到页面去实现
- // if(maybeFile) {
- // let confirmRes = false;
- // try {
- // await Vue.prototype.$confirm('监测到文件夹存在同名文件,是否继续上传并覆盖同名文件?');
- // confirmRes = true;
- // } catch(e) { console.log('user canceled'); }
- // if(!confirmRes) return;
- // }
-
- const uploadFile = maybeFile
- ? firstCharToUpperCase({ ...maybeFile, ModifyUserId: sessionStorage.userId })
- : {
- // 文件名称 不带扩展名
- ArchName: fileName,
- // CommonStatus: 0,
- // CreateTime: "string",
- // 文件上传者Id
- CreateUserId: sessionStorage.userId,
- // Deleted: 0,
- Extension: fileExtension,
- // 文件大小 单位?
- // FileSize: +size,
- // 所处文件夹id
- FolderId: folderId,
- // 所处文件夹层级,拼接符:_
- FolderLevelId: folderLevelId,
- Id: `upload:${`${Math.random()}`.slice(2, 8)}`,
- // IpfsCid: hash,
- // IsShowRecycle: 0,
- // Milestone: 0,
- // ModifyTime: "string",
- // ModifyUserId: 0,
- // 项目id
- ProjId: projectId,
- RelativePath: distFileRelativePath,
- // ShowUrl: "string",
- Status: 2,
- Version: 1,
- // WorkStatus: 0
- };
-
- // 预写一条上传信息给页面
- onProgressHandler({ process: 0 }, uploadFile);
-
- const uploadTask = () => {
- const resolveError = (...args) => {
- uploadingQueue = uploadingQueue.filter(iTask => iTask !== uploadTask);
- if(uploadQueue.length) {
- const nextTask = uploadQueue.shift();
- uploadingQueue.push(nextTask);
- nextTask();
- }
- onErrorHandler(...args);
- }
- const resolveSuccess = (...args) => {
- uploadingQueue = uploadingQueue.filter(iTask => iTask !== uploadTask);
- if(uploadQueue.length) {
- const nextTask = uploadQueue.shift();
- uploadingQueue.push(nextTask);
- nextTask();
- }
- onSuccessHandler(...args);
- }
- const socket = io('upload');
- socket.on('open', () => {
- const data = [sourceFilePath, extensionedFileName, projectName, distFilePath.replace(/\//g, '\\')].join('|');
- socket.send(data);
- onProgressHandler({ process: 0 }, uploadFile);
- });
-
- socket.on('message', async (e) => {
- // console.log('receive download file message:', e);
- if(e.data === '-1') {
- notify.error('文件上传失败');
- resolveError(e, uploadFile);
- return;
- }
- if(e.data === '-2') {
- notify.error('请先关闭本地文件后再上传');
- resolveError(e, uploadFile);
- return;
- }
- try {
- const progressData = JSON.parse(e.data);
- const { size, process, hash } = progressData;
- onProgressHandler(progressData, uploadFile);
- if(process !== 100 || !hash) return;
- socket.close();
- // {"size":"88.69","currentSize":"88.69","unit":"KiB","process":100,"hash":""}
- // {"size":"","currentSize":"","unit":"","process":100,"hash":"QmPJ9i4z5UdoQpLH1DrkhZiTZra2rGicXiPabiLw4LvTmX"}
- uploadFile.FileSize = +size;
- uploadFile.IpfsCid = hash;
- const copyUploadFile = { ...uploadFile };
- if(!maybeFile) {
- delete copyUploadFile.Id;
- }
- const res = await fetchApi(`file/${maybeFile ? 'updateFile' : 'addFile'}`, copyUploadFile);
- wrapErrorHint(res);
- if(res.Code !== 0) {
- resolveError(res, uploadFile);
- return;
- }
- //notify.success(maybeFile ? '上传成功, 已覆盖同名文件' : '上传成功');
- tempNumWrap.tempNumCount += 1;
- // console.log('tempNumCount', tempNumWrap.tempNumCount);
- // console.log('totalReadyUploadNum', totalReadyUploadNum);
- if(tempNumWrap.tempNumCount == totalReadyUploadNum) {
- Vue.prototype.$notify({
- type:["success","upload"],
- title:"文件上传成功",
- message:`${uploadFile.ArchName}`
- })
- }
- resolveSuccess(uploadFile);
- } catch (e) {
- console.error('socket-upload-file parse data have error:', e);
- resolveError(e, uploadFile);
- }
- });
- socket.on('error', e => {
- resolveError(e, uploadFile);
- });
- }
-
- // 处理任务单元
- if(uploadingQueue.length >= MAX_UPLOAD_ENQUEUE) {
- uploadQueue.push(uploadTask);
- } else {
- uploadingQueue.push(uploadTask);
- uploadTask();
- }
- }),
- /**
- * 上传文件到工作空间
- * 程序步骤:
- * + 用户选择本地文件/文件夹
- * + 文件上传至本地ipfs节点
- * + 将文件的ipfsCid连同文件信息发送到远端服务器
- */
- // uploadFileOld: safeCall(async (projectId, projectName, folderId, folderName, levelId, fileList, onSuccessHandler, onProgressHandler = identity, onErrorHandler = identity) => {
- // const { ipcRenderer } = global.electron;
- // const res = await ipcRenderer.invoke('project-upload-file');
- // console.log('ipcRenderer project-selected-upload-file: ', res);
- // const { canceled, filePaths } = res;
- // if(canceled) return;
- // const filePath = filePaths[0];
- // const extensionedFileName = filePath.split(/\/|\\/g).pop();
-
- // const tempFilePaths = extensionedFileName.split('.');
- // const extension = tempFilePaths.length > 1 ? tempFilePaths.pop() : '';
- // const fileName = tempFilePaths.join('.');
-
- // const maybeFile = fileList.find(iFile => `${iFile.archName}${iFile.extension ? `.${iFile.extension}` : ''}` === extensionedFileName);
- // // 检测当前工作目录中是否存在同名文件
- // if(maybeFile) {
- // let confirmRes = false;
- // try {
- // await Vue.prototype.$confirm('监测到文件夹存在同名文件,是否继续上传并覆盖同名文件?');
- // confirmRes = true;
- // } catch(e) { console.log('user canceled'); }
- // if(!confirmRes) return;
- // }
-
- // const uploadFile = maybeFile
- // ? firstCharToUpperCase({ ...maybeFile, ModifyUserId: sessionStorage.userId })
- // : {
- // // 文件名称 不带扩展名
- // ArchName: fileName,
- // // CommonStatus: 0,
- // // CreateTime: "string",
- // // 文件上传者Id
- // CreateUserId: sessionStorage.userId,
- // // Deleted: 0,
- // Extension: extension,
- // // 文件大小 单位?
- // // FileSize: +size,
- // // 所处文件夹id
- // FolderId: folderId,
- // // 所处文件夹层级,拼接符:_
- // FolderLevelId: levelId,
- // Id: `upload:${`${Math.random()}`.slice(2, 8)}`,
- // // IpfsCid: hash,
- // // IsShowRecycle: 0,
- // // Milestone: 0,
- // // ModifyTime: "string",
- // // ModifyUserId: 0,
- // // 项目id
- // ProjId: projectId,
- // // ShowUrl: "string",
- // Status: 2,
- // Version: 1,
- // // WorkStatus: 0
- // };
-
- // const socket = io('upload');
- // socket.on('open', () => {
- // const data = [filePath, extensionedFileName, projectName, folderName].join('|');
- // socket.send(data);
- // onProgressHandler({ process: 0 }, uploadFile);
- // });
-
- // socket.on('message', async (e) => {
- // console.log('receive download file message:', e);
- // if(e.data === '-1') {
- // notify.error('文件上传失败,请检查网络。');
- // onErrorHandler(e, uploadFile);
- // return;
- // }
- // if(e.data === '-2') {
- // notify.error('请先关闭本地文件后再上传');
- // onErrorHandler(e, uploadFile);
- // return;
- // }
- // try {
- // const progressData = JSON.parse(e.data);
- // const { size, process, hash } = progressData;
- // onProgressHandler(progressData, uploadFile);
- // if(process !== 100 || !hash) return;
- // socket.close();
- // // {"size":"88.69","currentSize":"88.69","unit":"KiB","process":100,"hash":""}
- // // {"size":"","currentSize":"","unit":"","process":100,"hash":"QmPJ9i4z5UdoQpLH1DrkhZiTZra2rGicXiPabiLw4LvTmX"}
- // // const maybeFile = fileList.find(iFile => `${iFile.archName}${iFile.extension ? `.${iFile.extension}` : ''}` === extensionedFileName);
- // uploadFile.FileSize = +size;
- // uploadFile.IpfsCid = hash;
- // if(!maybeFile) {
- // delete uploadFile.Id;
- // }
- // const res = await fetchApi(`file/${maybeFile ? 'updateFile' : 'addFile'}`, uploadFile);
- // wrapErrorHint(res);
- // if(res.Code !== 0) return;
- // //notify.success(maybeFile ? '上传成功, 已覆盖同名文件' : '上传成功');
- // notify.success('文件已上传。')
- // onSuccessHandler(uploadFile);
- // } catch (e) {
- // console.error('socket-upload-file parse data have error:', e);
- // onErrorHandler(e, uploadFile);
- // }
- // });
- // socket.on('error', e => {
- // onErrorHandler(e, uploadFile);
- // });
- // }),
- /**
- * 更新本地文件
- */
- updateFile: safeCall((file, localFilePathPrefix, projectName, relativePath, onSuccessHandler, onProgressHandler = identity, onErrorHandler = identity) => {
- const socket = io('upload');
- const { archName, extension, id: fileId } = file;
- const extensionedFileName = `${archName}${extension ? `.${extension}` : ''}`;
- const filePath = `${localFilePathPrefix}\\${relativePath}\\${extensionedFileName}`;
- socket.on('open', () => {
- const data = [filePath, extensionedFileName, projectName, relativePath].join('|');
- socket.send(data);
- });
- socket.on('message', async (e) => {
- if(e.data === '-1') {
- notify.error('文件上传失败');
- onErrorHandler(e);
- return;
- }
- if(e.data === '-2') {
- notify.error('请先关闭本地文件后再上传');
- onErrorHandler(e);
- return;
- }
- try {
- const progressData = JSON.parse(e.data);
- const { size, process, hash } = progressData;
- onProgressHandler(progressData);
- if(process !== 100 || !hash) return;
- socket.close();
- const copyFile = firstCharToUpperCase({ ...file, ipfsCid: hash, size: +size, ModifyUserId: sessionStorage.userId });
-
- const res = await fetchApi('file/updateFile', copyFile);
- wrapErrorHint(res);
- // if(res.Code === 0) { notify.success(`${archName} 更新成功`); }
- onSuccessHandler(copyFile);
- return;
- } catch(err) {
- console.error('socket-update-file parse data have error:', e);
- // todo 上传失败
- }
- });
- socket.on('error', e => {
- onErrorHandler(e, file);
- });
- }),
- /**
- * 系统打开文件
- */
- openFile: safeCall((filePath) => {
- const { shell } = global.electron;
- shell.openPath(filePath);
- }),
- /**
- * 系统打开文件目录
- */
- openFolder: safeCall((filePath) => {
- const { shell } = global.electron;
- shell.showItemInFolder(filePath);
- }),
- }
-
- export default system;
|