Merge branch 'master' of https://git.aishufu.top/super/crawler-plugin
Build Backend JAR / build (push) Failing after 4s
Build Backend JAR / build (push) Failing after 4s
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
name: Build Backend JAR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: Version tag
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: maven:3.9-eclipse-temurin-21
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with Maven
|
||||
run: mvn clean package -DskipTests -q
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: backend-jar
|
||||
path: target/*.jar
|
||||
+111
-23
@@ -1,36 +1,124 @@
|
||||
import argparse
|
||||
import base64
|
||||
import re
|
||||
import time
|
||||
import alibabacloud_oss_v2 as oss
|
||||
import requests
|
||||
"""对象存储上传工具(MinIO,S3 协议兼容)
|
||||
|
||||
原实现基于阿里云 OSS SDK(alibabacloud_oss_v2),现改为 boto3 对接 MinIO。
|
||||
对外函数名与返回值保持不变,业务代码无需修改。
|
||||
"""
|
||||
|
||||
import base64
|
||||
import io
|
||||
import mimetypes
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
|
||||
import boto3
|
||||
import requests
|
||||
from botocore.config import Config
|
||||
|
||||
from config import (
|
||||
region,
|
||||
endpoint,
|
||||
bucket,
|
||||
file_url_pre,
|
||||
bucket_path,
|
||||
accessKeyId,
|
||||
accessKeySecret,
|
||||
)
|
||||
|
||||
_client = None
|
||||
_client_lock = threading.Lock()
|
||||
|
||||
|
||||
def get_client():
|
||||
"""获取(懒加载)S3 客户端,MinIO 必须使用 path-style 寻址"""
|
||||
global _client
|
||||
if _client is None:
|
||||
with _client_lock:
|
||||
if _client is None:
|
||||
_client = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=endpoint,
|
||||
aws_access_key_id=accessKeyId,
|
||||
aws_secret_access_key=accessKeySecret,
|
||||
region_name=region,
|
||||
config=Config(
|
||||
signature_version="s3v4",
|
||||
s3={"addressing_style": "path"}, # MinIO 必须
|
||||
retries={"max_attempts": 3, "mode": "standard"},
|
||||
),
|
||||
)
|
||||
return _client
|
||||
|
||||
|
||||
def _guess_content_type(key: str) -> str:
|
||||
content_type, _ = mimetypes.guess_type(key)
|
||||
return content_type or "application/octet-stream"
|
||||
|
||||
|
||||
def get_presigned_url(key: str, expires: int = 7 * 24 * 3600) -> str:
|
||||
"""生成临时访问链接(存储桶未开放匿名读时使用),默认有效 7 天"""
|
||||
return get_client().generate_presigned_url(
|
||||
"get_object",
|
||||
Params={"Bucket": bucket, "Key": key.lstrip("/")},
|
||||
ExpiresIn=expires,
|
||||
)
|
||||
|
||||
from config import region, endpoint, bucket, file_url_pre, bucket_path
|
||||
|
||||
|
||||
def upload_file(file_content: bytes, key: str):
|
||||
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
|
||||
cfg = oss.config.load_default()
|
||||
cfg.credentials_provider = credentials_provider
|
||||
cfg.region = region
|
||||
cfg.endpoint = endpoint
|
||||
client = oss.Client(cfg)
|
||||
|
||||
result = client.put_object(
|
||||
oss.PutObjectRequest(
|
||||
bucket=bucket, # 存储空间名称
|
||||
key=key, # 对象名称
|
||||
body=file_content # 读取文件内容
|
||||
)
|
||||
"""上传字节内容到 MinIO,返回可访问链接"""
|
||||
key = key.lstrip("/")
|
||||
client = get_client()
|
||||
client.put_object(
|
||||
Bucket=bucket, # 存储桶名称
|
||||
Key=key, # 对象名称
|
||||
Body=io.BytesIO(file_content) if isinstance(file_content, (bytes, bytearray)) else file_content,
|
||||
ContentType=_guess_content_type(key),
|
||||
)
|
||||
# print(result)
|
||||
return file_url_pre + key
|
||||
|
||||
|
||||
def upload_data_url(data_url: str, prefix: str = "history", key_hint: str = "") -> str:
|
||||
"""
|
||||
将 base64 data URL 上传到对象存储,返回图片链接
|
||||
data_url: data:image/png;base64,xxxx 或 data:image/jpeg;base64,xxxx
|
||||
prefix: 对象 key 前缀
|
||||
key_hint: 可选后缀避免重名,如 "_0", "_1"
|
||||
"""
|
||||
match = re.match(r'data:image/(\w+);base64,(.+)', data_url)
|
||||
if not match:
|
||||
raise ValueError('无效的 data URL 格式')
|
||||
ext = 'png' if match.group(1).lower() in ('png', 'webp') else 'jpg'
|
||||
file_content = base64.b64decode(match.group(2))
|
||||
ts = int(time.time() * 1000)
|
||||
key = f"{bucket_path}{prefix}/{ts}{key_hint}.{ext}"
|
||||
return upload_file(file_content, key)
|
||||
|
||||
|
||||
def upload_data_urls(data_urls: list, prefix: str = "history") -> list:
|
||||
"""批量上传 base64 图片到对象存储,返回图片链接列表"""
|
||||
urls = []
|
||||
ts = int(time.time() * 1000)
|
||||
for i, data_url in enumerate(data_urls or []):
|
||||
if not data_url or not isinstance(data_url, str):
|
||||
continue
|
||||
if not data_url.startswith("http"):
|
||||
match = re.match(r'data:image/(\w+);base64,(.+)', data_url)
|
||||
if not match:
|
||||
continue
|
||||
ext = 'png' if match.group(1).lower() in ('png', 'webp') else 'jpg'
|
||||
file_content = base64.b64decode(match.group(2))
|
||||
else:
|
||||
file_content = requests.get(data_url).content
|
||||
ext = "png"
|
||||
key = f"{bucket_path}{prefix}/{ts}_{i}.{ext}"
|
||||
urls.append(upload_file(file_content, key))
|
||||
return urls
|
||||
|
||||
|
||||
# 脚本入口,当文件被直接运行时调用main函数
|
||||
if __name__ == "__main__":
|
||||
with open("测试图片数据/IMG_2685.JPG", "rb") as f:
|
||||
with open("D:\\pack\\nanri\\main.dist\\SHUFU.zip", "rb") as f:
|
||||
file_content = f.read()
|
||||
upload_file(file_content,key=bucket_path+"test.png")
|
||||
res = upload_file(file_content, key=bucket_path + "versions/1.0.46.zip")
|
||||
print(res)
|
||||
|
||||
@@ -11,6 +11,7 @@ import zipfile
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from urllib.parse import quote
|
||||
import traceback
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
@@ -2729,6 +2730,7 @@ def upload_version():
|
||||
'msg': '上传成功',
|
||||
})
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
|
||||
|
||||
+25
-3
@@ -63,9 +63,31 @@ backend_java_base_url, backend_java_base_url_source = _get_env(
|
||||
default="http://127.0.0.1:18080/",
|
||||
)
|
||||
backend_java_base_url = backend_java_base_url.rstrip("/")
|
||||
os.environ["OSS_ACCESS_KEY_ID"] = accessKeyId
|
||||
os.environ["OSS_ACCESS_KEY_SECRET"] = accessKeySecret
|
||||
os.environ["SECRET_KEY"] = "ddffc7c1d02121d9554d7b080b2511b6"
|
||||
# os.environ["OSS_ACCESS_KEY_ID"] = accessKeyId
|
||||
# os.environ["OSS_ACCESS_KEY_SECRET"] = accessKeySecret
|
||||
# os.environ["SECRET_KEY"] = "ddffc7c1d02121d9554d7b080b2511b6"
|
||||
|
||||
|
||||
# ==================== 对象存储配置(MinIO,S3 协议兼容) ====================
|
||||
# MinIO 默认 region 为 us-east-1
|
||||
region = os.getenv("oss_region", "us-east-1")
|
||||
# S3 API 地址(域名 http://api.aishufu.top,或直连 http://47.110.241.161:9000)
|
||||
endpoint = os.getenv("oss_endpoint", "https://oss.aishufu.top")
|
||||
bucket = os.getenv("oss_bucket", "client")
|
||||
accessKeyId = os.getenv("oss_access_key_id", "minioadmin")
|
||||
accessKeySecret = os.getenv("oss_access_key_secret", "Minio@2024Secure")
|
||||
bucket_path = os.getenv("oss_bucket_path", "nanri-image/")
|
||||
|
||||
# 对外访问地址(可与上传用 endpoint 不同,例如走 CDN/域名),MinIO 为 path-style:{host}/{bucket}/{key}
|
||||
_public_host = os.getenv("oss_public_host", endpoint).rstrip("/")
|
||||
file_url_pre = f"{_public_host}/{bucket}/"
|
||||
|
||||
|
||||
os.environ['OSS_ACCESS_KEY_ID'] = accessKeyId
|
||||
os.environ['OSS_ACCESS_KEY_SECRET'] = accessKeySecret
|
||||
os.environ.setdefault('AWS_ACCESS_KEY_ID', accessKeyId)
|
||||
os.environ.setdefault('AWS_SECRET_ACCESS_KEY', accessKeySecret)
|
||||
|
||||
|
||||
|
||||
debug = True
|
||||
|
||||
Reference in New Issue
Block a user