core icon indicating copy to clipboard operation
core copied to clipboard

[FEATURE] Implementation of cross-end and cross-window file system service

Open songhn233 opened this issue 3 years ago • 5 comments

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,实现了 writeTextreadText。将原先耦合存储于 file-tree-service 中的 _pasteStore 抽离为 ClipboardService 中的 writeResourcereadResource 操作,web 侧依然使用 LocalStorageService,node 侧使用 electron/Clipboard

对于 drag 操作,web 侧改动应该同样适用

native

参考 vscode 相关 issue https://github.com/microsoft/vscode/issues/164 可以拆分为几个部分

  1. 从 OpenSumi 中复制文件/文件夹到 native file explorer
  2. 从 native file explorer 中复制文件到 OpenSumi
  3. ~~从 native file explorer 中拖拽文件到 OpenSumi~~ (当前已支持)
  4. 从 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.30 First commit

songhn233 avatar Jun 30 '22 17:06 songhn233

Self-assigned, /cc @erha19

待讨论的问题

  • [x] 对于 cut 操作,跨窗口难以维护状态响应,是将 cut 降级为 copy 还是采用 postMessage 等跨窗口通信方式回调 cut
  • [x] 关于操作顺序的覆盖,当前考虑的处理方式是如果本地窗口有相关操作的中间态,则优先本地窗口操作,之后再考虑跨窗口可能性。但可能存在跨窗口复制在本地窗口时间之后在执行粘贴的情况,是否考虑维护一个 unix 时间戳等方式再同时有两种来源的情况下考虑时间线顺序

先考虑实现为:

  • cut 降级为 copy
  • 不考虑顺序,页面内部操作优先

songhn233 avatar Jun 30 '22 17:06 songhn233

对于 cut 操作,跨窗口难以维护状态响应,是将 cut 降级为 copy 还是采用 postMessage 等跨窗口通信方式回调 cut

降级为 copy 就可以,这块的状态确实不好维护

关于操作顺序的覆盖,当前考虑的处理方式是如果本地窗口有相关操作的中间态,则优先本地窗口操作,之后再考虑跨窗口可能性。但可能存在跨窗口复制在本地窗口时间之后在执行粘贴的情况,是否考虑维护一个 unix 时间戳等方式再同时有两种来源的情况下考虑时间线顺序

这里感觉不用做这么复杂,异常情况还有 Error 的弹窗提示兜底

另外,建议将 Web/Electron 对于跨窗口复制粘贴的场景,都抽象到 ClipboardService 做一层处理吧,这样后续维护上也会简单一些。

@songhn233

erha19 avatar Jul 01 '22 02:07 erha19

Pull request: web: https://github.com/opensumi/core/pull/1384 electron: WIP

songhn233 avatar Jul 28 '22 02:07 songhn233

@songhn233 目前还有遇到什么问题吗?预计什么时候把基础功能写完?

erha19 avatar Aug 12 '22 02:08 erha19

@songhn233 目前还有遇到什么问题吗?预计什么时候把基础功能写完?

正好准备最近两周把剩下部分完成了, 因为 review 后续也会有一定工作量

前段时间应届生的一些准备工作花了不少时间 😂

songhn233 avatar Aug 12 '22 03:08 songhn233

在 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.pathroot_0/xx

这个映射是使用了 compact mode,问题应该出在 multi 情况下对这个缓存 key 的维护上

详见 https://github.com/opensumi/core/issues/1556#issuecomment-1221583835

songhn233 avatar Aug 21 '22 11:08 songhn233

@songhn233 文件树上的 path 主要为 Tree 结构下维护的一份路径关系,在做复制粘贴等操作的时候,我比较建议通过文件本身的 uri 去进行数据处理。

例如,复制目录 A 下的文件到 B 目录时,复制的应该为原始文件路径,file://user/xx/A/a.js 在 B 目录下面再通过调用 FileTreeAPI 的方式拷贝文件进去,文件树本身的事件响应会在文件被创建时触发 B 树的刷新进而更新整个文件树状态。

erha19 avatar Aug 22 '22 01:08 erha19

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

origin_img_v2_c8ed2be3-06b4-45b1-88e2-d6b3792c5c3g

从 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 目前的预期应该就是写入文本或图片

songhn233 avatar Aug 24 '22 17:08 songhn233

@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 看了下现在的普遍做法是

origin_img_v2_d4a9a9b4-f60d-4cc9-aeeb-73a3706405ag https://github.com/opensumi/core/blob/54ecd1fa96cc0809a2e6404dbd6b6ab1c7d1b66c/packages/core-browser/src/bootstrap/inner-providers.ts#L27-L31 先在 providers 里注入,然后在 browser 也注入 electron 侧的实现,然后通过 isElectronRenderer 来进行切换。

我这样理解没有错吧~

songhn233 avatar Aug 28 '22 17:08 songhn233

@songhn233 这里主要还是先前没有把 electron 相关内容没有完整剥离出来导致的这种实现问题,目前安装框架内的普遍实现是这样做就可以了。先把功能实现,后续也可以看看是否有更合理的分层结构设计可以改改。

erha19 avatar Aug 29 '22 02:08 erha19

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 也没有实现这一操作

songhn233 avatar Sep 12 '22 11:09 songhn233

done #1594.

erha19 avatar Oct 08 '22 08:10 erha19