{"id":13413387,"url":"https://github.com/chanify/chanify","last_synced_at":"2025-05-16T08:05:16.542Z","repository":{"id":42133623,"uuid":"342322079","full_name":"chanify/chanify","owner":"chanify","description":"Chanify is a safe and simple notification tools. This repository is command line tools for Chanify.","archived":false,"fork":false,"pushed_at":"2023-06-01T20:31:42.000Z","size":485,"stargazers_count":1297,"open_issues_count":14,"forks_count":103,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-08T19:24:50.503Z","etag":null,"topics":["anonymous","apns","docker","docker-image","golang","ios","macos","message-workflow","notification-api","notification-service","notifications","notifications-alert","open-source","push-notifications","rest-api","server","webhook"],"latest_commit_sha":null,"homepage":"https://www.chanify.net","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chanify.png","metadata":{"files":{"readme":"README-zh_CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-02-25T17:20:04.000Z","updated_at":"2025-04-04T00:03:24.000Z","dependencies_parsed_at":"2024-01-08T15:34:44.090Z","dependency_job_id":null,"html_url":"https://github.com/chanify/chanify","commit_stats":{"total_commits":162,"total_committers":4,"mean_commits":40.5,"dds":0.01851851851851849,"last_synced_commit":"cc4bf1bf3ad9540ef005c9bfbe253731e3c3d9be"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chanify%2Fchanify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chanify%2Fchanify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chanify%2Fchanify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chanify%2Fchanify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chanify","download_url":"https://codeload.github.com/chanify/chanify/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254493378,"owners_count":22080126,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anonymous","apns","docker","docker-image","golang","ios","macos","message-workflow","notification-api","notification-service","notifications","notifications-alert","open-source","push-notifications","rest-api","server","webhook"],"created_at":"2024-07-30T20:01:39.175Z","updated_at":"2025-05-16T08:05:11.530Z","avatar_url":"https://github.com/chanify.png","language":"Go","readme":"# Chanify\n\n[![Docker](https://img.shields.io/docker/v/wizjin/chanify?sort=semver\u0026logo=docker\u0026style=flat-square)](https://hub.docker.com/r/wizjin/chanify)\n[![Release](https://img.shields.io/github/v/release/chanify/chanify?logo=github\u0026style=flat-square)](https://github.com/chanify/chanify/releases/latest)\n[![iTunes App Store](https://img.shields.io/itunes/v/1531546573?logo=apple\u0026style=flat-square)](https://itunes.apple.com/cn/app/id1531546573)\n[![WebStore](https://img.shields.io/chrome-web-store/v/llpdpmhkemkjeeigibdamadahmhoebdg?logo=Google%20Chrome\u0026logoColor=white\u0026style=flat-square)](https://chrome.google.com/webstore/detail/chanify/llpdpmhkemkjeeigibdamadahmhoebdg)\n[![Windows](https://img.shields.io/github/v/release/chanify/chanify-win?label=windows\u0026logo=windows\u0026style=flat-square)](https://github.com/chanify/chanify-win/releases/latest)\n[![Workflow](https://img.shields.io/github/workflow/status/chanify/chanify/ci?label=build\u0026logo=github\u0026style=flat-square)](https://github.com/chanify/chanify/actions?workflow=ci)\n[![CodeQL](https://img.shields.io/github/workflow/status/chanify/chanify/codeql?label=codeql\u0026logo=github\u0026style=flat-square)](https://github.com/chanify/chanify/actions?workflow=codeql)\n[![Codecov](https://img.shields.io/codecov/c/github/chanify/chanify?logo=codecov\u0026style=flat-square)](https://codecov.io/gh/chanify/chanify)\n[![Total alerts](https://img.shields.io/lgtm/alerts/g/chanify/chanify.svg?logo=lgtm\u0026logoWidth=18\u0026style=flat-square)](https://lgtm.com/projects/g/chanify/chanify/alerts/)\n[![Go Report Card](https://goreportcard.com/badge/github.com/chanify/chanify?style=flat-square)](https://goreportcard.com/report/github.com/chanify/chanify)\n[![Go Reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go\u0026logoColor=white\u0026style=flat-square)](https://pkg.go.dev/github.com/chanify/chanify)\n[![GitHub](https://img.shields.io/github/license/chanify/chanify?style=flat-square)](LICENSE)\n[![Docker pull](https://img.shields.io/docker/pulls/wizjin/chanify?style=flat-square)](https://hub.docker.com/r/wizjin/chanify)\n[![Downloads](https://img.shields.io/github/downloads/chanify/chanify/total?style=flat-square)](https://github.com/chanify/chanify/releases/latest)\n[![Users](https://img.shields.io/chrome-web-store/users/llpdpmhkemkjeeigibdamadahmhoebdg?style=flat-square)](https://chrome.google.com/webstore/detail/chanify/llpdpmhkemkjeeigibdamadahmhoebdg)\n\n[English](README.md) | 简体中文\n\nChanify 是一个简单的消息推送工具。每一个人都可以利用提供的 API 来发送消息推送到自己的 iOS 设备上。\n\n\u003cdetails open=\"open\"\u003e\n  \u003csummary\u003e\u003ch2 style=\"display: inline-block\"\u003e目录\u003c/h2\u003e\u003c/summary\u003e\n  \u003col\u003e\n    \u003cli\u003e\u003ca href=\"#功能\"\u003e功能\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#入门\"\u003e入门\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\n        \u003ca href=\"#安装\"\u003e安装\u003c/a\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#预编译包\"\u003e预编译包\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#docker\"\u003eDocker\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#从源代码\"\u003e从源代码\u003c/a\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n        \u003ca href=\"#用法\"\u003e用法\u003c/a\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#作为客户端\"\u003e作为客户端\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#作为无状态服务器\"\u003e作为无状态服务器\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#作为有状态服务器\"\u003e作为有状态服务器\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#添加节点服务器\"\u003e添加节点服务器\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\n                \u003ca href=\"#发送消息\"\u003e发送消息\u003c/a\u003e\n                \u003cul\u003e\n                    \u003cli\u003e\u003ca href=\"#命令行\"\u003e命令行\u003c/a\u003e\u003c/li\u003e\n                    \u003cli\u003e\u003ca href=\"#python-3\"\u003ePython 3\u003c/a\u003e\u003c/li\u003e\n                    \u003cli\u003e\u003ca href=\"#ruby\"\u003eRuby\u003c/a\u003e\u003c/li\u003e\n                    \u003cli\u003e\u003ca href=\"#nodejs\"\u003eNodeJS\u003c/a\u003e\u003c/li\u003e\n                    \u003cli\u003e\u003ca href=\"#php\"\u003ePHP\u003c/a\u003e\u003c/li\u003e\n                \u003c/ul\u003e\n            \u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n        \u003ca href=\"#http-api\"\u003eHTTP API\u003c/a\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#发送文本\"\u003e发送文本\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#发送链接\"\u003e发送链接\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#发送图片\"\u003e发送图片\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#发送音频\"\u003e发送音频\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#发送文件\"\u003e发送文件\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#发送动作\"\u003e发送动作\u003c/a\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#配置文件\"\u003e配置文件\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\n        \u003ca href=\"#安全\"\u003e安全\u003c/a\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#设置可注册\"\u003e设置可注册\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#令牌生命周期\"\u003e令牌生命周期\u003c/a\u003e\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#chrome-插件\"\u003eChrome 插件\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#windows-客户端\"\u003eWindows 客户端\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#docker-compose\"\u003eDocker Compose\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#lua-api\"\u003eLua API\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#贡献\"\u003e贡献\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#许可证\"\u003e许可证\u003c/a\u003e\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n## 功能\n\nChanify 包括这些功能：\n\n- 支持自定义频道分类消息\n- 支持部署自己的节点服务器\n- 依照去中心化设计的系统架构\n- 随机账号生成保护隐私\n- 支持文本/图片/音频/文件等多种消息格式\n\n## 入门\n\n1. 从 AppStore 安装 [iOS 应用](https://itunes.apple.com/cn/app/id1531546573)（1.0.0 或以上版本）或 [macOS 应用](https://apps.apple.com/cn/app/id1531546573) (1.3.0 或以上版本)。\n2. 获取发送使用的令牌`token`，[更多细节](https://github.com/chanify/chanify-ios)。\n3. 使用 API 来发送消息。\n\n## 安装\n\n### 预编译包\n\n可以[这里](https://github.com/chanify/chanify/releases/latest)下载最新的预编译二进制包。\n\n### Docker\n\n```bash\n$ docker pull wizjin/chanify:latest\n```\n\n### 从源代码\n\n```bash\n$ git clone https://github.com/chanify/chanify.git\n$ cd chanify\n$ make install\n```\n\n## 用法\n\n### 作为客户端\n\n可以使用下列命令来发送消息\n\n```bash\n# 文本消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --text=\u003c文本消息\u003e\n\n# 链接消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --link=\u003c网页链接\u003e\n\n# 图片消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --image=\u003c图片文件路径\u003e\n\n# 音频消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --audio=\u003c音频文件路径\u003e\n\n# 文件消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --file=\u003c文件路径\u003e --text=\u003c文件描述\u003e\n\n# 动作消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --text=\u003c文本消息\u003e --title=\u003c文本标题\u003e --action=\"\u003c动作名字\u003e|\u003c动作链接 url\u003e\"\n\n# 时间线消息\n$ chanify send --endpoint=http://\u003caddress\u003e:\u003cport\u003e --token=\u003ctoken\u003e --timeline.code=\u003c代号\u003e \u003c键值 1\u003e=\u003c数值 1\u003e \u003c键值 2\u003e=\u003c数值 2\u003e ...\n```\n\n`endpoint` 默认值是 `https://api.chanify.net`，并且会使用默认服务器发送消息。\n如果使用的是自建的节点服务器，请在讲`endpoint`设置成自建服务器的 URL。\n\n### 作为无状态服务器\n\nChanify 可以作为无状态服务器运行，在这种模式下节点服务器不会保存设备信息（APNS 令牌）。\n\n所有的设备信息会被存储在 api.chanify.net。\n\n消息会在节点服务器加密之后由 api.chanify.net 代理发送给苹果的 APNS 服务器。\n\n消息的流动如下:\n\n```text\n开始 =\u003e 自建节点服务器 =\u003e api.chanify.net =\u003e 苹果APNS服务器 =\u003e iOS客户端\n```\n\n```bash\n# 命令行启动\n$ chanify serve --host=\u003cip address\u003e --port=\u003cport\u003e --secret=\u003csecret key\u003e --name=\u003cnode name\u003e --endpoint=http://\u003caddress\u003e:\u003cport\u003e\n\n# 使用Docker启动\n$ docker run -it wizjin/chanify:latest serve --secret=\u003csecret key\u003e --name=\u003cnode name\u003e --endpoint=http://\u003caddress\u003e:\u003cport\u003e\n```\n\n### 作为有状态服务器\n\nChanify 可以作为有状态服务器运行，在这种模式下节点服务器会保存用户的设备信息（APNS 令牌）。\n\n消息会直接由节点服务器加密之后发送给苹果的 APNS 服务器。\n\n消息的流动如下:\n\n```text\n开始 =\u003e 自建节点服务器 =\u003e Apple server =\u003e iOS客户端\n```\n\n启动服务器\n\n```bash\n# 命令行启动\n$ chanify serve --host=\u003cip address\u003e --port=\u003cport\u003e --name=\u003cnode name\u003e --datapath=~/.chanify --endpoint=http://\u003caddress\u003e:\u003cport\u003e\n\n# 使用Docker启动\n$ docker run -it -v /my/data:/root/.chanify wizjin/chanify:latest serve --name=\u003cnode name\u003e --endpoint=http://\u003caddress\u003e:\u003cport\u003e\n```\n\n默认会使用 sqlite 保存数据，如果要使用 MySQL 作为数据库存储信息可以添加如下参数：\n\n```bash\n--dburl=mysql://\u003cuser\u003e:\u003cpassword\u003e@tcp(\u003cip address\u003e:\u003cport\u003e)/\u003cdatabase name\u003e?charset=utf8mb4\u0026parseTime=true\u0026loc=Local\n```\n\n注意：Chanify 不会创建数据库，只会创建表格，所以使用前请先自行建立数据库。\n\n### 添加节点服务器\n\n- 启动节点服务器\n- 获取服务器二维码（`http://\u003caddress\u003e:\u003cport\u003e/`）\n- 打开 iOS 的客户端扫描二维码添加节点\n\n### 发送消息\n\n#### 命令行\n\n```bash\n# 发送文本消息\n$ curl --form-string \"text=hello\" \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n\n# 发送文本文件\n$ cat message.txt | curl -H \"Content-Type: text/plain\" --data-binary @- \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n#### Python 3\n\n```python\nfrom urllib import request, parse\n\ndata = parse.urlencode({ 'text': 'hello' }).encode()\nreq = request.Request(\"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\", data=data)\nrequest.urlopen(req)\n```\n\n#### Ruby\n\n```ruby\nrequire 'net/http'\n\nuri = URI('http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e')\nres = Net::HTTP.post_form(uri, 'text' =\u003e 'hello')\nputs res.body\n```\n\n#### NodeJS\n\n```javascript\nconst https = require('https')\nconst querystring = require('querystring');\n\nconst data = querystring.stringify({ text: 'hello' })\nconst options = {\n    hostname: '\u003caddress\u003e:\u003cport\u003e',\n    port: 80,\n    path: '/v1/sender/\u003ctoken\u003e',\n    method: 'POST',\n    headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n        'Content-Length': data.length\n        }\n    }\n    var req = https.request(options, (res) =\u003e {\n    res.on('data', (d) =\u003e {\n        process.stdout.write(d);\n    });\n});  \nreq.write(data);\nreq.end();\n```\n\n#### PHP\n\n```php\n$curl = curl_init();\n\ncurl_setopt_array($curl, [\n    CURLOPT_URL           =\u003e 'http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e',\n    CURLOPT_CUSTOMREQUEST =\u003e 'POST',\n    CURLOPT_POSTFIELDS    =\u003e [ 'text' =\u003e 'hello' ],\n]);\n\n$response = curl_exec($curl);\n\ncurl_close($curl);\necho $response;\n```\n\n## HTTP API\n\n### 发送文本\n\n- __GET__\n```url\nhttp://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e/\u003cmessage\u003e\n```\n\n- __POST__\n```url\nhttp://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\n```\n\nContent-Type:\n\n- `text/plain`: Body is text message\n- `multipart/form-data`: The block of data(\"text\") is text message\n- `application/x-www-form-urlencoded`: `text=\u003curl encoded text message\u003e`\n- `application/json; charset=utf-8`: 字段都是可选的\n```json\n{\n    \"token\": \"\u003c令牌Token\u003e\",\n    \"title\": \"\u003c消息标题\u003e\",\n    \"text\": \"\u003c文本消息内容\u003e\",\n    \"copy\": \"\u003c可选的复制文本\u003e\",\n    \"autocopy\": 1,\n    \"sound\": 1,\n    \"priority\": 10,\n    \"actions\": [\n        \"动作名称1|http://\u003caction host\u003e/\u003caction1\u003e\",\n        \"动作名称2|http://\u003caction host\u003e/\u003caction2\u003e\",\n        ...\n    ],\n    \"timeline\": {\n        \"code\": \"\u003c标识 code\u003e\",\n        \"timestamp\": 1620000000000,\n        \"items\": {\n            \"key1\": \"value1\",\n            \"key2\": \"value2\",\n            ...\n        }\n    }\n}\n```\n\n支持以下参数：\n\n| 参数名              | 默认值    | 描述                              |\n| ------------------ | -------- | -------------------------------- |\n| title              | 无       | 通知消息的标题                      |\n| copy               | 无       | 可选的复制文本（仅文本消息有效）       |\n| autocopy           | `0`      | 是否自动复制文本（仅文本消息有效）     |\n| sound              | `0`      | `1` 启用声音提示, 其他情况会静音推送  |\n| priority           | `10`     | `10` 正常优先级, `5` 较低优先级     |\n| interruption-level | `active` | 通知时间的中断级别                  |\n| actions            | 无       | 动作列表                           |\n| timeline           | 无       | Timeline 对象                     |\n\n`sound`:\n  - 1 使用默认铃声\n  - 使用铃声代码，例如：\"bell\"\n\n`interruption-level`:\n  - `active`: 点亮屏幕并可能播放声音。\n  - `passive`: 不点亮屏幕或播放声音。\n  - `time-sensitive`: 点亮屏幕并可能播放声音； 可能会在“请勿打扰”期间展示。\n\n`timestamp` 单位为毫秒 (时区 - UTC)\n\n例如：\n\n```url\nhttp://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e?sound=1\u0026priority=10\u0026title=hello\u0026copy=123\u0026autocopy=1\n```\n\n覆盖 `Content-Type`\n\n```url\nhttp://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e?content-type=\u003ctext|json\u003e\n```\n\n### 发送链接\n\n```bash\n$ curl --form \"link=@\u003cweb url\u003e\" \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n```json\n{\n    \"link\": \"\u003cweb url\u003e\",\n    \"sound\": 1,\n    \"priority\": 10,\n}\n```\n\n### 发送图片\n\n目前仅支持使用 **POST** 方法通过自建的有状态服务器才能发送图片。\n\n- Content-Type: `image/png` 或者 `image/jpeg`\n\n```bash\ncat \u003cjpeg 文件路径\u003e | curl -H \"Content-Type: image/jpeg\" --data-binary @- \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n- Content-Type: `multipart/form-data`\n\n```bash\n$ curl --form \"image=@\u003cjpeg 文件路径\u003e\" \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n### 发送音频\n\n目前仅支持使用 **POST** 方法通过自建的有状态服务器才能发送 mp3 音频。\n\n- Content-Type: `audio/mpeg`\n\n```bash\ncat \u003cmp3 音频文件路径\u003e | curl -H \"Content-Type: audio/mpeg\" --data-binary @- \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n- Content-Type: `multipart/form-data`\n\n```bash\n$ curl --form \"audio=@\u003cmp3 音频文件路径\u003e\" \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n### 发送文件\n\n目前仅支持使用 **POST** 方法通过自建的有状态服务器才能发文件。\n\n- Content-Type: `multipart/form-data`\n\n```bash\n$ curl --form \"file=@\u003c文件路径\u003e\" \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n### 发送动作\n\n发送动作消息（最多 4 个动作）。\n\n- Content-Type: `multipart/form-data`\n\n```bash\n$ curl --form \"action=动作名称1|http://\u003caction host\u003e/\u003caction1\u003e\" \"http://\u003caddress\u003e:\u003cport\u003e/v1/sender/\u003ctoken\u003e\"\n```\n\n脚本动作的 URL:\n\n```bash\nchanify://action/run-script/\u003c脚本名称\u003e?\u003c参数名称1\u003e=\u003c参数值1\u003e\u0026\u003c参数名称2\u003e=\u003c参数值2\u003e\n```\n\n## 配置文件\n\n可以通过 yml 文件来配置 Chanify，默认路径`~/.chanify.yml`。\n\n```yml\nserver:\n    host: 0.0.0.0   # 监听IP地址\n    port: 8080      # 监听端口\n    endpoint: http://my.server/path # 入口URL\n    name: Node name # 节点名称\n    secret: \u003csecret code\u003e # 无状态服务器使用的密钥\n    datapath: \u003cdata path\u003e # 有状态服务器使用的数据存储路径\n#   pluginpath: \u003cplugin path\u003e # Lua 插件路径\n    dburl: mysql://root:test@tcp(127.0.0.1:3306)/chanify?charset=utf8mb4\u0026parseTime=true\u0026loc=Local # 有状态服务器使用的数据库链接\n    http:\n        - readtimeout: 10s  # Http 读取超时时间设置为 10 秒\n        - writetimeout: 10s # Http 写回超时时间设置为 10 秒\n    register:\n        enable: false # 关闭注册\n        whitelist: # 白名单\n            - \u003cuser id 1\u003e\n            - \u003cuser id 2\u003e\n#   plugin:\n#       webhook:\n#           - name: github  # POST http://my.server/path/v1/webhook/github/\u003ctoken\u003e\n#             file: webhook/github.lua # \u003cpluginpath\u003e/webhook/github.lua\n#             env:\n#               secret_token: \"secret token\"\n\nclient: # 作为客户端发送消息时使用\n    sound: 1    # 是否有提示音\n    endpoint: \u003cdefault node server endpoint\u003e\n    token: \u003cdefault token\u003e\n    interruption-level: \u003cinterruption level\u003e\n```\n\n## 安全\n\n### 设置可注册\n\n可以通过禁用节点服务器的用户注册功能，来使 Node 服务器成为私有服务器，防止非授权用户使用。\n\n```bash\nchanify serve --registerable=false --whitelist=\u003cuser1 id\u003e,\u003cuser2 id\u003e\n```\n\n- `--registerable=false`: 这个参数用来禁用用户注册\n- `whitelist`: 服务器禁用用户注册后，仍然可以添加使用的用户\n\n### 令牌生命周期\n\n- 令牌默认寿命约 90 天左右\n- 可以在频道详情页面配置令牌寿命 (1 天 ~ 5 年)\n\n如果令牌被泄露，请将泄露的令牌添加到禁用列表（在 iOS 客户端设置页面）。\n\n*注意: 请保护您的令牌不被泄露，禁用列表需要受信任的节点服务器（1.1.9 或以上版本）。*\n\n## Chrome 插件\n\n可以从[Chrome web store](https://chrome.google.com/webstore/detail/chanify/llpdpmhkemkjeeigibdamadahmhoebdg)下载插件.\n\n插件有以下功能:\n\n- 发送选中的`文本/图片/音频/链接`消息到 Chanify\n- 发送网页链接到 Chanify\n\n## Windows 客户端\n\n可以从[这里](https://github.com/chanify/chanify-win/releases/latest)获取到 [Windows 客户端](https://github.com/chanify/chanify-win)。\n\n客户端有以下功能:\n\n- 支持在 Windows 的 `发送到` 菜单中添加 Chanify\n- 支持利用`命令行`发送消息\n\n## Docker Compose\n\n1. 安装 [docker compose](https://docs.docker.com/compose/install).\n2. 编辑配置文件 (`docker-compose.yml`).\n3. 启动 docker compose: `docker-compose up -d`\n\n`docker-compose.yml`:\n```yml\nversion: \"3\"\nservices:\n    web:\n        image: nginx:alpine\n        restart: always\n        volumes:\n            - \u003cworkdir\u003e/nginx.conf:/etc/nginx/nginx.conf\n            - \u003cworkdir\u003e/ssl:/ssl\n        ports:\n            - 80:80\n            - 443:443\n    chanify:\n        image: wizjin/chanify:dev\n        restart: always\n        volumes:\n            - \u003cworkdir\u003e/data:/data\n            - \u003cworkdir\u003e/chanify.yml:/root/.chanify.yml\n```\n\n| 参数名    | 描述                        |\n| -------- | --------------------------- |\n| workdir  | 节点服务器的数据和配置存储目录。 |\n\n`\u003cworkdir\u003e/nginx.conf`:\n```txt\nuser  nginx;\nworker_processes  auto;\n\nerror_log  /var/log/nginx/error.log warn;\npid        /var/run/nginx.pid;\n\nevents {\n\tworker_connections  1024;\n}\n\nhttp {\n\tinclude       /etc/nginx/mime.types;\n\tdefault_type  application/octet-stream;\n\tlog_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n    '$status $body_bytes_sent \"$http_referer\" '\n    '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n\taccess_log  /var/log/nginx/access.log  main;\n\n\tserver_tokens   off;\n\tautoindex       off;\n\tsendfile        on;\n\ttcp_nopush      on;\n\ttcp_nodelay     on;\n\n\tkeepalive_timeout  10;\n\n    server {\n\t\tlisten\t\t\t\t80;\n\t\tserver_name         \u003chostname or ip\u003e;\n\t\taccess_log          off;\n\t\treturn 301 https://$host$request_uri;\n\t}\n\n\tserver {\n\t\tlisten              443 ssl http2;\n\t\tserver_name         \u003chostname or ip\u003e;\n\t\tssl_certificate     /ssl/\u003cssl key\u003e.crt;\n\t\tssl_certificate_key /ssl/\u003cssl key\u003e.key;\n\t\tssl_protocols       TLSv1.2 TLSv1.3;\n\t\tssl_ciphers         HIGH:!aNULL:!MD5;\n\t\tkeepalive_timeout   30;\n\t\tcharset             UTF-8;\n\t\taccess_log          off;\n\n\t\tlocation / {\n\t\t\tproxy_set_header   Host               $host;\n\t\t\tproxy_set_header   X-Real-IP          $remote_addr;\n\t\t\tproxy_set_header   X-Forwarded-Proto  $scheme;\n\t\t\tproxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;\n\t\t\tproxy_pass http://chanify:8080/;\n\t\t}\n\t}\n}\n```\n\n| 参数名           | 描述                           |\n| --------------- | ----------------------------- |\n| hostname or ip  | 节点服务器的外网域名或者 ip 地址。 |\n| ssl key         | SSL 证书的文件名。               |\n\n`\u003cworkdir\u003e/chanify.yml`:\n```yml\nserver:\n    endpoint: https://\u003chostname or ip\u003e\n    host: 0.0.0.0\n    port: 80\n    name: \u003cnode name\u003e\n    datapath: /data\n    register:\n        enable: false\n        whitelist: # whitelist    \n            - \u003cuser id\u003e\n```\n\n| 参数名           | 描述                           |\n| --------------- | ----------------------------- |\n| hostname or ip  | 节点服务器的外网域名或者 ip 地址。 |\n| node name       | 节点服务器名称。                 |\n| user id         | 用户白名单。                    |\n\n## Lua API\n\n使用方法\n\n```lua\nlocal hex = require \"hex\"\nlocal bytes = hex.decode(hex_string)\nlocal text = hex.encode(bytes_data)\n\nlocal json = require \"json\"\nlocal obj = json.decode(json_string)\nlocal str = json.encode(json_object)\n\nlocal crypto = require \"crypto\"\nlocal is_equal = crypto.equal(mac1, mac2)\nlocal mac = crypto.hmac(\"sha1\", key, message) -- 支持 md5 sha1 sha256\n\n-- Http 请求\nlocal req = ctx:request()\nlocal token_string = req:token()\nlocal http_url = req:url()\nlocal body_string = req:body()\nlocal query_value = req:query(\"key\")\nlocal header_value = req:header(\"key\")\n\n-- 发送消息\nctx:send({\n    title = \"message title\", -- 可选\n    text = \"message body\",\n    sound = \"sound or not\",  -- 可选\n    copy = \"copy\",           -- 可选\n    autocopy = \"autocopy\",   -- 可选 \n})\n```\n\n例子: [Github webhook event](plugin/webhook/github.lua)\n\n## 贡献\n\n贡献使开源社区成为了一个令人赞叹的学习，启发和创造场所。 **十分感谢**您做出的任何贡献。\n\n1. Fork 本项目\n2. 切换到 dev 分支 (`git checkout dev`)\n3. 创建您的 Feature 分支 (`git checkout -b feature/AmazingFeature`)\n4. 提交您的更改 (`git commit -m 'Add some AmazingFeature'`)\n5. 推送到分支 (`git push origin feature/AmazingFeature`)\n6. 开启一个 Pull Request (合并到 `chanify:dev` 分支)\n\n## 许可证\n\n根据 MIT 许可证分发，详情查看[`LICENSE`](LICENSE)。\n","funding_links":[],"categories":["Notification","Go","消息","Messaging","Relational Databases","server"],"sub_categories":["Selfhosted","检索及分析资料库","Search and Analytic Databases","Advanced Console UIs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanify%2Fchanify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchanify%2Fchanify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanify%2Fchanify/lists"}