Skip to content

Commit c19da62

Browse files
authored
Merge pull request vastsa#39 from ZHYCarge/master
add:支持使用阿里云OSS进行对象存储服务
2 parents cfa865c + 487895a commit c19da62

File tree

7 files changed

+125
-16
lines changed

7 files changed

+125
-16
lines changed

main.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,32 @@ async def index(code: str, ip: str = Depends(error_ip_limit), s: AsyncSession =
127127
await s.execute(update(Codes).where(Codes.id == info.id).values(count=info.count - 1))
128128
await s.commit()
129129
if info.type != 'text':
130-
info.text = f'/select?code={code}'
131-
return {
132-
'detail': f'取件成功,文件将在{settings.DELETE_EXPIRE_FILES_INTERVAL}分钟后删除',
133-
'data': {'type': info.type, 'text': info.text, 'name': info.name, 'code': info.code}
134-
}
130+
if settings.STORAGE_ENGINE == 'filesystem':
131+
info.text = f'/select?code={code}'
132+
return {
133+
'detail': f'取件成功,文件将在{settings.DELETE_EXPIRE_FILES_INTERVAL}分钟后删除',
134+
'data': {'type': info.type, 'text': info.text, 'name': info.name, 'code': info.code}
135+
}
136+
elif settings.STORAGE_ENGINE == 'aliyunsystem':
137+
info.text = await storage.get_filepath(info.text)
138+
return {
139+
'detail': f'取件成功,链接将在{settings.ACCESSTIME}秒后失效',
140+
'data': {'type': info.type, 'text': info.text, 'name': info.name, 'code': info.code}
141+
}
135142

143+
@app.post('/adminDownloadFile',dependencies=[Depends(admin_required)], description='管理员获取资源链接')
144+
async def admindownloadfile(filetext: str, s: AsyncSession = Depends(get_session)):
145+
if storage.STORAGE_ENGINE == 'aliyunsystem':
146+
filetext = await storage.get_filepath(filetext)
147+
return {
148+
'detail': f'获取文件链接成功,链接将在{settings.ACCESSTIME}秒后失效',
149+
'fileURL': filetext
150+
}
151+
elif storage.STORAGE_ENGINE == 'filesystem':
152+
return {
153+
'detail': f'获取文件链接成功',
154+
'fileURL':filetext
155+
}
136156

137157
@app.get('/banner')
138158
async def banner(request: Request, s: AsyncSession = Depends(get_session)):
@@ -176,7 +196,10 @@ async def get_file(code: str, ip: str = Depends(error_ip_limit), s: AsyncSession
176196
# 如果是文件,返回文件
177197
else:
178198
filepath = await storage.get_filepath(info.text)
179-
return FileResponse(filepath, filename=info.name)
199+
if settings.STORAGE_ENGINE == 'filesystem':
200+
return FileResponse(filepath, filename=info.name)
201+
else:
202+
return {'detail': '查询成功', 'data': filepath}
180203

181204

182205
@app.post('/share', dependencies=[Depends(admin_required)], description='分享文件')
@@ -206,6 +229,8 @@ async def share(background_tasks: BackgroundTasks, text: str = Form(default=None
206229
background_tasks.add_task(storage.save_file, file, _text)
207230
else:
208231
size, _text, _type, name = len(text), text, 'text', '文本分享'
232+
if settings.STORAGE_ENGINE == 'aliyunsystem':
233+
_text = f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/"+_text
209234
info = Codes(code=code, text=_text, size=size, type=_type, name=name, count=exp_count, exp_time=exp_time, key=key)
210235
s.add(info)
211236
await s.commit()

readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [x] 匿名分享:无需注册,无需登录
2222
- [x] 管理面板:查看所有文件,删除文件
2323
- [x] 一键部署:docker一键部署
24+
- [x] 多种存储方式:阿里云OSS、本地文件流
2425

2526
## 部署方式
2627

@@ -160,6 +161,15 @@ DESCRIPTION=FileCodeBox,文件快递柜,口令传送箱,匿名口令分享
160161
KEYWORDS=FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件,图片,视频,音频,压缩包等文件
161162
# 存储引擎
162163
STORAGE_ENGINE=filesystem
164+
# 如果使用阿里云OSS服务的话需要额外创建如下参数:
165+
# 阿里云账号AccessKey
166+
KeyId=阿里云账号AccessKey
167+
# 阿里云账号AccessKeySecret
168+
KeySecret=阿里云账号AccessKeySecret
169+
# 阿里云OSS Bucket的地域节点
170+
OSS_ENDPOINT=阿里云OSS Bucket的地域节点
171+
# 阿里云OSS Bucket的BucketName
172+
BUCKET_NAME=阿里云OSS Bucket的BucketName
163173
```
164174

165175
## 接口文档

readme_en.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- [x] anonymous sharing: no registration, no login
2323
- [x] management Panel: View all files and delete them
2424
- [x] one-click deployment: docker one-click deployment
25+
- [x] A variety of storage methods : Aliyun OSS、 local file flow
2526

2627
## Deployment method
2728

@@ -175,6 +176,15 @@ DESCRIPTION=FileCodeBox,文件快递柜,口令传送箱,匿名口令分享
175176
KEYWORDS=FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件,图片,视频,音频,压缩包等文件
176177
# 存储引擎
177178
STORAGE_ENGINE=filesystem
179+
# 如果使用阿里云OSS服务的话需要额外创建如下参数:
180+
# 阿里云账号AccessKey
181+
KeyId=阿里云账号AccessKey
182+
# 阿里云账号AccessKeySecret
183+
KeySecret=阿里云账号AccessKeySecret
184+
# 阿里云OSS Bucket的地域节点
185+
OSS_ENDPOINT=阿里云OSS Bucket的地域节点
186+
# 阿里云OSS Bucket的BucketName
187+
BUCKET_NAME=阿里云OSS Bucket的BucketName
178188
```
179189

180190
## Status

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ SQLAlchemy==1.4.44
44
python-multipart==0.0.5
55
uvicorn==0.15.0
66
greenlet==2.0.1
7-
starlette~=0.22.0
7+
starlette~=0.22.0
8+
oss2==2.16.0

settings.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,16 @@
4848
DESCRIPTION = config('DESCRIPTION', cast=str, default="FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件等文件")
4949
# 网站关键词
5050
KEYWORDS = config('KEYWORDS', cast=str, default="FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件等文件")
51-
# 存储引擎
51+
# 存储引擎:['aliyunsystem','filesystem']
5252
STORAGE_ENGINE = config('STORAGE_ENGINE', cast=str, default="filesystem")
53+
# 如果使用阿里云OSS的话需要创建如下参数
54+
# 阿里云账号AccessKey
55+
KeyId = config('KeyId', cast=str, default="阿里云账号AccessKey")
56+
# 阿里云账号AccessKeySecret
57+
KeySecret = config('KeySecret', cast=str, default="阿里云账号AccessKeySecret")
58+
# 阿里云OSS Bucket的地域节点
59+
OSS_ENDPOINT = config('BUCKET_URL', cast=str, default="阿里云OSS Bucket的地域节点")
60+
# 阿里云OSS Bucket的BucketName
61+
BUCKET_NAME = config('BUCKET_NAME', cast=str, default="阿里云OSS Bucket的BucketName")
62+
# 访问文件的读取时长(s)
63+
ACCESSTIME = config('ACCESSTIME', cast=int, default=60)

storage.py

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,69 @@
33
from datetime import datetime
44
from pathlib import Path
55
from typing import BinaryIO
6-
76
from fastapi import UploadFile
8-
97
import settings
8+
import oss2
9+
10+
11+
class AliyunFileStore:
12+
def __init__(self):
13+
auth = oss2.Auth(settings.KeyId, settings.KeySecret)
14+
self.bucket = oss2.Bucket(auth, settings.OSS_ENDPOINT, settings.BUCKET_NAME)
15+
16+
def upload_file(self, upload_filepath, remote_filepath):
17+
self.bucket.put_object_from_file(remote_filepath, upload_filepath)
18+
19+
async def get_text(self, file: UploadFile, key: str):
20+
ext = file.filename.split('.')[-1]
21+
now = datetime.now()
22+
path = f"FileCodeBox/upload/{now.year}/{now.month}/{now.day}"
23+
text = f"{path}/{f'{key}.{ext}'}"
24+
return text
25+
26+
async def get_filepath(self, text: str):
27+
text = text.strip(f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/")
28+
url = self.bucket.sign_url('GET', text, settings.ACCESSTIME, slash_safe=True)
29+
return url
30+
31+
@staticmethod
32+
async def get_size(file: UploadFile):
33+
f = file.file
34+
f.seek(0, os.SEEK_END)
35+
size = f.tell()
36+
f.seek(0, os.SEEK_SET)
37+
return size
38+
39+
@staticmethod
40+
def _save(filepath, file: BinaryIO):
41+
with open(filepath, 'wb') as f:
42+
chunk_size = 256 * 1024
43+
chunk = file.read(chunk_size)
44+
while chunk:
45+
f.write(chunk)
46+
chunk = file.read(chunk_size)
47+
48+
async def save_file(self, file: UploadFile, remote_filepath: str):
49+
now = int(datetime.now().timestamp())
50+
upload_filepath = settings.DATA_ROOT+str(now)
51+
await asyncio.to_thread(self._save, upload_filepath, file.file)
52+
self.upload_file(upload_filepath,remote_filepath)
53+
await asyncio.to_thread(os.remove,upload_filepath)
54+
55+
async def delete_files(self, texts):
56+
tasks = [self.delete_file(text) for text in texts]
57+
await asyncio.gather(*tasks)
58+
59+
async def delete_file(self, text: str):
60+
text = text.strip(f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/")
61+
self.bucket.delete_object(text)
1062

1163

1264
class FileSystemStorage:
13-
DATA_ROOT = Path(settings.DATA_ROOT)
14-
STATIC_URL = settings.STATIC_URL
15-
NAME = "filesystem"
65+
def __init__(self):
66+
self.DATA_ROOT = Path(settings.DATA_ROOT)
67+
self.STATIC_URL = settings.STATIC_URL
68+
self.NAME = "filesystem"
1669

1770
async def get_filepath(self, text: str):
1871
return self.DATA_ROOT / text.lstrip(self.STATIC_URL + '/')
@@ -68,5 +121,6 @@ def judge_delete_folder(self, filepath):
68121

69122

70123
STORAGE_ENGINE = {
71-
"filesystem": FileSystemStorage
124+
"filesystem": FileSystemStorage,
125+
"aliyunsystem": AliyunFileStore
72126
}

utils.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import datetime
22
import random
33
import asyncio
4-
5-
import chardet
64
from sqlalchemy import or_, select, delete
75
from sqlalchemy.ext.asyncio.session import AsyncSession
86
import settings

0 commit comments

Comments
 (0)