Skip to content

Commit fdab693

Browse files
feat:Add Tencent Cloud object storage support
1 parent a283abb commit fdab693

15 files changed

+1212
-1
lines changed

BotSharp.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.FileHandler
101101
EndProject
102102
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.Planner", "src\Plugins\BotSharp.Plugin.Planner\BotSharp.Plugin.Planner.csproj", "{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}"
103103
EndProject
104+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FileStorages", "FileStorages", "{38B37C0D-1930-4D47-BCBF-E358EC1096B1}"
105+
EndProject
106+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.TencentCos", "src\Plugins\BotSharp.Plugin.TencentCos\BotSharp.Plugin.TencentCos.csproj", "{BF029B0A-768B-43A1-8D91-E70B95505716}"
107+
EndProject
104108
Global
105109
GlobalSection(SolutionConfigurationPlatforms) = preSolution
106110
Debug|Any CPU = Debug|Any CPU
@@ -413,6 +417,14 @@ Global
413417
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|Any CPU.Build.0 = Release|Any CPU
414418
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|x64.ActiveCfg = Release|Any CPU
415419
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|x64.Build.0 = Release|Any CPU
420+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
421+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|Any CPU.Build.0 = Debug|Any CPU
422+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|x64.ActiveCfg = Debug|Any CPU
423+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|x64.Build.0 = Debug|Any CPU
424+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|Any CPU.ActiveCfg = Release|Any CPU
425+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|Any CPU.Build.0 = Release|Any CPU
426+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x64.ActiveCfg = Release|Any CPU
427+
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x64.Build.0 = Release|Any CPU
416428
EndGlobalSection
417429
GlobalSection(SolutionProperties) = preSolution
418430
HideSolutionNode = FALSE
@@ -461,6 +473,8 @@ Global
461473
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
462474
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
463475
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
476+
{38B37C0D-1930-4D47-BCBF-E358EC1096B1} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
477+
{BF029B0A-768B-43A1-8D91-E70B95505716} = {38B37C0D-1930-4D47-BCBF-E358EC1096B1}
464478
EndGlobalSection
465479
GlobalSection(ExtensibilityGlobals) = postSolution
466480
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(TargetFramework)</TargetFramework>
5+
<LangVersion>$(LangVersion)</LangVersion>
6+
<Nullable>enable</Nullable>
7+
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
8+
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
9+
<GenerateDocumentationFile>$(GenerateDocumentationFile)</GenerateDocumentationFile>
10+
<OutputPath>$(SolutionDir)packages</OutputPath>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="Tencent.QCloud.Cos.Sdk" Version="5.4.39" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\..\Infrastructure\BotSharp.Core\BotSharp.Core.csproj" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
using COSXML;
2+
using COSXML.CosException;
3+
using COSXML.Model.Bucket;
4+
using COSXML.Model.Object;
5+
using COSXML.Model.Tag;
6+
7+
namespace BotSharp.Plugin.TencentCos.Modules
8+
{
9+
public class BucketClient
10+
{
11+
private readonly CosXmlServer _cosXml;
12+
private readonly string _fullBucketName;
13+
private readonly string _appId;
14+
private readonly string _region;
15+
public BucketClient(CosXmlServer cosXml, string fullBucketName, string appId, string region)
16+
{
17+
_cosXml = cosXml;
18+
_fullBucketName = fullBucketName;
19+
_appId = appId;
20+
_region = region;
21+
}
22+
23+
public bool UploadBytes(string key, byte[] fileData)
24+
{
25+
var result = false;
26+
try
27+
{
28+
var request = new PutObjectRequest(_fullBucketName, key, fileData);
29+
30+
var resultData = _cosXml.PutObject(request);
31+
32+
if (resultData != null && resultData.IsSuccessful())
33+
{
34+
result = true;
35+
}
36+
}
37+
catch (CosClientException clientEx)
38+
{
39+
throw new Exception(clientEx.Message);
40+
}
41+
catch (CosServerException serverEx)
42+
{
43+
throw new Exception(serverEx.Message);
44+
}
45+
return result;
46+
}
47+
48+
public bool UploadStream(string key, Stream stream)
49+
{
50+
var result = false;
51+
try
52+
{
53+
var request = new PutObjectRequest(_fullBucketName, key, stream);
54+
55+
var resultData = _cosXml.PutObject(request);
56+
57+
if (resultData != null && resultData.IsSuccessful())
58+
{
59+
result = true;
60+
}
61+
}
62+
catch (CosClientException clientEx)
63+
{
64+
throw new Exception(clientEx.Message);
65+
}
66+
catch (CosServerException serverEx)
67+
{
68+
throw new Exception(serverEx.Message);
69+
}
70+
return result;
71+
}
72+
73+
public (string, byte[]) DownloadDirDefaultFileBytes(string dir)
74+
{
75+
try
76+
{
77+
var request = new GetBucketRequest(_fullBucketName);
78+
request.SetPrefix($"{dir.TrimEnd('/')}/");
79+
request.SetDelimiter("/");
80+
81+
var result = _cosXml.GetBucket(request);
82+
83+
var info = result.listBucket;
84+
85+
var objects = info.contentsList;
86+
87+
var objectData = objects.FirstOrDefault(o => o.size > 0);
88+
89+
if (objectData != null)
90+
{
91+
var fileName = Path.GetFileName(objectData.key);
92+
var fileBytes = DownloadFileBytes(objectData.key);
93+
return (fileName, fileBytes);
94+
}
95+
}
96+
catch (CosClientException clientEx)
97+
{
98+
throw new Exception(clientEx.Message);
99+
}
100+
catch (CosServerException serverEx)
101+
{
102+
throw new Exception(serverEx.Message);
103+
}
104+
return (string.Empty, Array.Empty<byte>());
105+
}
106+
107+
public byte[] DownloadFileBytes(string key)
108+
{
109+
try
110+
{
111+
var request = new GetObjectBytesRequest(_fullBucketName, key);
112+
var result = _cosXml.GetObject(request);
113+
if (result != null)
114+
{
115+
return result.content;
116+
}
117+
}
118+
catch (CosClientException clientEx)
119+
{
120+
throw new Exception(clientEx.Message);
121+
}
122+
catch (CosServerException serverEx)
123+
{
124+
throw new Exception(serverEx.Message);
125+
}
126+
return Array.Empty<byte>();
127+
}
128+
129+
public List<string> GetDirFiles(string dir)
130+
{
131+
try
132+
{
133+
var request = new GetBucketRequest(_fullBucketName);
134+
request.SetPrefix($"{dir.TrimEnd('/')}/");
135+
request.SetDelimiter("/");
136+
137+
var result = _cosXml.GetBucket(request);
138+
139+
var info = result.listBucket;
140+
141+
var objects = info.contentsList;
142+
143+
return objects.Where(o => o.size > 0).Select(o => o.key).ToList();
144+
145+
}
146+
catch (CosClientException clientEx)
147+
{
148+
throw new Exception(clientEx.Message);
149+
}
150+
catch (CosServerException serverEx)
151+
{
152+
throw new Exception(serverEx.Message);
153+
}
154+
}
155+
156+
public List<string> GetDirectories(string dir)
157+
{
158+
var dirs = new List<string>();
159+
try
160+
{
161+
var request = new GetBucketRequest(_fullBucketName);
162+
request.SetPrefix($"{dir.TrimEnd('/')}/");
163+
request.SetDelimiter("/");
164+
165+
var result = _cosXml.GetBucket(request);
166+
167+
var info = result.listBucket;
168+
169+
var objects = info.contentsList;
170+
171+
var list = objects.Where(o => o.size == 0 && o.key != dir).Select(o => o.key).ToList();
172+
173+
dirs.AddRange(list);
174+
175+
var commonPrefixes = info.commonPrefixesList;
176+
177+
dirs.AddRange(commonPrefixes.Select(c => c.prefix));
178+
179+
return dirs;
180+
181+
}
182+
catch (CosClientException clientEx)
183+
{
184+
throw new Exception(clientEx.Message);
185+
}
186+
catch (CosServerException serverEx)
187+
{
188+
throw new Exception(serverEx.Message);
189+
}
190+
}
191+
192+
public bool DirExists(string dir)
193+
{
194+
try
195+
{
196+
var request = new GetBucketRequest(_fullBucketName);
197+
request.SetPrefix($"{dir.TrimEnd('/')}/");
198+
request.SetDelimiter("/");
199+
200+
var result = _cosXml.GetBucket(request);
201+
202+
var info = result.listBucket;
203+
204+
var objects = info.contentsList;
205+
206+
return objects.Count > 0 || info?.commonPrefixesList.Count > 0;
207+
208+
}
209+
catch (CosClientException clientEx)
210+
{
211+
throw new Exception(clientEx.Message);
212+
}
213+
catch (CosServerException serverEx)
214+
{
215+
throw new Exception(serverEx.Message);
216+
}
217+
}
218+
219+
public void MoveDir(string sourceDir, string destDir)
220+
{
221+
var listRequest = new GetBucketRequest(_fullBucketName);
222+
223+
listRequest.SetPrefix($"{sourceDir.TrimEnd('/')}/");
224+
var listResult = _cosXml.GetBucket(listRequest);
225+
226+
var info = listResult.listBucket;
227+
228+
var objects = info.contentsList;
229+
230+
foreach (var obj in objects)
231+
{
232+
string sourceKey = obj.key;
233+
string destinationKey = $"{destDir.TrimEnd('/')}/{sourceKey.Substring(sourceDir.Length)}";
234+
235+
var copySource = new CopySourceStruct(_appId, _fullBucketName, _region, sourceKey);
236+
237+
var request = new CopyObjectRequest(_fullBucketName, destinationKey);
238+
239+
request.SetCopySource(copySource);
240+
try
241+
{
242+
243+
var result = _cosXml.CopyObject(request);
244+
var deleteRequest = new DeleteObjectRequest(_fullBucketName, sourceKey);
245+
var deleteResult = _cosXml.DeleteObject(deleteRequest);
246+
}
247+
catch (CosClientException clientEx)
248+
{
249+
throw new Exception(clientEx.Message);
250+
}
251+
catch (CosServerException serverEx)
252+
{
253+
throw new Exception(serverEx.Message);
254+
}
255+
}
256+
257+
}
258+
259+
public void DeleteDir(string dir)
260+
{
261+
try
262+
{
263+
string nextMarker = null;
264+
do
265+
{
266+
var listRequest = new GetBucketRequest(_fullBucketName);
267+
listRequest.SetPrefix($"{dir.TrimEnd('/')}/");
268+
listRequest.SetMarker(nextMarker);
269+
var listResult = _cosXml.GetBucket(listRequest);
270+
var info = listResult.listBucket;
271+
List<ListBucket.Contents> objects = info.contentsList;
272+
nextMarker = info.nextMarker;
273+
274+
var deleteRequest = new DeleteMultiObjectRequest(_fullBucketName);
275+
276+
deleteRequest.SetDeleteQuiet(false);
277+
var deleteObjects = new List<string>();
278+
foreach (var content in objects)
279+
{
280+
deleteObjects.Add(content.key);
281+
}
282+
deleteRequest.SetObjectKeys(deleteObjects);
283+
284+
var deleteResult = _cosXml.DeleteMultiObjects(deleteRequest);
285+
286+
} while (nextMarker != null);
287+
}
288+
catch (CosClientException clientEx)
289+
{
290+
throw new Exception(clientEx.Message);
291+
}
292+
catch (CosServerException serverEx)
293+
{
294+
throw new Exception(serverEx.Message);
295+
}
296+
}
297+
298+
public bool DoesObjectExist(string key)
299+
{
300+
var request = new DoesObjectExistRequest(_fullBucketName, key);
301+
return _cosXml.DoesObjectExist(request);
302+
}
303+
}
304+
}

0 commit comments

Comments
 (0)