内容#

本节介绍了内容如何在 JupyterLite 网站上集成以及如何使用它。

内核内的访问#

默认情况下,通过默认文件浏览器访问的内容独立于在执行内核内访问的内容。 使文件对内核可用可能取决于内核的实现方式。

Emscripten 内核#

使用 Emscripten 的内核(如 pyodidexeus 内核)依赖于 Emscripten 文件系统 来访问其内容。 对于这种情况,@jupyterlite/contents 提供了一个 DriveFS 辅助类,可用于在 Emscripten 文件系统中挂载文件

  const mountpoint = '/drive';
  const { FS, PATH, ERRNO_CODES } = /* provided by the emscripten module */;
  const { baseUrl } = options;
  const { DriveFS } = await import('@jupyterlite/contents');

  const driveFS = new DriveFS({
    FS,
    PATH,
    ERRNO_CODES,
    baseUrl, // Website base URL
    driveName: 'my-drive', // Any name of your choosing
    mountpoint,
  });
  FS.mkdir(mountpoint);
  FS.mount(driveFS, {}, mountpoint);
  FS.chdir(mountpoint);

挂载驱动器后,Jupyter Server 内容(在文件浏览器中显示的内容)将在内核中以 /drive 文件夹的形式提供。

DriveFS 需要网站基本 URL 来从主应用程序请求其内容。 深入了解驱动器架构将阐明这一点。

流程图 LR 子图 主线程 方向 TB M[主线程] M --- C[内容] 结束 子图 webworker 方向 TB M -.- K[内核] K --- FS[Emscripten FS] FS --- D[DriveFS] 结束 S[服务工作者] -.-|BroadcastChannel| M D -.-|REST API| S

在 JupyterLite 中运行内核时,会使用三个线程。

  • 主线程:它执行主用户界面,并了解文件浏览器的内容。

  • 内核 Web 工作者:它执行内核(例如,评估来自主线程的笔记本中的代码片段)。它将一个 DriveFS 挂载到 Emscripten 文件系统中。

  • 服务工作者:它从缓存中提供网站资产(以便离线工作)。它还可以捕获任何其他网络请求。

假设内核执行以下 Python 代码片段,将内容写入文本文件。

Path("dummy.txt").write_text("Writing on Emscripten filesystem")

以下是执行文件系统操作时发生的交互简化序列。

序列图 参与者 P 作为 Python 解释器 参与者 F 作为 Emscripten FS 参与者 D 作为 DriveFS 参与者 S 作为服务工作者 参与者 M 作为主线程 参与者 C 作为内容管理器 P->>+F: 将文本写入文件 F->>+D: 调用 put D->>+S: 发送 HTTP POST /api/drive S->>+M: 通过通道广播消息 M->>+C: 调用 `save` C-->>-M: 无 M-->>-S: 响应 S-->>-D: 响应 D-->>-F: 返回 F-->>-P: 完成

当代码与文件系统交互时,它会与 Emscripten 虚拟文件系统 交互。该虚拟文件系统允许经典代码(如本例中的 Python 代码片段)在几乎无需更改的情况下运行。此外,虚拟文件系统允许开发人员通过 文件系统 API 提供自己的文件系统 I/O 处理机制。在序列中,我们将触发的 API 简化为单个 put(实际上,在写入文件时会发生多次调用)。由于我们插入了一个自定义驱动实现 DriveFS,因此 put 解析将由该代码负责。现有的逻辑是启动一个 POST HTTP 请求,该请求在 /api/drive 端点上,其主体描述了要执行的文件系统操作。在本例中,它看起来像

{
  "method": "put",
  "path": "/dummy.txt",
  "data": { "format": "text", "data": "Writing on Emscripten filesystem" }
}

该请求旨在由服务工作者捕获(在 @jupyterlite/server 包中定义)。服务工作者将通过 BroadcastChannel(名为 /api/drive.v1)中的消息将 HTTP 请求转发到主线程。
该消息将由 BroadcastChannelWrapper 捕获,该包装器在插件 @jupyterlite/server-extension:emscripten-filesystem 中实例化。该包装器了解 Jupyter 内容管理器,以便回答请求。例如,在 put 操作的情况下,将调用内容管理器的 save 方法。
然后,回复将通过广播通道、网络请求等传播回 Emscripten 文件系统。

使用 HTTP 请求的必要性导致了使用异步 API(即 Jupyter 内容管理器)回答同步 API(即 Emscripten 文件系统)的约束。

这种架构使 Lite 内核能够从自定义 JupyterLab 驱动 访问内容,从而拥有多个内容来源。