支持天翼云文件上传

This commit is contained in:
梁朝伟 2023-11-21 15:21:58 +08:00
parent 4e6c198648
commit d199ace4ed
8 changed files with 306 additions and 3 deletions

16
lib/utils/cos/ctyun.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
import { ED, BRC, FRC } from '../../types/RuntimeCxt';
import Cos from "../../types/Cos";
import { OpSchema } from '../../oak-app-domain/ExtraFile/Schema';
export default class CTYun implements Cos<ED, BRC, FRC> {
name: string;
autoInform(): boolean;
private formKey;
formUploadMeta(extraFile: OpSchema, context: BRC): Promise<void>;
upload(extraFile: OpSchema, uploadFn: (file: File | string, name: string, // 文件的part name
uploadUrl: string, // 上传的url
formData: Record<string, any>, // 上传的其它part参数
autoInform?: boolean) => Promise<any>, file: string | File): Promise<void>;
composeFileUrl(extraFile: ED['extraFile']['OpSchema'], context: FRC, style?: string): string;
checkWhetherSuccess(extraFile: OpSchema, context: BRC): Promise<boolean>;
removeFile(extraFile: OpSchema, context: BRC): Promise<void>;
}

96
lib/utils/cos/ctyun.js Normal file
View File

@ -0,0 +1,96 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = require("oak-domain/lib/utils/assert");
const getContextConfig_1 = require("../getContextConfig");
const Exception_1 = require("../../types/Exception");
const oak_domain_1 = require("oak-domain");
class CTYun {
name = 'ctyun';
autoInform() {
return false;
}
formKey(extraFile) {
const { id, extension, objectId } = extraFile;
(0, assert_1.assert)(objectId);
return `extraFile/${objectId}${extension ? '.' + extension : ''}`;
}
async formUploadMeta(extraFile, context) {
const { bucket } = extraFile;
// 构造文件上传所需的key
const key = this.formKey(extraFile);
const { instance, config } = (0, getContextConfig_1.getConfig)(context, 'Cos', 'ctyun');
const { buckets } = config;
let bucket2 = bucket;
if (!bucket2) {
const { defaultBucket } = config;
bucket2 = defaultBucket;
}
(0, assert_1.assert)(bucket2);
const b = buckets.find(ele => ele.name === bucket2);
(0, assert_1.assert)(b, `${bucket2}不是一个有效的桶配置`);
Object.assign(extraFile, {
bucket: bucket2,
uploadMeta: instance.getUploadInfo(bucket2, b.zone, key),
});
}
async upload(extraFile, uploadFn, file) {
const uploadMeta = extraFile.uploadMeta;
let result;
try {
result = await uploadFn(file, 'file', uploadMeta.uploadHost, {
Key: uploadMeta.key,
Policy: uploadMeta.policy,
AWSAccessKeyId: uploadMeta.accessKey,
signature: uploadMeta.signature,
}, true);
}
catch (err) {
// 网络错误
throw new oak_domain_1.OakNetworkException('网络异常,请求失败');
}
let isSuccess = false;
if (process.env.OAK_PLATFORM === 'wechatMp') {
// 小程序端上传 使用wx.uploadFile
if (result.errMsg === 'uploadFile:ok') {
const jsonData = JSON.parse(result.data);
isSuccess = !!jsonData.key;
}
}
else {
isSuccess = !!(result.success === true || result.key);
}
// 解析回调
if (isSuccess) {
return;
}
else {
throw new Exception_1.OakUploadException('图片上传七牛失败');
}
}
composeFileUrl(extraFile, context, style) {
const { config } = (0, getContextConfig_1.getConfig)(context, 'Cos', 'qiniu');
if (config) {
let bucket = config.buckets.find((ele) => ele.name === extraFile.bucket);
if (bucket) {
const { domain, protocol } = bucket;
let protocol2 = protocol;
if (protocol instanceof Array) {
// protocol存在https 说明域名有证书
const index = protocol.includes('https')
? protocol.findIndex((ele) => ele === 'https')
: 0;
protocol2 = protocol[index];
}
return `${protocol2}://${domain}/${this.formKey(extraFile)}`;
}
}
return '';
}
async checkWhetherSuccess(extraFile, context) {
return true;
}
async removeFile(extraFile, context) {
}
}
exports.default = CTYun;
;

