Skip to content

Commit 6360f20

Browse files
Begun implementing SNS support
1 parent f4ff29f commit 6360f20

File tree

14 files changed

+548
-9
lines changed

14 files changed

+548
-9
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright © Vincent Bengtsson & Contributors 2022-2023
7+
* https://github.com/Visual-Vincent/GuiStack
8+
*/
9+
10+
using System;
11+
using Amazon;
12+
using Amazon.Runtime;
13+
using Amazon.SimpleNotificationService;
14+
15+
namespace GuiStack.Authentication.AWS
16+
{
17+
public class SNSAuthenticator : Authenticator<AWSCredentials, AmazonSimpleNotificationServiceClient>
18+
{
19+
public override AmazonSimpleNotificationServiceClient Authenticate(AWSCredentials credentials)
20+
{
21+
var config = new AmazonSimpleNotificationServiceConfig() {
22+
AuthenticationRegion = AWSConfigs.AWSRegion,
23+
MaxErrorRetry = 1
24+
};
25+
26+
string endpointUrl = Environment.GetEnvironmentVariable("AWS_SNS_ENDPOINT_URL");
27+
28+
if(!string.IsNullOrWhiteSpace(endpointUrl))
29+
config.ServiceURL = endpointUrl;
30+
31+
return new AmazonSimpleNotificationServiceClient(credentials, config);
32+
}
33+
34+
public override AWSCredentials GetCredentials()
35+
{
36+
return new BasicAWSCredentials(
37+
Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID"),
38+
Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY")
39+
);
40+
}
41+
}
42+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright © Vincent Bengtsson & Contributors 2022-2023
7+
* https://github.com/Visual-Vincent/GuiStack
8+
*/
9+
10+
using System;
11+
using System.Net;
12+
using System.Threading.Tasks;
13+
using Amazon.SimpleNotificationService;
14+
using GuiStack.Extensions;
15+
using GuiStack.Models;
16+
using GuiStack.Repositories;
17+
using Microsoft.AspNetCore.Mvc;
18+
19+
namespace GuiStack.Controllers.SNS
20+
{
21+
[ApiController]
22+
[Route("api/" + nameof(SNS) + "/[controller]")]
23+
public class TopicsController : Controller
24+
{
25+
private ISNSRepository snsRepository;
26+
27+
public TopicsController(ISNSRepository snsRepository)
28+
{
29+
this.snsRepository = snsRepository;
30+
}
31+
32+
private ActionResult HandleException(Exception ex)
33+
{
34+
if(ex == null)
35+
throw new ArgumentNullException(nameof(ex));
36+
37+
if(ex is AmazonSimpleNotificationServiceException snsEx)
38+
{
39+
if(snsEx.StatusCode == HttpStatusCode.NotFound)
40+
return StatusCode((int)snsEx.StatusCode, new { error = snsEx.Message });
41+
42+
Console.Error.WriteLine(snsEx);
43+
return StatusCode((int)HttpStatusCode.InternalServerError, new { error = ex.Message });
44+
}
45+
46+
Console.Error.WriteLine(ex);
47+
return StatusCode((int)HttpStatusCode.InternalServerError);
48+
}
49+
50+
[HttpPut]
51+
[Consumes("application/json")]
52+
public async Task<ActionResult> CreateTopic([FromBody] SNSCreateTopicModel model)
53+
{
54+
if(string.IsNullOrWhiteSpace(model.TopicName))
55+
return StatusCode((int)HttpStatusCode.BadRequest);
56+
57+
try
58+
{
59+
await snsRepository.CreateTopicAsync(model);
60+
return Ok();
61+
}
62+
catch(Exception ex)
63+
{
64+
return HandleException(ex);
65+
}
66+
}
67+
68+
[HttpDelete("{topicArn}")]
69+
public async Task<ActionResult> DeleteTopic([FromRoute] string topicArn)
70+
{
71+
if(string.IsNullOrWhiteSpace(topicArn))
72+
return StatusCode((int)HttpStatusCode.BadRequest);
73+
74+
topicArn = topicArn.DecodeRouteParameter();
75+
76+
try
77+
{
78+
await snsRepository.DeleteTopicAsync(topicArn);
79+
return Ok();
80+
}
81+
catch(Exception ex)
82+
{
83+
return HandleException(ex);
84+
}
85+
}
86+
}
87+
}

GuiStack/GuiStack.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="AWSSDK.Core" Version="3.7.6.1" />
11-
<PackageReference Include="AWSSDK.S3" Version="3.7.7.16" />
12-
<PackageReference Include="AWSSDK.SQS" Version="3.7.2.15" />
10+
<PackageReference Include="AWSSDK.Core" Version="3.7.106.33" />
11+
<PackageReference Include="AWSSDK.S3" Version="3.7.104.12" />
12+
<PackageReference Include="AWSSDK.SimpleNotificationService" Version="3.7.101.62" />
13+
<PackageReference Include="AWSSDK.SQS" Version="3.7.102.1" />
1314
<PackageReference Include="Google.Protobuf" Version="3.20.0" />
1415
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.9" />
1516
</ItemGroup>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright © Vincent Bengtsson & Contributors 2022-2023
7+
* https://github.com/Visual-Vincent/GuiStack
8+
*/
9+
10+
using System;
11+
12+
namespace GuiStack.Models
13+
{
14+
public class SNSCreateTopicModel
15+
{
16+
public string TopicName { get; set; }
17+
public bool IsFifo { get; set; }
18+
}
19+
}

GuiStack/Models/SNSTopic.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright © Vincent Bengtsson & Contributors 2022-2023
7+
* https://github.com/Visual-Vincent/GuiStack
8+
*/
9+
10+
using System;
11+
using Amazon;
12+
13+
namespace GuiStack.Models
14+
{
15+
public class SNSTopic
16+
{
17+
public string Name { get; set; }
18+
public Arn Arn { get; set; }
19+
20+
public SNSTopic()
21+
{
22+
}
23+
24+
public SNSTopic(string arn)
25+
{
26+
Arn = Arn.Parse(arn);
27+
Name = Uri.UnescapeDataString(Arn.Resource);
28+
}
29+
}
30+
}

GuiStack/Pages/SNS/Index.cshtml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
@*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright © Vincent Bengtsson & Contributors 2022-2023
7+
* https://github.com/Visual-Vincent/GuiStack
8+
*@
9+
10+
@page "{topic?}"
11+
12+
@using System.Net
13+
@using Amazon.SimpleNotificationService
14+
@model GuiStack.Pages.SNS.IndexModel
15+
16+
@{
17+
ViewData["Title"] = "SNS Topics";
18+
ViewData["TopicArn"] = Model.Topic;
19+
20+
bool hasTopicArn = !string.IsNullOrWhiteSpace(Model.Topic);
21+
}
22+
23+
@if(hasTopicArn)
24+
{
25+
<h1>@Model.Topic</h1>
26+
}
27+
else
28+
{
29+
<div id="new-sns-topic-modal" class="cssWindow dark backdropblur text-center">
30+
<div class="closeWindowButton"><a no-href onclick="closeParentWindow(event)">×</a></div>
31+
32+
<h2 class="title">New SNS topic</h2>
33+
<p>
34+
<input type="text" class="name-textbox text-center" maxlength="80" style="width: 400px" />
35+
</p>
36+
<p>
37+
<input type="checkbox" id="new-sns-topic-fifo-checkbox" class="fifo-checkbox" />
38+
<label for="new-sns-topic-fifo-checkbox">FIFO</label>
39+
</p>
40+
41+
<div class="modal-buttons text-center">
42+
<button onclick="sns_CreateTopic()">Create</button>
43+
</div>
44+
</div>
45+
46+
<div style="display: flex; align-items: center">
47+
<h1>SNS topics</h1>
48+
<div style="text-align: right; font-size: 1.5em; flex-grow: 1">
49+
<a no-href onclick="showWindow('new-sns-topic-modal')" class="gs-icon-stack initial-white neon-green">
50+
<i class="fa-solid fa-square-envelope" style="margin-right: 4px"></i>
51+
<i class="bi bi-plus-circle-fill gs-icon-overlay stroked" style="color: #000000"></i>
52+
</a>
53+
</div>
54+
</div>
55+
}
56+
57+
<div id="list-container">
58+
@try
59+
{
60+
if(!hasTopicArn)
61+
{
62+
await Html.RenderPartialAsync("~/Pages/SNS/_TopicsTable.cshtml", await Model.SNSRepository.GetTopicsAsync());
63+
}
64+
else
65+
{
66+
// TODO:
67+
//await Html.RenderPartialAsync("~/Pages/SNS/_TopicInfo.cshtml", await Model.SNSRepository.GetTopicAttributesAsync(Model.Topic));
68+
}
69+
}
70+
catch(AmazonSimpleNotificationServiceException ex)
71+
{
72+
if(ex.StatusCode == HttpStatusCode.NotFound)
73+
{
74+
<h2 class="error-text">Topic not found</h2>
75+
}
76+
else
77+
{
78+
if(!hasTopicArn)
79+
{
80+
<h2 class="error-text">Failed to fetch topics:</h2>
81+
}
82+
else
83+
{
84+
<h2 class="error-text">Failed to fetch topics contents:</h2>
85+
}
86+
87+
<p class="error-text">@ex.Message</p>
88+
}
89+
}
90+
catch(Exception ex)
91+
{
92+
if(!hasTopicArn)
93+
{
94+
<h2 class="error-text">Failed to fetch topics:</h2>
95+
}
96+
else
97+
{
98+
<h2 class="error-text">Failed to fetch topic contents:</h2>
99+
}
100+
101+
<p class="error-text">@ex.Message</p>
102+
}
103+
</div>
104+
105+
@if(!hasTopicArn)
106+
{
107+
<script type="text/javascript">
108+
async function sns_CreateTopic()
109+
{
110+
try
111+
{
112+
var topicName = document.querySelector("#new-sns-topic-modal .name-textbox").value;
113+
var isFifo = document.getElementById("new-sns-topic-fifo-checkbox").checked;
114+
115+
var response = await fetch("@Url.Action("CreateTopic", "Topics")", {
116+
method: "PUT",
117+
headers: new Headers({ "Content-Type": "application/json" }),
118+
body: JSON.stringify({
119+
topicName: topicName,
120+
isFifo: isFifo
121+
})
122+
});
123+
124+
if(!response.ok) {
125+
throw "Failed to create SNS topic: Server returned HTTP status " + response.status;
126+
}
127+
128+
window.location.reload(true);
129+
}
130+
catch(error)
131+
{
132+
gs_DisplayError(error);
133+
}
134+
135+
closeWindow("new-sns-topic-modal");
136+
}
137+
</script>
138+
}

GuiStack/Pages/SNS/Index.cshtml.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright © Vincent Bengtsson & Contributors 2022-2023
7+
* https://github.com/Visual-Vincent/GuiStack
8+
*/
9+
10+
using System;
11+
using GuiStack.Repositories;
12+
using Microsoft.AspNetCore.Mvc;
13+
using Microsoft.AspNetCore.Mvc.RazorPages;
14+
15+
namespace GuiStack.Pages.SNS
16+
{
17+
public class IndexModel : PageModel
18+
{
19+
public ISNSRepository SNSRepository { get; }
20+
21+
[BindProperty(SupportsGet = true)]
22+
public string Topic { get; set; }
23+
24+
public IndexModel(ISNSRepository snsRepository)
25+
{
26+
this.SNSRepository = snsRepository;
27+
}
28+
29+
public void OnGet()
30+
{
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)