///|
/// 文件系统相关的响应模型。
///
/// 与用户模型一样,解码一律容错:字段缺失、`null`、类型不符都退化成零值。
/// 这里额外处理两类 Go 带来的麻烦:
///
/// - `int64` 字段(文件大小、分片大小)在 JSON 里是**数字**,而 core json 的
/// `Int64` 只认字符串,所以统一用 `int64_field` 读;
/// - JSON 键叫 `type` 的字段在 MoonBit 里没法直接当字段名(保留字),
/// 统一命名 `obj_type`。
///|
/// 列表排序设置(Go 的 `model.Sort`,被存储、分享、归档元数据共用)。
pub struct ListSort {
/// 排序字段,例如 `name`、`size`、`modified`。
order_by : String
/// `asc` 或 `desc`。
order_direction : String
/// 解压策略:`front`、`decompress` 等。
extract_folder : String
}
///|
/// 解码排序设置。
pub impl @json.FromJson for ListSort with fn from_json(json, path) {
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "ListSort: expected object"))
}
{
order_by: string_field(fields, "order_by"),
order_direction: string_field(fields, "order_direction"),
extract_folder: string_field(fields, "extract_folder"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend ListSort with @json.FromJson::{from_json}
///|
/// 挂载点容量信息。
///
/// 只有登录用户(非游客)且管理员没有隐藏存储详情时才会随文件对象返回。
pub struct StorageDetails {
/// 存储驱动名,例如 `Local`、`Aliyundrive`。
driver_name : String
/// 总容量(字节)。
total_space : Int64
/// 剩余容量(字节)。
free_space : Int64
}
///|
/// 解码挂载点容量信息。
pub impl @json.FromJson for StorageDetails with fn from_json(json, path) {
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "StorageDetails: expected object"))
}
{
driver_name: string_field(fields, "driver_name"),
total_space: int64_field(fields, "total_space"),
free_space: int64_field(fields, "free_space"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend StorageDetails with @json.FromJson::{from_json}
///|
/// 文件系统对象(文件或目录)。
pub struct ObjResp {
/// 名称(不含路径)。
name : String
/// 字节大小;目录通常是 0。
size : Int64
/// 是否为目录。
is_dir : Bool
/// 修改时间(RFC3339 字符串)。
modified : String
/// 创建时间(RFC3339 字符串)。
created : String
/// 签名,用于拼接带签名的直链。
sign : String
/// 缩略图 URL。
thumb : String
/// 对象类型编号(服务端 `utils.GetObjType` 的结果,对应 JSON 键 `type`)。
obj_type : Int
/// 哈希信息的字符串形式。
hashinfo : String
/// 哈希信息(算法名 → 值)。
hash_info : Map[String, String]
/// 所在挂载点的容量信息;服务端未提供时是 `None`。
mount_details : StorageDetails?
}
///|
/// 解码文件系统对象。
pub impl @json.FromJson for ObjResp with fn from_json(json, path) {
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "ObjResp: expected object"))
}
{
name: string_field(fields, "name"),
size: int64_field(fields, "size"),
is_dir: bool_field(fields, "is_dir"),
modified: string_field(fields, "modified"),
created: string_field(fields, "created"),
sign: string_field(fields, "sign"),
thumb: string_field(fields, "thumb"),
obj_type: int_field(fields, "type"),
hashinfo: string_field(fields, "hashinfo"),
hash_info: map_field(fields, "hash_info"),
mount_details: json_field(fields, "mount_details"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend ObjResp with @json.FromJson::{from_json}
///|
/// `POST /api/fs/list` 的响应。
pub struct FsListResponse {
/// 目录下的对象。
content : Array[ObjResp]
/// 目录内对象总数。
total : Int64
/// 该目录的说明(来自元数据配置)。
readme : String
/// 该目录的自定义头信息。
header : String
/// 当前用户对该目录是否有写权限。
write : Bool
/// 是否允许绕过写内容检查。
write_content_bypass : Bool
/// 实际提供该目录的存储驱动名。
provider : String
/// 该目录可用的直传工具。
direct_upload_tools : Array[String]
}
///|
/// 解码目录列表响应。
pub impl @json.FromJson for FsListResponse with fn from_json(json, path) {
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "FsListResponse: expected object"))
}
{
content: array_field(fields, "content"),
total: int64_field(fields, "total"),
readme: string_field(fields, "readme"),
header: string_field(fields, "header"),
write: bool_field(fields, "write"),
write_content_bypass: bool_field(fields, "write_content_bypass"),
provider: string_field(fields, "provider"),
direct_upload_tools: array_field(fields, "direct_upload_tools"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend FsListResponse with @json.FromJson::{from_json}
///|
/// `POST /api/fs/get` 的响应。
///
/// Go 服务端把 `ObjResp` 内嵌进来,对象字段与 `raw_url` 等在同一层;
/// MoonBit 没有结构体内嵌,所以对象部分放在 `obj` 里(解码时仍从同一个
/// 扁平对象读)。
pub struct FsGetResponse {
/// 对象本身(名称、大小、签名等)。
obj : ObjResp
/// 带签名的直链。
raw_url : String
/// 该对象的说明。
readme : String
/// 该对象的自定义头信息。
header : String
/// 提供该对象的存储驱动名。
provider : String
/// 同目录下的相关对象(开启 `related` 时才有)。
related : Array[ObjResp]
}
///|
/// 解码对象详情响应。
pub impl @json.FromJson for FsGetResponse with fn from_json(json, path) {
let obj : ObjResp = @json.from_json(json, path~)
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "FsGetResponse: expected object"))
}
{
obj,
raw_url: string_field(fields, "raw_url"),
readme: string_field(fields, "readme"),
header: string_field(fields, "header"),
provider: string_field(fields, "provider"),
related: array_field(fields, "related"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend FsGetResponse with @json.FromJson::{from_json}
///|
/// 目录项(`POST /api/fs/dirs` 用,只有名字与修改时间)。
pub struct DirResp {
/// 目录名。
name : String
/// 修改时间(RFC3339 字符串)。
modified : String
}
///|
/// 解码目录项。
pub impl @json.FromJson for DirResp with fn from_json(json, path) {
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "DirResp: expected object"))
}
{
name: string_field(fields, "name"),
modified: string_field(fields, "modified"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend DirResp with @json.FromJson::{from_json}
///|
/// 搜索结果项(`POST /api/fs/search` 用)。
pub struct SearchResult {
/// 所在目录的完整路径。
parent : String
/// 对象名。
name : String
/// 是否为目录。
is_dir : Bool
/// 字节大小。
size : Int64
/// 对象类型编号(对应 JSON 键 `type`)。
obj_type : Int
}
///|
/// 解码搜索结果项。
pub impl @json.FromJson for SearchResult with fn from_json(json, path) {
guard json is Object(fields) else {
raise @json.JsonDecodeError((path, "SearchResult: expected object"))
}
{
parent: string_field(fields, "parent"),
name: string_field(fields, "name"),
is_dir: bool_field(fields, "is_dir"),
size: int64_field(fields, "size"),
obj_type: int_field(fields, "type"),
}
}
///|
/// 显式声明手写的 `FromJson` 实现以普通方法暴露。
pub extend SearchResult with @json.FromJson::{from_json}