123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- #import "../docs_common/template/template.typ" : ZRYGenericDocs
- #import "@preview/tablex:0.0.8": tablex, colspanx, rowspanx
- #import "@preview/oxifmt:0.2.0": strfmt
- #let pageCounting = locate(loc=>counter(page).final(loc).at(0))
- #let title = "openNGVFS 文档"
- #let version = (
- major: 1,
- minor: 1,
- patch: 0,
- )
- #let semVerStr = strfmt("{}.{}.{}", version.major, version.minor, version.patch)
- #show: body => ZRYGenericDocs(
- title: title,
- subTitle: "",
- titleDesc: "",
- docVer: "API Ver. " + semVerStr,
- headerSettings: (
- enable: true,
- ascent: 20%,
- content: locate(loc => {
- let elems = query(selector(heading).before(loc), loc)
- if counter(page).at(loc).first() > 1 [
- #text(
- weight: "bold",
- size: 0.9em,
- )[
- #title
- ]
- #h(1fr)
- #text(
- weight: "thin",
- size: 0.7em,
- )[
- #counter(page).display() / #pageCounting
- ]
- #line(length: 100%)
- ]
- }),
- ),
- footerSettings: (
- enable: true,
- descent: 30%,
- content: locate(loc => {
- if counter(page).at(loc).first() > 1 [
- #line(length: 100%)
- #text(
- weight: "thin",
- size: 0.6em,
- )[
- 公开文档
- ]
- ]
- }),
- ),
- body
- )
- = 项目说明
- 该项目基于商业项目ProjectNagae下属的NagaeVFS V1.1.0,为NagaeVFS的开源版本。该版本使用MIT License开源。注意,NagaeVFS后续版本将不再与openNGVFS兼容。
- = 版本说明
- 当前版本从NagaeVFS V1.1.0衍生,经过一定程度的测试,但使用前请自行进行必要的功能测试。
- 当前版本提供以下功能。
- == VFS
- 一个可挂载的虚拟文件系统。其主机接口兼容afero.Fs。
- == INIT WASM
- 用于初始化文件系统挂载的WASM虚拟机。
- 该虚拟机提供以下接口:
- + 在主机上创建和释放afero.Fs对象的接口。
- + 挂载主机上被创建的afero.Fs对象的接口。
- + 在主机VFS上创建目录的接口。
- + 读取配置文件中ExKV键值对内容的接口。
- === 可创建的afs对象
- ==== 来自afero.Fs的类型
- 当前版本可创建的afero.Fs对象,由afero包本身提供的有:
- - afero.OsFs
- - afero.MemMapFs
- - afero.BasePathFs
- - afero.RegexpFs
- - afero.ReadOnlyFs
- - afero.CopyOnWriteFs
- - afero.CacheOnReadFs
- 其中经过简单测试并通过的有:
- - afero.OsFs
- - afero.MemMapFs
- - afero.BasePathFs
- - afero.ReadOnlyFs
- 其中经过测试有问题的:
- - afero.RegexpFs
- - Readdir功能在遇到无法匹配的文件时产生error
-
- 该问题来自afero.RegexpFs本身,故不提供其修正。
- 谨慎考虑使用RegexpFs。
- ==== 来自第三方的
- - `"github.com/bep/overlayfs" overlayfs.OverlayFs`
-
- 经过测试,但有如下问题:
- - 不支持在子目录下创建文件,会产生错误
-
- `The system cannot find the path specified.`
- = 主机接口
- 这部分是关于主机golang库的文档。
- 该库位于 `openngvfs` 目录,包名 `git.swzry.com/zry/openNGVFS/openngvfs`。
- 以下为主机部分的示例代码,更完整的示例代码可以参考
- `testing/standalone-test-0001/go`。
- ```go
- func main() {
- // Init logger.
- logger := hiedalog.NewHiedaLogger()
- consoleBke := hiedabke_console.NewConsoleBackend(os.Stderr)
- logger.AddBackend(
- consoleBke,
- logger.LevelFilter.NameToID(hiedalog.DLN_DEBUG),
- )
- // Create openNGVFS object.
- fs := ngvfs.NewOpenNagaeVFS(logger)
- // Create Context.
- ctx := context.Background()
- // root is the root path of this program.
- root := "/home/satori/openngvfs_test_root/"
- // Init openNGVFS.
- // "test" is app name of this program.
- err := fs.Init(ctx, root, "test")
- if err != nil {
- fmt.Println("error initializing fs: ", err)
- return
- }
- // start init-wasm to mount filesystems.
- err = fs.RunMount()
- if err != nil {
- fmt.Println("error in run auto-mount: ", err)
- return
- }
- // ...
- // deinitializing before quit.
- err = fs.DeInit()
- if err != nil {
- fmt.Println("error deinitializing fs: ", err)
- }
- }
- ```
- 在上述示例代码中,App名称为test,
- openNGVFS相关的根目录为`/home/satori/openngvfs_test_root`,
- 那么我们应该像这样准备根目录的内容:
- ```bash
- cd /home/satori/openngvfs_test_root
- mkdir -p ./syscfg/openngvfs/wasm
- ```
- 然后将init-wasm文件test-init.wasm放入
- `/home/satori/openngvfs_test_root/syscfg/openngvfs/wasm`
- 目录中。
- 接下来在`/home/satori/openngvfs_test_root/syscfg/openngvfs/`下创建配置文件
- `fstab.toml`并写入如下内容
- ```toml
- [wasm]
- # 用于未单独定义的app的默认值
- default = "default-init"
- # 定义app `test` 的设置
- [test.app]
- wpms = "test-init"
- # 在这里定义全局的ExKV,这些键值可以在wasm中获取到
- [exkv.default]
- # 为每个app定义ExKV,会和全局ExKV合并,如key相同,则取每个app单独定义的值。
- [exkv.app.wpms]
- ```
- = INIT WASI接口
- == WASM导出函数
- #{
- let data = yaml("init_wasi_export.yaml")
- for funcPair in data {
- {
- let funcName = funcPair.at(0)
- [==== 函数 #raw(funcName)]
- let funcPart = funcPair.at(1)
- let funcParams = funcPart.at("params", default: none)
- let funcResults = funcPart.at("results", default: none)
- let prototypeParams = if funcParams != none and funcParams.len() > 0 {
- let prototypeParamsList = ()
- for iParam in funcParams {
- prototypeParamsList.push(iParam.name + ": " + iParam.type)
- }
- prototypeParamsList.join(",")
- }else{""}
- let prototypeCode = "fn " + funcName + "(" + prototypeParams + ")"
- let prototypeResult = if funcResults != none and funcResults.len() > 0 {
- let prototypeResultList = ()
- for iResult in funcResults {
- prototypeResultList.push(iResult.name + ": " + iResult.type)
- }
- " -> (" + prototypeResultList.join(",") + ")"
- }else{""}
- prototypeCode = prototypeCode + prototypeResult + ";"
- let prototype = raw(prototypeCode, lang:"rust")
- let tableContent = (
- [*名称*], colspanx(4)[#funcPair.at(0)],
- [*说明*], colspanx(4)[#funcPart.desc],
- [*原型*], colspanx(4)[#prototype],
- )
- if funcParams != none and funcParams.len() > 0 {
- let lenParams = funcParams.len()
- tableContent.push(rowspanx(lenParams+1)[*参数*])
- tableContent.push([*名称*])
- tableContent.push([*WASM类型*])
- tableContent.push([*语义类型*])
- tableContent.push([*说明*])
- for param in funcParams {
- let paramEnum = param.at("enum", default: none)
- tableContent.push(param.name)
- tableContent.push(param.type)
- tableContent.push(if param.xtyp != none {param.xtyp} else {param.type})
- tableContent.push(
- if paramEnum != none [
- #param.desc
- #let paramEnumTable = ()
- #for peti in paramEnum {
- paramEnumTable.push(peti.at(0))
- paramEnumTable.push(peti.at(1))
- }
- #tablex(
- columns: 2,
- [*值*], [*说明*],
- ..paramEnumTable
- )
- ]else[#param.desc]
- )
- }
- }
- if funcResults != none and funcResults.len() > 0 {
- let lenResults = funcResults.len()
- tableContent.push(rowspanx(lenResults+1)[*返回值*])
- tableContent.push([*名称*])
- tableContent.push([*WASM类型*])
- tableContent.push([*语义类型*])
- tableContent.push([*说明*])
- for param in funcResults {
- let paramEnum = param.at("enum", default: none)
- let paramXtyp = param.at("xtyp", default: none)
- tableContent.push(param.name)
- tableContent.push(param.type)
- tableContent.push(if paramXtyp != none {paramXtyp} else {param.type})
- tableContent.push(
- if paramEnum != none [
- #param.desc
- #let paramEnumTable = ()
- #for peti in paramEnum {
- paramEnumTable.push(peti.at(0))
- paramEnumTable.push(peti.at(1))
- }
- #tablex(
- columns: 2,
- [*值*], [*说明*],
- ..paramEnumTable
- )
- ]else[#param.desc]
- )
- }
- }
- tablex(
- columns: 5,
- ..tableContent
- )
- }
- }
- }
- == 主机导出模块
- #{
- let data = yaml("init_wasi_import.yaml")
- for modPair in data {
- [=== 模块 #raw(modPair.at(0))]
- for funcPair in modPair.at(1) {
- {
- let funcName = funcPair.at(0)
- [==== 函数 #raw(funcName)]
- let funcPart = funcPair.at(1)
- let funcParams = funcPart.at("params", default: none)
- let funcResults = funcPart.at("results", default: none)
- let prototypeParams = if funcParams != none and funcParams.len() > 0 {
- let prototypeParamsList = ()
- for iParam in funcParams {
- prototypeParamsList.push(iParam.name + ": " + iParam.type)
- }
- prototypeParamsList.join(",")
- }else{""}
- let prototypeCode = "fn " + funcName + "(" + prototypeParams + ")"
- let prototypeResult = if funcResults != none and funcResults.len() > 0 {
- let prototypeResultList = ()
- for iResult in funcResults {
- prototypeResultList.push(iResult.name + ": " + iResult.type)
- }
- " -> (" + prototypeResultList.join(",") + ")"
- }else{""}
- prototypeCode = prototypeCode + prototypeResult + ";"
- let prototype = raw(prototypeCode, lang:"rust")
- let tableContent = (
- [*名称*], colspanx(4)[#funcPair.at(0)],
- [*说明*], colspanx(4)[#funcPart.desc],
- [*原型*], colspanx(4)[#prototype],
- )
- if funcParams != none and funcParams.len() > 0 {
- let lenParams = funcParams.len()
- tableContent.push(rowspanx(lenParams+1)[*参数*])
- tableContent.push([*名称*])
- tableContent.push([*WASM类型*])
- tableContent.push([*语义类型*])
- tableContent.push([*说明*])
- for param in funcParams {
- let paramEnum = param.at("enum", default: none)
- let paramXtyp = param.at("xtyp", default: none)
- tableContent.push(param.name)
- tableContent.push(param.type)
- tableContent.push(if paramXtyp != none {paramXtyp} else {param.type})
- tableContent.push(
- if paramEnum != none [
- #param.desc
- #let paramEnumTable = ()
- #for peti in paramEnum {
- paramEnumTable.push(peti.at(0))
- paramEnumTable.push(peti.at(1))
- }
- #tablex(
- columns: 2,
- [*值*], [*说明*],
- ..paramEnumTable
- )
- ]else[#param.desc]
- )
- }
- }
- if funcResults != none and funcResults.len() > 0 {
- let lenResults = funcResults.len()
- tableContent.push(rowspanx(lenResults+1)[*返回值*])
- tableContent.push([*名称*])
- tableContent.push([*WASM类型*])
- tableContent.push([*语义类型*])
- tableContent.push([*说明*])
- for param in funcResults {
- let paramEnum = param.at("enum", default: none)
- tableContent.push(param.name)
- tableContent.push(param.type)
- tableContent.push(if param.xtyp != none {param.xtyp} else {param.type})
- tableContent.push(
- if paramEnum != none [
- #param.desc
- #let paramEnumTable = ()
- #for peti in paramEnum {
- paramEnumTable.push(peti.at(0))
- paramEnumTable.push(peti.at(1))
- }
- #tablex(
- columns: 2,
- [*值*], [*说明*],
- ..paramEnumTable
- )
- ]else[#param.desc]
- )
- }
- }
- tablex(
- columns: 5,
- ..tableContent
- )
- }
- }
- }
- }
- == WASM侧Rust Crate
- 提供有用于WASM侧的接口包装Rust Crate。
- 示例程序在`testing\standalone-test-0001\openngvfs_init_wasm_test`,
- 编译该版本建议安装cargo-wasi。
- ```bash
- cargo install cargo-wasi
- ```
- 可使用如下命令编译init-wasm示例:
- ```bash
- just wasm
- ```
- 若未安装cargo-wasi请修改justfile内的编译命令。
- 目前本文档内暂不提供该Crate的文档。
- 该包的交互式文档可使用rustdoc生成:
- ```bash
- cd init-wasm
- just doc_html
- ```
- 生成的文档在`init-wasm/ngvfs_init_wasm_lib/target/doc/ngvfs_init_wasm_lib`
- 若安装有`SimpleHttpTestServer`,可继续使用如下命令:
- ```bash
- # 端口号可换成其他值
- just serv_doc "localhost:8088"
- ```
- 然后使用浏览器打开 #link("http://localhsot:8088/")。
|