View File

@ -12,6 +12,7 @@ type BeforeCommit =
| undefined;
export default OakComponent({
isList: false,
formData({ features }) {
const ids: string[] = this.getEfIds();
const states = ids.map((id) => features.extraFile.getFileState(id));

View File

@ -1,10 +1,15 @@
import { QiniuZone } from 'oak-external-sdk';
import { QiniuZone, CTYunZone } from 'oak-external-sdk';
export type QiniuCloudConfig = {
accessKey: string;
secretKey: string;
};
export type CTYunConfig = {
accessKey: string;
secretKey: string;
}
export type QiniuLiveConfig = {
accessKey: string;
liveHost: string; // 七牛直播云接口域名
@ -27,6 +32,17 @@ export type QiniuCosConfig = {
defaultBucket: string; // 默认上传桶
}
export type CTYunCosConfig = {
accessKey: string;
buckets: { // 七牛配置的桶信息
zone: CTYunZone; // 七牛存储区域(https://developer.qiniu.com/kodo/1671/region-endpoint-fq)
name: string;
domain: string;
protocol: string | string[];
}[];
defaultBucket: string; // 默认上传桶
}
export type AmapMapConfig = {
webApiKey: string;
};
@ -84,10 +100,12 @@ export type Config = {
ali?: AliCloudConfig[];
tencent?: TencentCloudConfig[];
qiniu?: QiniuCloudConfig[];
ctyun?: CTYunConfig[];
amap?: AmapCloudConfig[];
};
Cos?: {
qiniu?: QiniuCosConfig;
ctyun?: CTYunCosConfig;
};
Live?: {
qiniu?: QiniuLiveConfig;
@ -109,5 +127,5 @@ export type Config = {
};
};
export type Origin = 'ali' | 'tencent' | 'qiniu' | 'amap';
export type Origin = 'ali' | 'tencent' | 'qiniu' | 'amap' | 'ctyun';
export type Service = 'Map' | 'Cos' | 'Live' | 'Sms';

View File

@ -4,6 +4,15 @@ export type QiniuUploadInfo = {
uploadHost: string;
bucket: string;
};
export type CTYunUploadInfo = {
key?: string;
accessKey: string;
uploadToken: string;
uploadHost: string;
policy: string;
signature: string;
bucket: string;
};
export type AliyunUploadInfo = {
key?: string;

142
src/utils/cos/ctyun.ts Normal file
View File

@ -0,0 +1,142 @@
import { ED, BRC, FRC } from '../../types/RuntimeCxt';
import { assert } from 'oak-domain/lib/utils/assert';
import Cos from "../../types/Cos";
import { OpSchema } from '../../oak-app-domain/ExtraFile/Schema';
import { CTYunUploadInfo } from '../../types/Upload';
import { getConfig } from '../getContextConfig';
import { CTYunCosConfig } from '../../types/Config';
import { CTYunInstance } from 'oak-external-sdk';
import { urlSafeBase64Encode } from '../sign';
import { OakUploadException } from '../../types/Exception';
import { OakExternalException, OakNetworkException } from 'oak-domain';
export default class CTYun implements Cos<ED, BRC, FRC> {
name = 'ctyun';
autoInform(): boolean {
return false;
}
private formKey(extraFile: OpSchema) {
const { id, extension, objectId } = extraFile;
assert(objectId);
return `extraFile/${objectId}${extension ? '.' + extension : ''}`;
}
async formUploadMeta(
extraFile: OpSchema,
context: BRC
) {
const { bucket } = extraFile;
// 构造文件上传所需的key
const key = this.formKey(extraFile);
const { instance, config } = getConfig<ED, BRC, FRC>(context, 'Cos', 'ctyun');
const { buckets } = config as CTYunCosConfig;
let bucket2 = bucket;
if (!bucket2) {
const { defaultBucket } = config as CTYunCosConfig;
bucket2 = defaultBucket!;
}
assert(bucket2);
const b = buckets.find(ele => ele.name === bucket2);
assert(b, `${bucket2}不是一个有效的桶配置`);
Object.assign(extraFile, {
bucket: bucket2,
uploadMeta: (instance as CTYunInstance).getUploadInfo(
bucket2,
b.zone,
key
),
});
}
async upload(
extraFile: OpSchema,
uploadFn: (
file: File | string,
name: string, // 文件的part name
uploadUrl: string, // 上传的url
formData: Record<string, any>, // 上传的其它part参数
autoInform?: boolean // 上传成功是否会自动通知server若不会则需要前台显式通知
) => Promise<any>,
file: string | File
) {
const uploadMeta = extraFile.uploadMeta! as CTYunUploadInfo;
let result;
try {
result = await uploadFn(
file,
'file',
uploadMeta.uploadHost,
{
Key: uploadMeta.key,
Policy: uploadMeta.policy,
AWSAccessKeyId: uploadMeta.accessKey,
signature: uploadMeta.signature,
},
true
);
} catch (err) {
// 网络错误
throw new OakNetworkException('网络异常,请求失败');
}
let isSuccess = false;
if (process.env.OAK_PLATFORM === 'wechatMp') {
// 小程序端上传 使用wx.uploadFile
if (result.errMsg === 'uploadFile:ok') {
const jsonData = JSON.parse(result.data);
isSuccess = !!jsonData.key;
}
}
else {
isSuccess = !!(result.success === true || result.key);
}
// 解析回调
if (isSuccess) {
return;
} else {
throw new OakUploadException('图片上传七牛失败');
}
}
composeFileUrl(
extraFile: ED['extraFile']['OpSchema'],
context: FRC,
style?: string,
) {
const { config } = getConfig<ED, BRC, FRC>(context, 'Cos', 'qiniu');
if (config) {
let bucket = (config.buckets as CTYunCosConfig['buckets']).find((ele) => ele.name === extraFile.bucket!);
if (bucket) {
const { domain, protocol } = bucket!;
let protocol2 = protocol;
if (protocol instanceof Array) {
// protocol存在https 说明域名有证书
const index = (protocol as ['http', 'https']).includes(
'https'
)
? protocol.findIndex((ele) => ele === 'https')
: 0;
protocol2 = protocol[index];
}
return `${protocol2}://${domain}/${this.formKey(extraFile)}`;
}
}
return '';
}
async checkWhetherSuccess(
extraFile: OpSchema,
context: BRC
) {
return true;
}
async removeFile(extraFile: OpSchema, context: BRC) {
}
};

View File

@ -9,13 +9,16 @@ import { ED, BRC, FRC } from '../../types/RuntimeCxt';
import Cos from '../../types/Cos';
import Qiniu from './qiniu';
import Wechat from './wechat';
import CTYun from './ctyun';
const ctyun = new CTYun();
const qiniu = new Qiniu();
const wechat = new Wechat();
const CosDict: Record<string, any> = {
[qiniu.name]: qiniu,
[wechat.name]: wechat,
[ctyun.name]: ctyun,
};
/**

View File

@ -1,6 +1,6 @@
import { assert } from 'oak-domain/lib/utils/assert';
import { OakDataException } from 'oak-domain/lib/types/Exception';
import { AmapSDK, QiniuSDK } from 'oak-external-sdk';
import { AmapSDK, QiniuSDK, CTYunSDk } from 'oak-external-sdk';
import {
AliCloudConfig,
AmapCloudConfig,
@ -9,6 +9,7 @@ import {
QiniuCloudConfig,
Service,
TencentCloudConfig,
CTYunConfig
} from '../types/Config';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
import { FrontendRuntimeContext, AspectDict } from '../context/FrontendRuntimeContext';
@ -87,6 +88,23 @@ export function getConfig<
config: originConfig,
};
}
case 'ctyun': {
const ctyunAccount = (
originCloudAccounts as CTYunConfig[]
).find((ele) => ele.accessKey === originConfig.accessKey);
assert(
ctyunAccount,
`调用的服务${service}${origin}找不到相应的云平台帐号,请联系管理员`
);
const ctyunInstance = CTYunSDk.getInstance(
ctyunAccount!.accessKey,
ctyunAccount!.secretKey,
);
return {
instance: ctyunInstance,
config: originConfig,
};
}
default: {
assert(origin === 'amap');
const amapAccount = (originCloudAccounts as AmapCloudConfig[]).find(