core
core copied to clipboard
[FEATURE] Implementation of cross-end and cross-window file system service
Note A sub module for OSPP 2022 proposal.
Issues
Related discussions: https://github.com/opensumi/core/discussions/1086
Now on the OpenSumi we can't use this function while copying or dragging some files from one window to the other window.
描述预期的功能表现(Describe the solution)
增强跨窗口文件交互能力。包括
- web 单容器跨窗口文件复制支持
- electron 跨窗口文件复制支持
- web 和 electron 跨窗口文件拖拽支持
- 和 native 文件交互增强
描述替代方案(Describe alternatives)
web
对于 paste 操作,修改 fileTreeModelService.pasteFile,额外增加读取 localStorage.setItem 获得 uri string 同时校验后反序列得到 Uri 实例
https://github.com/opensumi/core/blob/5e8c4c14b54b54fa98b22c18c293f1c071da9a9e/packages/file-tree-next/src/browser/services/file-tree-model.service.ts#L1572-L1634
对于 copy 操作,通过 localStorage.getItem 增加 uri.toString()
https://github.com/opensumi/core/blob/5e8c4c14b54b54fa98b22c18c293f1c071da9a9e/packages/file-tree-next/src/browser/services/file-tree-model.service.ts#L1547-L1570
考虑对于 localStorage 抽离出 core-browser/src/service 中的 ILocalStorageService,接口配置类似 StorageService(只能存储在 session 中)
对于 drag 操作,当前 handleDrop 通过 beingDraggedActiveUri 来维护内部状态
https://github.com/opensumi/core/blob/ed336f234610e69a505634857fccaf61739a8ad8/packages/file-tree-next/src/browser/services/file-tree-dnd.service.ts#L216-L235
对于当前无 active 的情况,则从 ev.dataTransfer 中读取 uri 进行校验并解析实例,以支持跨窗口拖拽
electron
对于 copy 操作 和 drag 操作,基本改动逻辑相同,使用 electron/Clipboard 实现 set/get uri 操作
考虑改造当前 ClipboardService,实现了 writeText 和 readText。将原先耦合存储于 file-tree-service 中的 _pasteStore 抽离为 ClipboardService 中的 writeResource、readResource 操作,web 侧依然使用 LocalStorageService,node 侧使用 electron/Clipboard
对于 drag 操作,web 侧改动应该同样适用
native
参考 vscode 相关 issue https://github.com/microsoft/vscode/issues/164 可以拆分为几个部分
- 从 OpenSumi 中复制文件/文件夹到 native file explorer
- 从 native file explorer 中复制文件到 OpenSumi
- ~~从 native file explorer 中拖拽文件到 OpenSumi~~ (当前已支持)
- 从 OpenSumi 中拖拽文件到 native file explorer
目前比较明确可以实现的是第二点,通过 e.clipboardData.files 来获取,需要 chromium 91 及以后
https://chromestatus.com/feature/5671807392677888
Roadmap
- [x] web 复制能力改造
- [ ] electron 复制能力改造
- [x] web 拖拽能力改造
- [ ] electron 拖拽能力改造
- [ ] native 实现性改造
Related pull request: TODO
Changelog
2022.06.30First commit
Self-assigned, /cc @erha19
待讨论的问题
- [x] 对于 cut 操作,跨窗口难以维护状态响应,是将 cut 降级为 copy 还是采用 postMessage 等跨窗口通信方式回调 cut
- [x] 关于操作顺序的覆盖,当前考虑的处理方式是如果本地窗口有相关操作的中间态,则优先本地窗口操作,之后再考虑跨窗口可能性。但可能存在跨窗口复制在本地窗口时间之后在执行粘贴的情况,是否考虑维护一个 unix 时间戳等方式再同时有两种来源的情况下考虑时间线顺序
先考虑实现为:
- cut 降级为 copy
- 不考虑顺序,页面内部操作优先
对于 cut 操作,跨窗口难以维护状态响应,是将 cut 降级为 copy 还是采用 postMessage 等跨窗口通信方式回调 cut
降级为 copy 就可以,这块的状态确实不好维护
关于操作顺序的覆盖,当前考虑的处理方式是如果本地窗口有相关操作的中间态,则优先本地窗口操作,之后再考虑跨窗口可能性。但可能存在跨窗口复制在本地窗口时间之后在执行粘贴的情况,是否考虑维护一个 unix 时间戳等方式再同时有两种来源的情况下考虑时间线顺序
这里感觉不用做这么复杂,异常情况还有 Error 的弹窗提示兜底
另外,建议将 Web/Electron 对于跨窗口复制粘贴的场景,都抽象到 ClipboardService 做一层处理吧,这样后续维护上也会简单一些。
@songhn233
Pull request: web: https://github.com/opensumi/core/pull/1384 electron: WIP
@songhn233 目前还有遇到什么问题吗?预计什么时候把基础功能写完?
@songhn233 目前还有遇到什么问题吗?预计什么时候把基础功能写完?
正好准备最近两周把剩下部分完成了, 因为 review 后续也会有一定工作量
前段时间应届生的一些准备工作花了不少时间 😂
在 Electron 适配时发现对于跨目录项目原先的 getNodeByPathOrUri 支持有问题,getNodeByPathOrUri 所有操作在 FileTree 对应的 root 下操作,而多窗口场景下基本面对的是不同的 root
之前 web 下指定了固定 workspace,所以跨窗口操作时能获取到相同的 root,而实际上不同 root 下会出现问题
发现 workspace 有类似思路的处理,但需要特殊判断后对于预设的 roots 进行处理
不过发现虽然 workspace 能正确处理拖拽的情况,但是对于复制/粘贴操作依然有问题,在获取 parent 时返回为 undefined
file-server 支持通用的 copy/paste,但是视图侧的操作强依赖于 file-tree 的模型
对于多 root 的情况来说,getFileTreeNodePathByUri 需要处理拼接
https://github.com/opensumi/core/blob/4012f4cbfff88d48f7db751f0c8b72817e9dea6e/packages/file-tree-next/src/browser/file-tree.service.ts#L449-L457
这块的 Path 看来经过了优化,和实际的路径不一致,比如我的个人目录 User/songhn/xx 实际反应在 root.path 为 root_0/xx
这个映射是使用了 compact mode,问题应该出在 multi 情况下对这个缓存 key 的维护上
详见 https://github.com/opensumi/core/issues/1556#issuecomment-1221583835
@songhn233 文件树上的 path 主要为 Tree 结构下维护的一份路径关系,在做复制粘贴等操作的时候,我比较建议通过文件本身的 uri 去进行数据处理。
例如,复制目录 A 下的文件到 B 目录时,复制的应该为原始文件路径,file://user/xx/A/a.js 在 B 目录下面再通过调用 FileTreeAPI 的方式拷贝文件进去,文件树本身的事件响应会在文件被创建时触发 B 树的刷新进而更新整个文件树状态。
Native 增强补充说明
https://github.com/microsoft/vscode/issues/164
从 native file explorer 中拖拽文件到 OpenSumi
原先已支持。判断 native 来源后通过 DataTransfer.files 读取即可,浏览器普遍兼容
从 native file explorer 中复制文件到 OpenSumi
之前准备采用 https://chromestatus.com/feature/5671807392677888 这里写了个 Demo,可以正常获取到 File 文件,应该是可行的(>= Chrome 91) 复制任意文件在网页执行复制操作即可,https://stackblitz.com/edit/typescript-vv4nz8?file=index.ts,index.html,package.json

