BioforestChain / dweb_browser

BioforestChain Infrastructure
https://docs.dweb-browser.org
MIT License
13 stars 4 forks source link

file.std.dweb 的标准化 #88

Open Gaubee opened 8 months ago

Gaubee commented 8 months ago

现在 file 协议是由 file.std.dweb 这个模块提供核心服务,其它模块还能通过适配器的方式额外进行适配,从而来影响一个设备中所有模块对于file:///的内容访问。

这其实会带来很多困惑,因此这里我提出一些基本理念来避免一些根本性的安全问题发生。

PS: 以下内容中 “file” 指 “file 模块”,“模块” 指 “其它模块”

  1. file:///file://file.std.dweb的缩写。

    正如http://file://http.std.dweb/fetch的缩写、ws://file://http.std.dweb/websocket的缩写

  2. 模块是完全独立的,我们应该以一个硬件一个模块的理念去看待模块,因此在我们做开发的时候,不可以认为文件是可以直接在硬件层面进行共享。而是要理解成 file 与模块是私有化的,每个模块背后的 file 模块都是完全独立的

    这也是目前 file 模块提供服务的方式,即便是同一个硬件设备上,模块是不能直接访问到其它模块的文件,但是我们现在通过 picker+realPath 这两接口来实现了直接访问。这其实是一个错误的设计,它打破的原则,是一种妥协,它应该被逐渐废弃。

  3. 如果要做所谓的共享,那么概念上不可以脱离我们的“统一传输层”,并且共享必须是“模块与模块”之间发生,而不能是“模块与 file 与模块”的关系,之所以要遵守这种关系,更 DwebBrowser 的愿景有很大关系,我当然不希望基于之前错误设计写出来的代码在未来标准往前走的时候才发现原来的代码都用不了,因此需要及时作出纠正:

    1. 首先数据的源头来自 file,如果只是转发,虽然正确,但是固然存在大量的资源损耗,所以我们需要在“统一传输层”这里打通直连加速。
    2. 直连加速的意味着在客观的硬件层面,作出一张设备与设备之间的连接网,跟路由表一样,数据传输可以自己在这个底层逻辑中自动进行传输优化。
    3. 目前我们已经尝试过类似的方案:就是 ipcBody 的句柄传输,只不过目前这个方案非常具有针对性,不具备标准化和普世性。
    4. 未来用户将个人与家庭的所有支持 dweb 协议的设备进行互联的时候,“统一传输层”就会更加重要,大家一定要把这个目标纳入 DwebBrowser 这个软件的心脏中,如果失去这个目标,那么 DwebBrowser 本身就只是一个把 webview 和网络协议玩得比较花的软件平台而已,只有将设备互联的理念带进来,它才能真正意义上具备“移动区块链基础设施”这个冠名。
    5. 在统一传输层,我们需要根据各种客观因素打交道,通常来说可以归纳成这三种情况:
      1. file =(all_data_1)=> A =(all_data_2)=> B

        就是转发

      2. file =(headers_1)=> A =(headers_2)=> B; file =(body_data_1)=> B

        只转发头,内容还是直连获取

      3. file =(all_data_1)=> A =(headers_2)=> B; file =(body_data_1)=> B

        file 发送了两次内容数据,这种场景是 A 需要读取数据,但对于给 B 的数据并不修改,所以可以由 file 直接发出两次数据

    6. 对于文件的写入,也是同样的原理,应该直接发生在 A 与 B 两个模块之间,不可以绕过模块直接向 file 进行数据写入,这是不安全的。
    7. 但是如果对于每个模块承担资源访问的编程负担,那么这可能会增加模块访问者的心智负担,因为本来是直接面向 file 来做开发的,现在 file 是对方模块私有的东西,导致现在需要换成向对方模块发送数据,让对方模块自己去做 file 的读写,这会非常冗长。因此我们需要一种标准化的方案来解决这个问题:

      1. 首先对于服务模块(a.server.dweb)来说,它要提供 file 访问:

        class AServer extends MicroModule {
        override async bootstrap(bootstrapContext) {
         /// 注册子协议
         this.protocol("file.std.dweb", async (protocolContext) => {
           // 在收到访问的时候
           protocolContext.onConnect((clientIpc, reason) => {
             // 自己连接到 file,构建出一个 子连接
             const fileSubIpc = this.connect("file.std.dweb").fork(reason);
             /// 简单的双向绑定
             clientIpc.pipe(fileSubIpc); // 等价于 clientIpc.onMessage((msg)=>otherIpc.send(msg))
             fileSubIpc.pipe(clientIpc);
        
             /// 也可以在双向绑定是做一些拦截,从而做一些自定义
             clientIpc.pipe(fileSubIpc, {
               onRequest(request, toClientIpc) {
                 if (request.pathname === "/some-custom") {
                   // ...
                 } else {
                   return toClientIpc.request(request);
                 }
               },
             });
           });
         });
        }
        }
      2. 那么对于访问模块(b.client.dweb),它可以这样做使用 sub-protcol 来进行资源访问:

        const serverIpc = await dns.connect("a.server.dweb");
        await serverIpc.request("file://file.std.dweb/info.txt").text(); // 可以缩写成 file:///info.txt