868 lines
14 KiB
Markdown
868 lines
14 KiB
Markdown
# Gomog HTTP API 参考文档
|
||
|
||
**版本**: v1.0.0-alpha
|
||
**最后更新**: 2026-03-14
|
||
**基础路径**: `/api/v1`
|
||
|
||
---
|
||
|
||
## 📖 目录
|
||
|
||
1. [概述](#概述)
|
||
2. [认证与授权](#认证与授权)
|
||
3. [数据库管理](#数据库管理)
|
||
4. [集合管理](#集合管理)
|
||
5. [文档操作](#文档操作)
|
||
6. [查询操作](#查询操作)
|
||
7. [聚合操作](#聚合操作)
|
||
8. [索引管理](#索引管理)
|
||
9. [错误处理](#错误处理)
|
||
10. [响应格式](#响应格式)
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
### 协议
|
||
|
||
- **传输协议**: HTTP/1.1 或 HTTP/2
|
||
- **数据格式**: JSON
|
||
- **字符编码**: UTF-8
|
||
- **默认端口**: 8080
|
||
|
||
### 基础 URL
|
||
|
||
```
|
||
http://localhost:8080/api/v1/{database}/{collection}/{operation}
|
||
```
|
||
|
||
### URL 参数说明
|
||
|
||
| 参数 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| `{database}` | 数据库名称 | `testdb` |
|
||
| `{collection}` | 集合名称 | `users` |
|
||
| `{operation}` | 操作类型 | `find`, `insert`, `update` 等 |
|
||
|
||
### HTTP 方法
|
||
|
||
| 方法 | 用途 |
|
||
|------|------|
|
||
| POST | 执行数据库操作(查询、插入、更新、删除等) |
|
||
| GET | 获取元数据信息 |
|
||
|
||
---
|
||
|
||
## 数据库管理
|
||
|
||
### 列出所有数据库
|
||
|
||
**端点**: `POST /api/v1/admin/listDatabases`
|
||
|
||
**请求**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/admin/listDatabases
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"databases": [
|
||
{"name": "testdb", "sizeOnDisk": 1024, "empty": false},
|
||
{"name": "prod", "sizeOnDisk": 2048, "empty": false}
|
||
],
|
||
"totalSize": 3072,
|
||
"totalSizeMb": 3
|
||
}
|
||
```
|
||
|
||
### 列出当前数据库的集合
|
||
|
||
**端点**: `POST /api/v1/{database}/listCollections`
|
||
|
||
**请求**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/listCollections
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"collections": [
|
||
{"name": "users", "type": "collection"},
|
||
{"name": "orders", "type": "collection"}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 集合管理
|
||
|
||
### 创建集合
|
||
|
||
Gomog 会在首次插入数据时自动创建集合,无需手动创建。
|
||
|
||
### 删除集合
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/drop`
|
||
|
||
**请求**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/drop
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"nIndexesWas": 1
|
||
}
|
||
```
|
||
|
||
### 重命名集合
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/renameCollection`
|
||
|
||
**请求**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/renameCollection \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"to": "members"}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 文档操作
|
||
|
||
### 插入文档
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/insert`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `documents` | array | ✅ | 要插入的文档数组 |
|
||
| `ordered` | boolean | ❌ | 是否按顺序插入(默认 true) |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/insert \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"documents": [
|
||
{
|
||
"name": "Alice",
|
||
"age": 30,
|
||
"email": "alice@example.com"
|
||
},
|
||
{
|
||
"name": "Bob",
|
||
"age": 25,
|
||
"email": "bob@example.com"
|
||
}
|
||
]
|
||
}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"n": 2,
|
||
"insertedIds": {
|
||
"0": "20240101120000.000000000",
|
||
"1": "20240101120001.000000000"
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应**:
|
||
```json
|
||
{
|
||
"ok": 0,
|
||
"errmsg": "duplicate key error",
|
||
"code": 11000
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 查询操作
|
||
|
||
### 查询文档
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/find`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `filter` | object | ❌ | 查询条件(默认 `{}`) |
|
||
| `projection` | object | ❌ | 字段投影 |
|
||
| `sort` | object | ❌ | 排序规则 |
|
||
| `skip` | number | ❌ | 跳过文档数 |
|
||
| `limit` | number | ❌ | 返回文档数限制 |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/find \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"filter": {
|
||
"age": {"$gte": 25, "$lte": 30},
|
||
"department": "技术部"
|
||
},
|
||
"projection": {
|
||
"name": 1,
|
||
"email": 1,
|
||
"_id": 0
|
||
},
|
||
"sort": {"age": -1},
|
||
"limit": 10
|
||
}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"cursor": {
|
||
"firstBatch": [
|
||
{"name": "Alice", "email": "alice@example.com"},
|
||
{"name": "Bob", "email": "bob@example.com"}
|
||
],
|
||
"id": 0,
|
||
"ns": "testdb.users"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 查询单个文档
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/findOne`
|
||
|
||
**请求参数**: 同 `find`
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/findOne \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"filter": {"email": "alice@example.com"}}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"value": {
|
||
"_id": "20240101120000.000000000",
|
||
"name": "Alice",
|
||
"age": 30,
|
||
"email": "alice@example.com"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 统计文档数
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/count`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `filter` | object | ❌ | 查询条件(默认 `{}`) |
|
||
| `limit` | number | ❌ | 最大计数限制 |
|
||
| `skip` | number | ❌ | 跳过文档数 |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/count \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"filter": {"age": {"$gte": 25}}}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"n": 15
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 更新操作
|
||
|
||
### 更新单个文档
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/update`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `filter` | object | ✅ | 查询条件 |
|
||
| `update` | object | ✅ | 更新操作 |
|
||
| `upsert` | boolean | ❌ | 不存在则插入(默认 false) |
|
||
| `multi` | boolean | ❌ | 更新多个(默认 false) |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/update \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"filter": {"name": "Alice"},
|
||
"update": {
|
||
"$set": {"age": 31},
|
||
"$inc": {"loginCount": 1}
|
||
}
|
||
}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"n": 1,
|
||
"nModified": 1,
|
||
"matchedCount": 1,
|
||
"modifiedCount": 1,
|
||
"upsertedId": null
|
||
}
|
||
```
|
||
|
||
### 更新多个文档
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/update \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"filter": {"department": "技术部"},
|
||
"update": {"$inc": {"salary": 1000}},
|
||
"multi": true
|
||
}'
|
||
```
|
||
|
||
### Upsert 操作
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/update \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"filter": {"email": "charlie@example.com"},
|
||
"update": {
|
||
"$setOnInsert": {
|
||
"email": "charlie@example.com",
|
||
"name": "Charlie",
|
||
"age": 28
|
||
}
|
||
},
|
||
"upsert": true
|
||
}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"n": 1,
|
||
"nModified": 0,
|
||
"upsertedId": "20240101120002.000000000"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 删除操作
|
||
|
||
### 删除单个文档
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/delete`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `filter` | object | ✅ | 查询条件 |
|
||
| `multi` | boolean | ❌ | 删除多个(默认 false) |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/delete \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"filter": {"email": "alice@example.com"}}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"n": 1,
|
||
"deletedCount": 1
|
||
}
|
||
```
|
||
|
||
### 删除多个文档
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/delete \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"filter": {"status": "inactive"},
|
||
"multi": true
|
||
}'
|
||
```
|
||
|
||
---
|
||
|
||
## 聚合操作
|
||
|
||
### 执行聚合管道
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/aggregate`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `pipeline` | array | ✅ | 聚合管道数组 |
|
||
| `cursor` | object | ❌ | 游标选项 |
|
||
| `explain` | boolean | ❌ | 是否返回执行计划 |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/orders/aggregate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"pipeline": [
|
||
{
|
||
"$match": {
|
||
"status": "completed",
|
||
"createdAt": {"$gte": "2024-01-01"}
|
||
}
|
||
},
|
||
{
|
||
"$group": {
|
||
"_id": "$customerId",
|
||
"totalAmount": {"$sum": "$amount"},
|
||
"orderCount": {"$sum": 1},
|
||
"avgAmount": {"$avg": "$amount"}
|
||
}
|
||
},
|
||
{
|
||
"$sort": {"totalAmount": -1}
|
||
},
|
||
{
|
||
"$limit": 10
|
||
}
|
||
]
|
||
}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"cursor": {
|
||
"firstBatch": [
|
||
{
|
||
"_id": "cust_001",
|
||
"totalAmount": 15000,
|
||
"orderCount": 5,
|
||
"avgAmount": 3000
|
||
},
|
||
{
|
||
"_id": "cust_002",
|
||
"totalAmount": 12000,
|
||
"orderCount": 4,
|
||
"avgAmount": 3000
|
||
}
|
||
],
|
||
"id": 0,
|
||
"ns": "testdb.orders"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 支持的聚合阶段
|
||
|
||
详见 [聚合管道文档](AGGREGATION_PIPELINE.md)
|
||
|
||
---
|
||
|
||
## 索引管理
|
||
|
||
### 创建索引
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/createIndex`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `keys` | object | ✅ | 索引键定义 |
|
||
| `unique` | boolean | ❌ | 是否唯一索引 |
|
||
| `name` | string | ❌ | 索引名称 |
|
||
| `background` | boolean | ❌ | 后台创建(默认 false) |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/createIndex \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"keys": {"email": 1},
|
||
"unique": true,
|
||
"name": "idx_email_unique"
|
||
}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"createdCollectionAutomatically": false,
|
||
"numIndexesBefore": 1,
|
||
"numIndexesAfter": 2,
|
||
"note": "all indexes already exist"
|
||
}
|
||
```
|
||
|
||
### 列出索引
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/getIndexes`
|
||
|
||
**请求**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/getIndexes
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"indexes": [
|
||
{
|
||
"v": 2,
|
||
"key": {"_id": 1},
|
||
"name": "_id_",
|
||
"ns": "testdb.users"
|
||
},
|
||
{
|
||
"v": 2,
|
||
"key": {"email": 1},
|
||
"name": "idx_email_unique",
|
||
"unique": true,
|
||
"ns": "testdb.users"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 删除索引
|
||
|
||
**端点**: `POST /api/v1/{database}/{collection}/dropIndex`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `index` | string | ✅ | 索引名称 |
|
||
|
||
**请求示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/v1/testdb/users/dropIndex \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"index": "idx_email_unique"}'
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"nIndexesWas": 2
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 错误处理
|
||
|
||
### 错误响应格式
|
||
|
||
```json
|
||
{
|
||
"ok": 0,
|
||
"errmsg": "错误描述信息",
|
||
"code": 错误码,
|
||
"codeName": "错误名称"
|
||
}
|
||
```
|
||
|
||
### 常见错误码
|
||
|
||
| 错误码 | 错误名称 | 说明 |
|
||
|--------|---------|------|
|
||
| 1 | InternalError | 内部错误 |
|
||
| 2 | BadValue | 参数值错误 |
|
||
| 7 | NoSuchKey | 键不存在 |
|
||
| 11000 | DuplicateKey | 重复键值 |
|
||
| 26 | NamespaceNotFound | 集合不存在 |
|
||
| 43 | NamespaceExists | 集合已存在 |
|
||
| 52 | InvalidPipelineOperator | 无效的聚合操作符 |
|
||
|
||
### 错误处理示例
|
||
|
||
**请求重复键值**:
|
||
```json
|
||
// 请求
|
||
{
|
||
"documents": [{"email": "existing@example.com"}]
|
||
}
|
||
|
||
// 响应
|
||
{
|
||
"ok": 0,
|
||
"errmsg": "duplicate key error",
|
||
"code": 11000,
|
||
"codeName": "DuplicateKey"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 响应格式
|
||
|
||
### 成功响应
|
||
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
// 其他响应数据...
|
||
}
|
||
```
|
||
|
||
### 分页响应
|
||
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"cursor": {
|
||
"firstBatch": [...],
|
||
"nextBatch": [...],
|
||
"id": 12345,
|
||
"ns": "database.collection"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 批量操作响应
|
||
|
||
```json
|
||
{
|
||
"ok": 1,
|
||
"n": 10,
|
||
"insertedIds": {"0": "id1", "1": "id2"},
|
||
"upsertedIds": {},
|
||
"matchedCount": 10,
|
||
"modifiedCount": 8,
|
||
"deletedCount": 0
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 高级查询
|
||
|
||
### 查询操作符
|
||
|
||
详见 [查询操作符文档](QUERY_OPERATORS.md)
|
||
|
||
#### 比较操作符
|
||
|
||
```json
|
||
{
|
||
"filter": {
|
||
"age": {"$gt": 25},
|
||
"salary": {"$gte": 5000, "$lte": 10000},
|
||
"status": {"$in": ["active", "pending"]}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 逻辑操作符
|
||
|
||
```json
|
||
{
|
||
"filter": {
|
||
"$or": [
|
||
{"age": {"$lt": 25}},
|
||
{"salary": {"$gt": 8000}}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 元素操作符
|
||
|
||
```json
|
||
{
|
||
"filter": {
|
||
"tags": {"$elemMatch": {"$eq": "important"}},
|
||
"score": {"$exists": true}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 更新操作符
|
||
|
||
详见 [更新操作符文档](UPDATE_OPERATORS.md)
|
||
|
||
#### 字段更新
|
||
|
||
```json
|
||
{
|
||
"update": {
|
||
"$set": {"status": "active"},
|
||
"$unset": {"tempField": ""},
|
||
"$rename": {"oldName": "newName"}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 数组操作
|
||
|
||
```json
|
||
{
|
||
"update": {
|
||
"$push": {"scores": 95},
|
||
"$addToSet": {"tags": "new"},
|
||
"$pull": {"items": {"price": {"$lt": 100}}}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 算术更新
|
||
|
||
```json
|
||
{
|
||
"update": {
|
||
"$inc": {"viewCount": 1},
|
||
"$mul": {"price": 0.9}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 性能优化
|
||
|
||
### 使用投影
|
||
|
||
```bash
|
||
# 只返回需要的字段
|
||
{"projection": {"name": 1, "email": 1, "_id": 0}}
|
||
```
|
||
|
||
### 使用索引
|
||
|
||
```bash
|
||
# 为常用查询字段创建索引
|
||
{"keys": {"email": 1, "status": 1}}
|
||
```
|
||
|
||
### 限制结果集
|
||
|
||
```bash
|
||
# 总是使用 limit
|
||
{"limit": 100}
|
||
```
|
||
|
||
### 避免全表扫描
|
||
|
||
```bash
|
||
# ❌ 不推荐
|
||
{"filter": {"$expr": {"$gt": ["$field1", "$field2"]}}}
|
||
|
||
# ✅ 推荐
|
||
{"filter": {"field1": {"$gt": 100}}}
|
||
```
|
||
|
||
---
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 批量操作
|
||
|
||
```bash
|
||
# 批量插入而不是逐条插入
|
||
{"documents": [{...}, {...}, {...}]}
|
||
```
|
||
|
||
### 2. 合理使用 upsert
|
||
|
||
```bash
|
||
# 使用 $setOnInsert 避免覆盖现有数据
|
||
{
|
||
"filter": {"email": "user@example.com"},
|
||
"update": {"$setOnInsert": {"name": "User"}},
|
||
"upsert": true
|
||
}
|
||
```
|
||
|
||
### 3. 事务性操作
|
||
|
||
对于需要事务的场景,使用 PostgreSQL 或 DM8 作为底层数据库。
|
||
|
||
### 4. 监控慢查询
|
||
|
||
```yaml
|
||
log:
|
||
level: "debug"
|
||
slow_query_threshold: "100ms"
|
||
```
|
||
|
||
---
|
||
|
||
## 附录
|
||
|
||
### HTTP 状态码
|
||
|
||
| 状态码 | 说明 |
|
||
|--------|------|
|
||
| 200 | 成功 |
|
||
| 400 | 请求参数错误 |
|
||
| 404 | 资源不存在 |
|
||
| 500 | 服务器内部错误 |
|
||
|
||
### 数据类型映射
|
||
|
||
| MongoDB | SQLite | PostgreSQL |
|
||
|---------|--------|------------|
|
||
| String | TEXT | VARCHAR |
|
||
| Number | REAL | DOUBLE PRECISION |
|
||
| Integer | INTEGER | BIGINT |
|
||
| Boolean | INTEGER | BOOLEAN |
|
||
| Array | JSONB | JSONB |
|
||
| Object | JSONB | JSONB |
|
||
| Date | DATETIME | TIMESTAMP |
|
||
|
||
---
|
||
|
||
**维护者**: Gomog Team
|
||
**许可证**: MIT
|