从 OpenSumi 中拖拽文件到 native file explorer
也写了个 Demo,拖拽文件到本地有三种实现方式,https://stackblitz.com/edit/typescript-bgzk98?file=index.html 第一种 drop file 直接 DataTransfer.files.add(File) 不能正常工作,这应该也是浏览器安全策略一部分 https://stackoverflow.com/a/37696609
第二种写入 text/plain,对于 text 会生成一个 name 为 text,context 也为 text 的文件。同时如果文本内容为文件名的形式,也会像第一种方式一样生成一个临时文件 text.md.textClipping(不同浏览器操作系统策略不一样)
目前决定采用第三种,和 vscode.dev 实现类似,vscode 对应逻辑见 https://github.com/microsoft/vscode/commit/6c1f37fa73ad5943306a96c44c3fe119c92c14e2
ev.dataTransfer.setData(
'DownloadURL',
'application/octet-stream:text.md:data:application/octet-stream;base64,aGVsbG8gd29ybGQ='
);
vscode web 默认实现需要一个类似文件服务的系统提供 url 下载,所以在直接 open local folder 的情况下拖拽是无法正常工作的,只能拖拽出空文件
构造 url 的方式最前是文件名,后续为 base64 的文件内容。但是考虑到直接复制文件内容和名称下载一个新的文件不合适。感觉还是拖拽后产生一个同名的空文件来处理比较好
从 OpenSumi 中复制文件到 native file explorer
这个目前浏览器环境应该是做不到的,https://web.dev/async-clipboard Clipboard API 目前的预期应该就是写入文本或图片
@erha19 在接 electron clipboard 的时候遇到一个问题,当前 Clipboard 的实现是 common 放定义,browser 和 electron 分别实现,直接去注入的话是不起作用的,实际结果还是使用了 browser 侧的逻辑 https://github.com/opensumi/core/blob/bf45fef9be6ca267d5c6cd58963e7358d24299ab/packages/core-electron-main/src/bootstrap/services/index.ts#L9-L18 看了下现在的普遍做法是
https://github.com/opensumi/core/blob/54ecd1fa96cc0809a2e6404dbd6b6ab1c7d1b66c/packages/core-browser/src/bootstrap/inner-providers.ts#L27-L31
先在 providers 里注入,然后在 browser 也注入 electron 侧的实现,然后通过 isElectronRenderer 来进行切换。
我这样理解没有错吧~
@songhn233 这里主要还是先前没有把 electron 相关内容没有完整剥离出来导致的这种实现问题,目前安装框架内的普遍实现是这样做就可以了。先把功能实现,后续也可以看看是否有更合理的分层结构设计可以改改。
Native 增强补充说明
从 OpenSumi 中复制文件到 native file explorer
浏览器 这个目前浏览器环境应该是做不到的,https://web.dev/async-clipboard
electron https://stackoverflow.com/questions/65264058/how-to-clip-file-into-clipboard-in-electron 看起来 electron 也不支持这种能力,vscode 也没有实现这一操作
done #1594.