-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathS3Manager.cs
182 lines (161 loc) · 7.01 KB
/
S3Manager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using MimeKit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace EmailClient
{
public sealed class S3Manager
{
private readonly AmazonS3Client s3Client;
private readonly EmailDatabase db;
public S3Manager(RegionEndpoint regionEndpoint, EmailDatabase db)
{
s3Client = new AmazonS3Client(regionEndpoint);
this.db = db;
}
public async Task<List<Email>> ListAndDownloadEmails(string bucketName)
{
try
{
ListObjectsV2Response response = await s3Client.ListObjectsV2Async(new ListObjectsV2Request
{
BucketName = bucketName
}).ConfigureAwait(false);
List<Task<Email>> tasks = new List<Task<Email>>();
foreach (var obj in response.S3Objects)
{
Console.WriteLine("Key:" + obj.Key);
Task<Email> task = Task.Run(async () =>
{ // Since we are I/O bound running each Db check and then reading the object will preform much better in parallel then waiting with a single thread
try
{
if (!db.EmailExists(obj.Key))
{
return await ReadEmailContent(bucketName, obj.Key);
}
}
catch (Exception e)
{
Console.WriteLine($"ListAndDownloadEmailsError Message:{e.Message} StackTrace:{e.StackTrace}");
}
return null;
});
tasks.Add(task);
}
// Waits for all tasks to complete, auto filters out null Task's. Then ensures each email is not null before ordering them in ascending order (oldest to newest)
List<Email> newEmails = (await Task.WhenAll(tasks)).Where(email => email != null).OrderBy(email => email.Date).ToList();
db.AddEmails(newEmails); // Db must be ordered from oldest to newest
newEmails.Reverse(); // Now reverse the array so that newest emails come first
return newEmails;
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred in ListAndDownloadEmails: {ex.Message}");
return new List<Email>(); // Return an empty list or handle as appropriate
}
}
private async Task<Email> ReadEmailContent(string bucketName, string keyName)
{
try
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = bucketName,
Key = keyName
};
using GetObjectResponse response = await s3Client.GetObjectAsync(request);
using Stream responseStream = response.ResponseStream;
using MimeMessage mimeMessage = MimeMessage.Load(responseStream);
string body = "";
if (!string.IsNullOrEmpty(mimeMessage.HtmlBody))
{
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(mimeMessage.HtmlBody);
var paragraphNodes = doc.DocumentNode.SelectNodes("//p");
if (paragraphNodes != null)
{
foreach (var node in paragraphNodes)
{
body += WebUtility.HtmlDecode(node.InnerText);
}
}
else
{ // Extracting all text nodes to ensure some data is retrieved.
var allTextNodes = doc.DocumentNode.SelectNodes("//text()");
if (allTextNodes != null)
{
foreach (var node in allTextNodes)
{
string text = WebUtility.HtmlDecode(node.InnerText);
if (!string.IsNullOrWhiteSpace(text)) body += text;
}
}
}
}
else if (!string.IsNullOrEmpty(mimeMessage.TextBody))
{ // If HtmlBody is null, fallback to TextBody
body = mimeMessage.TextBody;
}
return new Email
{
New = true,
Key = keyName,
Sender = string.Join("; ", mimeMessage.From.Mailboxes.Select(mb => mb.Address)),
Receiver = string.Join("; ", mimeMessage.To.Mailboxes.Select(mb => mb.Address)),
Subject = mimeMessage.Subject,
Body = body,
Date = mimeMessage.Date.DateTime
};
} catch (Exception e) { Console.WriteLine($"Failed ReadEmailContent Key:{keyName} Message:{e.Message} "); }
return null;
}
public async Task DeleteEmailFromS3Bucket(string bucketName, string emailKey)
{
DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest
{
BucketName = bucketName,
Key = emailKey
};
try
{ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/DeletingObjectVersions.html
var response = await s3Client.DeleteObjectAsync(deleteObjectRequest);
Console.WriteLine("Email deleted successfully from S3 bucket.");
}
catch (AmazonS3Exception e)
{
Console.WriteLine("Error encountered on server. Message:'{0}' when writing an object", e.Message);
}
}
private async Task DownloadFile(string bucketName, string keyName)
{
string localPath = Path.Combine("C:\\Users\\yozma\\Downloads", keyName);
var request = new GetObjectRequest
{
BucketName = bucketName,
Key = keyName
};
using GetObjectResponse response = await s3Client.GetObjectAsync(request);
using Stream responseStream = response.ResponseStream;
using FileStream fileStream = File.Create(localPath);
responseStream.CopyTo(fileStream);
}
}
public sealed class Email
{
public bool Checked { get; set; } = false;
public int Id { get; set; }
public string Key { get; set; }
public string Sender { get; set; }
public string Receiver { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public DateTime Date { get; set; }
public bool New { get; set; } = false;
}
}