{"id":23790029,"url":"https://github.com/blackglory/refile","last_synced_at":"2025-10-16T09:23:39.253Z","repository":{"id":82413020,"uuid":"544251507","full_name":"BlackGlory/refile","owner":"BlackGlory","description":"🌲","archived":false,"fork":false,"pushed_at":"2024-02-15T07:48:19.000Z","size":2669,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-21T12:43:37.428Z","etag":null,"topics":["docker-image","esm","microservice","nodejs","typescript"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/blackglory/refile","language":"TypeScript","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/BlackGlory.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-02T02:42:00.000Z","updated_at":"2023-02-09T03:13:57.000Z","dependencies_parsed_at":"2024-02-15T08:47:04.750Z","dependency_job_id":null,"html_url":"https://github.com/BlackGlory/refile","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/BlackGlory/refile","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackGlory%2Frefile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackGlory%2Frefile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackGlory%2Frefile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackGlory%2Frefile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BlackGlory","download_url":"https://codeload.github.com/BlackGlory/refile/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackGlory%2Frefile/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265437620,"owners_count":23765124,"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":["docker-image","esm","microservice","nodejs","typescript"],"created_at":"2025-01-01T17:18:10.345Z","updated_at":"2025-10-16T09:23:34.197Z","avatar_url":"https://github.com/BlackGlory.png","language":"TypeScript","readme":"# Refile\n提供基于HTTP的文件管理服务, 受到IPFS启发.\n\nRefile的文件管理是基于内容寻址和引用计数进行的, 通过Refile上传的文件会失去它的文件名和MIME类型.\n\n## Quickstart\n```sh\ndocker run \\\n  --detach \\\n  --publish 8080:8080 \\\n  blackglory\n```\n\n## Install\n### 从源代码运行\n```sh\ngit clone https://github.com/BlackGlory\ncd log\nyarn install\nyarn build\nyarn bundle\nyarn --silent start\n```\n\n### 从源代码构建\n```sh\ngit clone https://github.com/BlackGlory\ncd refile\nyarn install\nyarn docker:build\n```\n\n### Recipes\n#### docker-compose.yml\n```yaml\nversion: '3.8'\n\nservices:\n  refile:\n    image: 'blackglory'\n    restart: always\n    volumes:\n      - 'refile-database:/database'\n      - 'reifle-storage:/storage'\n    ports:\n      - '8080:8080'\n\nvolumes:\n  refile-database:\n  refile-storage:\n```\n\n## API\n所有API中的namespace和id都需要满足此正则表达式: `^[a-zA-Z0-9\\.\\-_]{0,255}$`\n\n### upload file\n`PUT /files/\u003chash\u003e`\n\n上传文件.\n\n上传文件时需要提供三个参数:\n- `file`:\n  需要上传的二进制文件, 由FormData的file字段提供.\n  一次只能上传一个文件, 表单的编码必须为`multipart/form-data`.\n- `hashList`:\n  分段hash列表, 由ForumData的多个名为hashList的同名字段提供.\n  将文件按512KiB为切割点进行分段, 计算出每段内容的SHA-256,\n  将其16进制字符串形式保存为有序数组, 该数组即为文件的hashList.\n- `hash`:\n  文件的最终hash, 在URL里提供.\n  将hashList的字符串连接起来, 计算其SHA-256, 其16进制字符串形式即为文件的最终hash.\n\n被上传的文件必须先通过set reference建立相应的引用关系.\n如果文件的引用数为零, 上传会被拒绝.\n上传参数设计得如此复杂是为了能够尽早拒绝错误和重复的文件.\n\n上传的文件原本不存在时, 返回HTTP状态码201.\n上传的文件原本就已经存在时, 返回HTTP状态码204.\n上传的文件的hash校验错误时, 返回HTTP状态码409.\n\n### get file info\n`GET /files/\u003chash\u003e`\n\n获取与资源相关的信息.\n\n返回JSON:\n```ts\n{\n  hash: string\n  location: string | null // 未上传时, location为null\n  references: number\n}\n```\n\n#### Example\n##### curl\n```sh\ncurl \"http://localhost:8080/files/$hash\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/files/${hash}`)\n  .then(res =\u003e res.json())\n```\n\n### get file location\n`GET /files/\u003chash\u003e/location`\n\n通过hash获取文件的location.\n它与get file info的功能重合, 但性能更好.\n\n如果location存在, 返回HTTP状态码200, 以文本形式返回location.\n如果location不存在, 返回HTTP状态码404.\n\n#### Example\n##### curl\n```sh\ncurl \"http://localhost:8080/files/$hash/location\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/files/${hash}/location`)\n  .then(res =\u003e res.text())\n```\n\n### set reference\n`PUT /namespaces/\u003cnamespace\u003e/items/\u003cid\u003e/files/\u003chash\u003e`\n\n设置文件hash与引用的关系.\n\n#### Example\n##### curl\n```sh\ncurl \\\n  --request PUT \\\n  \"http://localhost:8080/namespaces/$namespace/items/$id/files/$hash\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/namespaces/${namespace}/items/${id}/files/${hash}`)\n```\n\n### remove reference\n`DELETE /namespaces/\u003cnamespace\u003e/items/\u003cid\u003e/files/\u003chash\u003e`\n\n移除文件hash与引用的关系.\n\n#### Example\n##### curl\n```sh\ncurl \\\n  --request DELETE \\\n  \"http://localhost:8080/namespaces/$namespace/items/$id/files/$hash\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/namespaces/${namespace}/items/${id}/files/${hash}`, {\n  method: 'DELETE'\n})\n```\n\n### remove references by item id\n`DELETE /namespaces/\u003cnamespace\u003e/items/\u003cid\u003e`\n\n移除特定项目的全部引用.\n\n#### Example\n##### curl\n```sh\ncurl \\\n  --request DELETE \\\n  \"http://localhost:8080/namespaces/$namespace/items/$id\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/namespaces/${namespace}/items/${id}`, {\n  method: 'DELETE'\n})\n```\n\n### remove references by namespace\n`DELETE /namespaces/\u003cnamespace\u003e`\n\n删除特定命名空间下的全部引用.\n\n#### Example\n##### curl\n```sh\ncurl \\\n  --request DELETE \\\n  \"http://localhost:8080/namespaces/$namespace\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/namespaces/${namespace}`, {\n  method: 'DELETE'\n})\n```\n\n### get all namespaces\n`GET /namespaces`\n\n获取所有命名空间.\n\n返回JSON:\n```ts\nstring[]\n```\n\n#### Example\n##### curl\n```sh\ncurl 'http://localhost:8080/namespaces'\n```\n\n##### JavaScript\n```js\nawait fetch('http://localhost:8080/namespaces')\n  .then(res =\u003e res.json())\n```\n\n### get all item ids\n`GET /namespaces/\u003cnamespace\u003e/items`\n\n获取特定命名空间下的所有项目id列表.\n\n返回JSON:\n```ts\nstring[]\n```\n\n#### Example\n##### curl\n```sh\ncurl \"http://localhost:8080/namespaces/$namespace/items\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/namespaces/${namespace}/items`)\n  .then(res =\u003e res.json())\n```\n\n### get file hashes by item id\n`GET /namespaces/\u003cnamespace\u003e/items/\u003cid\u003e/files`\n\n获取与特定引用相关联的文件hash列表.\n\n返回JSON:\n```ts\nstring[]\n```\n\n#### Example\n##### curl\n```sh\ncurl \"http://localhost:8080/namespaces/$namespace/items/$id/files\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/namespace/${namespace}/items/${id}/files`)\n  .then(res =\u003e res.json())\n```\n\n### get item ids by file hash\n`GET /files/\u003chash\u003e/namespaces/\u003cnamespace\u003e/items`\n\n获取特定命名空间下与特定文件相关的项目id列表.\n\n返回JSON:\n```ts\nstring[]\n```\n\n#### Example\n##### curl\n```sh\ncurl \"http://localhost:8080/files/$hash/namespaces/$namespace/items\"\n```\n\n##### JavaScript\n```js\nawait fetch(`http://localhost:8080/files/${hash}/namespaces/${namespace}/items`)\n  .then(res =\u003e res.json())\n```\n\n### collect garbage\n`POST /collect-garbage`\n\n执行垃圾回收, 将引用数为0的文件从存储中删除.\n\n#### Example\n##### curl\n```sh\ncurl 'http://localhost:8080/collect-garbage'\n```\n       \n##### JavaScript\n```js\nawait fetch('http://localhost:8080/collect-garbage', {\n  method: 'POST'\n})\n```\n\n## 环境变量\n### `REFILE_HOST`, `REFILE_PORT`\n通过环境变量`REFILE_HOST`和`REFILE_PORT`决定服务器监听的地址和端口,\n默认值为`localhost`和`8080`.\n\n## 客户端\n- JavaScript/TypeScript(Node.js, Browser): \u003chttps://github.com/BlackGlory/refile-js\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblackglory%2Frefile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblackglory%2Frefile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblackglory%2Frefile/lists"}