|
1 | | -# callit |
2 | | - |
| 1 | +# Callit |
| 2 | +A lightweight self-hosted personal serverless platform based on Docker. |
3 | 3 | 轻量级、自建、基于 Docker 的个人 Serverless 平台。 |
4 | 4 |
|
| 5 | +`Callit` 允许你通过 Python 或 Node.js 编写 Worker,并通过 HTTP 路由触发执行,适合轻量 API、HTML 页面展示、个人自动化等服务。 |
| 6 | + |
| 7 | +<div style="width: 100%; display: flex; gap: 10px; text-align: center; padding: 20px;"> |
| 8 | + <a href="#快速开始" |
| 9 | + style="padding: 8px 14px; background-color: #007bff; color: white; border-radius: 8px; text-decoration: none;" |
| 10 | + target="_blank" rel="noreferrer"> |
| 11 | + Quick Start |
| 12 | + </a> |
| 13 | + <a href="./docs/README.md" |
| 14 | + style="padding: 8px 14px; background-color: #e600ff; color: white; border-radius: 8px; text-decoration: none;" |
| 15 | + target="_blank" rel="noreferrer"> |
| 16 | + Documentation |
| 17 | + </a> |
| 18 | +</div> |
| 19 | + |
| 20 | +## 屏幕截图 |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +## 核心能力 |
| 25 | +不依赖 Docker、Kubernetes 等容器技术,提供开箱即用的 Serverless 体验 |
| 26 | +快速开发,支持热更新 Worker 函数 |
| 27 | + |
| 28 | +- 基于 HTTP 路由触发 Worker |
| 29 | +- 支持 Python / Node.js 运行时 |
| 30 | +- 支持文件上传、文件返回、HTML 页面返回 |
| 31 | +- 支持全局依赖管理 |
| 32 | +- 内置 Admin 后台管理 Worker、配置和依赖 |
| 33 | + |
| 34 | +tips: |
| 35 | +> 如果你需要一个更成熟、功能更丰富且适用于企业级的 Serverless 平台,应该考虑 OpenFaas、Fission、AWS Lambda、Cloudflare Workers 等解决方案。`Callit` 更适合个人开发者、轻量级使用场景。 |
| 36 | +
|
| 37 | +## 快速开始 |
| 38 | + |
| 39 | +### Docker Compose (推荐) |
| 40 | + |
| 41 | +```yaml |
| 42 | +services: |
| 43 | + callit: |
| 44 | + image: yangzxi/callit:latest |
| 45 | + container_name: callit |
| 46 | + environment: |
| 47 | + - ADMIN_TOKEN= # 在生产环境中请设置一个强随机值 |
| 48 | + # - TZ=Asia/Shanghai |
| 49 | + ports: |
| 50 | + - "3100:3100" |
| 51 | + volumes: |
| 52 | + - ./data:/app/data |
| 53 | + restart: unless-stopped |
| 54 | +``` |
| 55 | +
|
| 56 | +启动: |
| 57 | +
|
| 58 | +```bash |
| 59 | +docker compose up -d |
| 60 | +``` |
| 61 | + |
| 62 | +启动后可访问: |
| 63 | + |
| 64 | +- Router: `http://127.0.0.1:3100` |
| 65 | +- Admin: `http://127.0.0.1:3100/admin` |
| 66 | + |
| 67 | +## Worker 模板 |
| 68 | + |
| 69 | +### Python Worker 模板 |
| 70 | + |
| 71 | +```python |
| 72 | +def handler(ctx): |
| 73 | + request = ctx.get("request", {}) |
| 74 | + |
| 75 | + return { |
| 76 | + "status": 200, |
| 77 | + "body": { |
| 78 | + "message": "Hello, Callit!", |
| 79 | + "request": request |
| 80 | + }, |
| 81 | + "headers": { |
| 82 | + "Content-Type": "application/json" |
| 83 | + } |
| 84 | + } |
| 85 | +``` |
| 86 | + |
| 87 | +### Node Worker 模板 |
| 88 | + |
| 89 | +```javascript |
| 90 | +function handler(ctx) { |
| 91 | + const { request } = ctx; |
| 92 | + |
| 93 | + return { |
| 94 | + status: 200, |
| 95 | + body: { |
| 96 | + message: "Hello, Callit!", |
| 97 | + request, |
| 98 | + }, |
| 99 | + headers: { |
| 100 | + "Content-Type": "application/json" |
| 101 | + } |
| 102 | + }; |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +说明: |
| 107 | + |
| 108 | +- Worker 目录中必须包含 `main.py` 或 `main.js` |
| 109 | +- 主文件中必须定义 `handler(ctx)`,通过 ctx 对象获取请求信息、上下文等信息 |
| 110 | +- 通过返回 JSON 结构化数据来控制 HTTP 响应的状态码、响应体和响应头 |
| 111 | +- 具体文档与样例请参考 [Worker 文档](./docs/worker_introduction.md) |
| 112 | + |
| 113 | + |
5 | 114 | ## 技术栈 |
6 | 115 |
|
7 | 116 | - Backend: Go + Gin |
8 | 117 | - Frontend: React + Vite + HeroUI |
9 | 118 | - Database: SQLite3 |
10 | 119 | - Runtime: Python3 / Node.js |
11 | 120 |
|
12 | | -## 端口 |
13 | 121 |
|
14 | | -- Router: `3100` |
15 | | -- Admin: `3101` |
| 122 | +## 二次开发 |
| 123 | + |
| 124 | +如果你需要本地修改源码、调试前端或开发后端,可按下面方式启动。 |
16 | 125 |
|
17 | | -## 运行前准备 |
| 126 | +### 1. 设置管理令牌 |
18 | 127 |
|
19 | 128 | ```bash |
20 | 129 | export ADMIN_TOKEN=your-token |
21 | 130 | ``` |
22 | 131 |
|
23 | | -## 本地运行 |
24 | | - |
25 | | -先构建前端并复制到 `/public`: |
| 132 | +### 2. 启动前端 |
26 | 133 |
|
27 | 134 | ```bash |
28 | 135 | cd pages |
29 | | -npm run build |
30 | | -cd .. |
31 | | -rm -rf public/* |
32 | | -cp -r pages/dist/* public/ |
| 136 | +pnpm install |
| 137 | +pnpm run dev |
33 | 138 | ``` |
34 | 139 |
|
35 | | -再启动后端: |
| 140 | +### 3. 启动后端 |
36 | 141 |
|
37 | 142 | ```bash |
38 | 143 | go run ./cmd |
39 | 144 | ``` |
40 | 145 |
|
41 | | -## Docker 运行 |
42 | | - |
43 | | -```bash |
44 | | -docker compose up --build |
45 | | -``` |
| 146 | +默认前端端口为 `3180`。 |
| 147 | +默认后端端口为 `3100`。 |
46 | 148 |
|
47 | 149 | ## 数据目录 |
48 | 150 |
|
49 | | -- `data/app.db` |
50 | | -- `data/workers/<worker_id>/...` |
51 | | -- `data/temps/<request_id>/...`(请求结束自动清理) |
52 | | -- `public`(Admin 前端构建产物目录) |
| 151 | +- `data/app.db`:SQLite 数据库 |
| 152 | +- `data/workers/<worker_id>/`:Worker 文件目录 |
| 153 | +- `data/temps/<request_id>/`:上传文件临时目录,请求结束后自动清理 |
| 154 | +- `data/.lib/<runtime>/`:运行时全局依赖目录 |
| 155 | +- `public/`:Admin 前端构建产物目录 |
53 | 156 |
|
54 | | -## 前端开发 |
| 157 | +## 常见使用场景 |
55 | 158 |
|
56 | | -```bash |
57 | | -cd pages |
58 | | -pnpm run dev |
59 | | -``` |
60 | | - |
61 | | -默认端口 `3180`,并已将 `/api` 代理到 `http://localhost:3101`。 |
62 | | - |
63 | | -## 脚本标准输入(stdin)示例 |
64 | | - |
65 | | -Router 会将请求上下文序列化为 JSON,通过标准输入传给 Worker: |
66 | | - |
67 | | -```json |
68 | | -{ |
69 | | - "request": { |
70 | | - "method": "POST", |
71 | | - "uri": "/api/js?data=123&data=456", |
72 | | - "url": "http://127.0.0.1:3100/api/js?data=123&data=456", |
73 | | - "route_suffix": "/", |
74 | | - "params": { |
75 | | - // `params` 规则: |
76 | | - // - `?data=123` -> `{"data":"123"}` |
77 | | - // - `?data=123&data=456` -> `{"data":"456"}`(同名参数以后出现的值覆盖前值) |
78 | | - "data": "456" |
79 | | - }, |
80 | | - "headers": { |
81 | | - "Content-Type": "application/json", |
82 | | - "X-Trace": "abc" |
83 | | - }, |
84 | | - "body": "{\"name\":\"callit\"}", |
85 | | - "json": { |
86 | | - "name": "callit" |
87 | | - } |
88 | | - }, |
89 | | - "event": { |
90 | | - "request_id": "f3f3f1f6-8ad0-4f42-b31a-a90f9e8b2b31", |
91 | | - "runtime": "node", |
92 | | - "worker_id": "2bcf9922-c7d9-4d2e-a15d-b83de4ece1c6", |
93 | | - "route": "/api/js" |
94 | | - } |
95 | | -} |
96 | | -``` |
97 | | - |
98 | | -## 脚本标准输出(stdout)示例 |
99 | | - |
100 | | -Worker 必须输出合法 JSON 到标准输出: |
101 | | - |
102 | | -```json |
103 | | -{ |
104 | | - "status": 200, |
105 | | - "headers": { |
106 | | - "X-Trace": "abc" |
107 | | - }, |
108 | | - "file": "index.html", |
109 | | - "body": { |
110 | | - "data": {}, |
111 | | - "message": "hello" |
112 | | - } |
113 | | -} |
114 | | -``` |
115 | | - |
116 | | -说明: |
117 | | -- `status` 可选,该值决定了 HTTP Status Code,默认 200。 |
118 | | -- `headers` 可选。 |
119 | | -- `body` 为业务响应体,支持 JSON 对象/数组,也支持字符串(例如 HTML 或纯文本)。 |
120 | | -- `file` 可选,表示 Worker 目录下的相对路径(如 `index.html`、`./index.html`、`/index.html`)。 |
121 | | -- 当 `file` 和 `body` 都不存在,固定返回 `404`(忽略 Worker 提供的 `status` 与 `Content-Type`)。 |
| 159 | +- 编写 JSON API |
| 160 | +- 上传文件后做解析或处理 |
| 161 | +- 生成并返回文件 |
| 162 | +- 返回 HTML 页面 |
| 163 | +- 使用第三方依赖扩展 Worker 能力 |
0 commit comments