Skip to content

Commit ea49f28

Browse files
committed
beta04
1 parent 150fe91 commit ea49f28

File tree

24 files changed

+368
-66010
lines changed

24 files changed

+368
-66010
lines changed

src/Server/Coderr.Server.App/Core/Support/SendSupportRequestHandler.cs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Net.Http;
34
using System.Security.Claims;
45
using System.Threading.Tasks;
56
using Coderr.Server.Abstractions.Config;
67
using Coderr.Server.Abstractions.Security;
78
using Coderr.Server.Api.Core.Accounts.Queries;
9+
using Coderr.Server.Api.Core.Messaging;
10+
using Coderr.Server.Api.Core.Messaging.Commands;
811
using Coderr.Server.Api.Core.Support;
912
using Coderr.Server.Infrastructure.Configuration;
1013
using Coderr.Server.Infrastructure.Security;
@@ -47,16 +50,32 @@ public async Task HandleAsync(IMessageContext context, SendSupportRequest comman
4750
}
4851

4952
string installationId = null;
50-
if (email == null)
53+
if (string.IsNullOrEmpty(email))
5154
email = baseConfig.SupportEmail;
5255

5356
if (errorConfig != null)
5457
{
55-
if (errorConfig.ContactEmail != null)
58+
if (!string.IsNullOrEmpty(errorConfig.ContactEmail) && string.IsNullOrEmpty(errorConfig.ContactEmail))
5659
email = errorConfig.ContactEmail;
60+
5761
installationId = errorConfig.InstallationId;
5862
}
5963

64+
// A support contact have been specified.
65+
// Thus this is a OnPremise/community server installation
66+
if (!string.IsNullOrEmpty(baseConfig.SupportEmail))
67+
{
68+
var msg = new EmailMessage(email)
69+
{
70+
Subject = command.Subject,
71+
ReplyTo = new EmailAddress(email),
72+
TextBody = $"Request from: {email}\r\n\r\n{command.Message}"
73+
};
74+
var cmd = new SendEmail(msg);
75+
await context.SendAsync(cmd);
76+
return;
77+
}
78+
6079
var items = new List<KeyValuePair<string, string>>();
6180
if (installationId != null)
6281
items.Add(new KeyValuePair<string, string>("InstallationId", installationId));
@@ -68,8 +87,11 @@ public async Task HandleAsync(IMessageContext context, SendSupportRequest comman
6887
items.Add(new KeyValuePair<string, string>("PageUrl", command.Url));
6988

7089
var content = new FormUrlEncodedContent(items);
71-
var client = new HttpClient();
72-
await client.PostAsync("https://coderrapp.com/support/request", content);
90+
var client = new HttpClient
91+
{
92+
Timeout = TimeSpan.FromSeconds(5)
93+
};
94+
await client.PostAsync("https://coderr.io/support/request", content);
7395
}
7496
}
7597
}

src/Server/Coderr.Server.Domain/Modules/ReportSpikes/ErrorReportSpike.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ public ErrorReportSpike(int applicationId, int count)
2525
NotifiedAccounts = new int[0];
2626
}
2727

28+
protected ErrorReportSpike()
29+
{
30+
31+
}
32+
33+
public int Id { get; set; }
34+
2835
/// <summary>
2936
/// Application that the inspected incident belongs to.
3037
/// </summary>

src/Server/Coderr.Server.ReportAnalyzer.Abstractions/Boot/RegisterExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Linq;
34
using System.Reflection;
45
using Coderr.Server.Abstractions.Boot;
@@ -34,8 +35,12 @@ public static void RegisterMessageHandlers(this IServiceCollection serviceCollec
3435
var types = assembly.GetTypes()
3536
.Where(y => y.GetInterfaces().Any(x => x.Name.Contains("IMessageHandler")))
3637
.ToList();
38+
3739
foreach (var type in types)
3840
{
41+
if (type.GetCustomAttributes().Any(x => x.GetType().Name.StartsWith("ContainerService")))
42+
Debugger.Break();
43+
3944
serviceCollection.AddScoped(type, type);
4045
serviceCollection.AddScoped(type.GetInterfaces()[0], type);
4146
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Reflection;
4+
using System.Security.Claims;
5+
using System.Threading.Tasks;
6+
using Coderr.Server.Api.Core.Accounts;
7+
using DotNetCqs;
8+
using DotNetCqs.Queues;
9+
using log4net;
10+
11+
namespace Coderr.Server.ReportAnalyzer.Boot.Starters
12+
{
13+
/// <summary>
14+
/// Used to decide which queue outbound messages should be enqueued in.
15+
/// </summary>
16+
internal class MessageRouter : IMessageRouter
17+
{
18+
private ILog _logger = LogManager.GetLogger(typeof(MessageRouter));
19+
private readonly Assembly _appAssembly;
20+
21+
public MessageRouter()
22+
{
23+
_appAssembly = typeof(RegisterSimple).Assembly;
24+
}
25+
26+
/// <summary>
27+
/// Queue where all messages defined in App.Api is processed
28+
/// </summary>
29+
public IMessageQueue AppQueue { get; set; }
30+
31+
/// <summary>
32+
/// Queue where all report analyzer messages are being processed.
33+
/// </summary>
34+
public IMessageQueue ReportAnalyzerQueue { get; set; }
35+
36+
public async Task SendAsync(Message message)
37+
{
38+
await SendAsync(null, message);
39+
}
40+
41+
42+
public async Task SendAsync(IReadOnlyCollection<Message> messages)
43+
{
44+
await SendAsync(null, messages);
45+
}
46+
47+
public async Task SendAsync(ClaimsPrincipal principal, Message message)
48+
{
49+
if (IsReportAnalyzerMessage(message))
50+
await SendAppMessage(principal, message);
51+
else
52+
await SendReportAnalyzerMessage(principal, message);
53+
}
54+
55+
public async Task SendAsync(ClaimsPrincipal principal, IReadOnlyCollection<Message> messages)
56+
{
57+
var reporAnalyzerMessages = messages.Where(IsReportAnalyzerMessage).ToList();
58+
var appMsgs = messages.Except(reporAnalyzerMessages).ToList();
59+
await SendReportAnalyzerMessages(principal, reporAnalyzerMessages);
60+
await SendAppMessages(principal, appMsgs);
61+
}
62+
63+
private bool IsReportAnalyzerMessage(Message message)
64+
{
65+
return message.Body?.GetType().Assembly != _appAssembly;
66+
}
67+
68+
private async Task SendAppMessage(ClaimsPrincipal claimsPrincipal, Message message)
69+
{
70+
using (var session = AppQueue.BeginSession())
71+
{
72+
if (claimsPrincipal == null)
73+
await session.EnqueueAsync(message);
74+
else
75+
await session.EnqueueAsync(claimsPrincipal, message);
76+
_logger.Info($"AppMsg[{GetHashCode()}]: {message.Body}");
77+
await session.SaveChanges();
78+
}
79+
}
80+
81+
private async Task SendAppMessages(ClaimsPrincipal principal, List<Message> msgs)
82+
{
83+
using (var session = AppQueue.BeginSession())
84+
{
85+
foreach (var message in msgs)
86+
{
87+
_logger.Debug($"AppMsg[{GetHashCode()}]: {message.Body}");
88+
}
89+
await session.EnqueueAsync(principal, msgs);
90+
await session.SaveChanges();
91+
}
92+
}
93+
94+
private async Task SendReportAnalyzerMessage(ClaimsPrincipal claimsPrincipal, Message message)
95+
{
96+
using (var session = ReportAnalyzerQueue.BeginSession())
97+
{
98+
if (claimsPrincipal == null)
99+
await session.EnqueueAsync(message);
100+
else
101+
await session.EnqueueAsync(claimsPrincipal, message);
102+
_logger.Debug($"AnalyzerMsg[{GetHashCode()}]: {message.Body}");
103+
await session.SaveChanges();
104+
}
105+
}
106+
107+
private async Task SendReportAnalyzerMessages(ClaimsPrincipal principal, List<Message> msgs)
108+
{
109+
using (var session = ReportAnalyzerQueue.BeginSession())
110+
{
111+
foreach (var message in msgs)
112+
{
113+
_logger.Debug($"AnalyzerMsg[{GetHashCode()}]: {message.Body}");
114+
}
115+
await session.EnqueueAsync(principal, msgs);
116+
await session.SaveChanges();
117+
}
118+
}
119+
}
120+
}

src/Server/Coderr.Server.ReportAnalyzer/Boot/Starters/ReportQueueModule.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using Griffin.Data;
2121
using log4net;
2222
using Microsoft.Extensions.DependencyInjection;
23+
using Newtonsoft.Json;
2324
using ConfigurationContext = Coderr.Server.ReportAnalyzer.Abstractions.Boot.ConfigurationContext;
2425
using StartContext = Coderr.Server.ReportAnalyzer.Abstractions.Boot.StartContext;
2526

@@ -90,11 +91,27 @@ private QueueListener ConfigureQueueListener(ConfigurationContext context, strin
9091
? inboundQueue
9192
: _messageQueueProvider.Open(outboundQueueName);
9293
var scopeFactory = new ScopeWrapper(context.ServiceProvider);
93-
var listener = new QueueListener(inboundQueue, outboundQueue, scopeFactory)
94+
var router = new MessageRouter
95+
{
96+
ReportAnalyzerQueue = outboundQueue,
97+
AppQueue = _messageQueueProvider.Open("Messaging")
98+
};
99+
100+
var listener = new QueueListener(inboundQueue, router, scopeFactory)
94101
{
95102
RetryAttempts = new[]
96103
{TimeSpan.FromMilliseconds(500), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2)},
97-
MessageInvokerFactory = scope => new MessageInvoker(scope),
104+
MessageInvokerFactory = scope =>
105+
{
106+
var invoker = new MessageInvoker(scope);
107+
invoker.Logger += (level, name, message) => _logger.Debug("[" + name + "] " + message);
108+
invoker.InvokingHandler += (sender, args) =>
109+
{
110+
_logger.Debug(
111+
$"Invoking {JsonConvert.SerializeObject(args.Message)} ({args.Handler.GetType()}).");
112+
};
113+
return invoker;
114+
},
98115
Logger = DiagnosticLog
99116
};
100117
listener.PoisonMessageDetected += (sender, args) =>
@@ -117,7 +134,7 @@ private QueueListener ConfigureQueueListener(ConfigurationContext context, strin
117134
var all = args.Scope.ResolveDependency<IAdoNetUnitOfWork>().ToList();
118135
all[0].SaveChanges();
119136

120-
var queue = (DomainQueueWrapper) args.Scope.ResolveDependency<IDomainQueue>().First();
137+
var queue = (DomainQueueWrapper)args.Scope.ResolveDependency<IDomainQueue>().First();
121138
queue.SaveChanges();
122139
};
123140
listener.MessageInvokerFactory = MessageInvokerFactory;
@@ -141,6 +158,7 @@ private void CreateDomainQueue(ConfigurationContext context)
141158

142159
private void DiagnosticLog(LogLevel level, string queueNameOrMessageName, string message)
143160
{
161+
_logger.Debug("[" + queueNameOrMessageName + "] " + message);
144162
}
145163

146164
private void HaveRun(Task obj)

src/Server/Coderr.Server.ReportAnalyzer/ErrorReports/HashcodeGenerators/FileNotFoundHttpErrorGenerator.cs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,31 +35,30 @@ public bool CanGenerateFrom(ErrorReportEntity entity)
3535
/// <exception cref="ArgumentNullException">entity</exception>
3636
public string GenerateHashCode(ErrorReportEntity entity)
3737
{
38-
var props = entity.ContextCollections.FirstOrDefault(x => x.Name == "ExceptionProperties")
39-
?? entity.ContextCollections.FirstOrDefault(x => x.Name == "Properties");
40-
if (props == null)
38+
string requestUrl = null;
39+
var httpCode = 0;
40+
41+
foreach (var collection in entity.ContextCollections)
4142
{
42-
_logger.Error("Failed to find ExceptionProperties collection for entity " + entity.Id);
43-
return null;
44-
}
43+
if (collection.Properties.TryGetValue("HttpCode", out var value))
44+
{
45+
int.TryParse(value, out httpCode);
4546

46-
if (!props.Properties.TryGetValue("HttpCode", out var value))
47-
return null;
48-
var statusCode = int.Parse(value);
47+
}
48+
49+
if (!collection.Properties.TryGetValue("RequestUrl", out requestUrl))
50+
collection.Properties.TryGetValue("Url", out requestUrl);
4951

50-
var headerProps = entity.ContextCollections.FirstOrDefault(x => x.Name == "HttpHeaders");
51-
if (headerProps == null)
52-
{
53-
_logger.Error("Failed to find HttpHeaders collection for entity " + entity.Id);
54-
return null;
5552
}
5653

57-
var url = headerProps.Properties["Url"].ToLower();
58-
var pos = url.IndexOf("?");
54+
if (httpCode == 0 || string.IsNullOrWhiteSpace(requestUrl))
55+
return null;
56+
57+
var pos = requestUrl.IndexOf("?");
5958
if (pos != -1)
60-
url = url.Remove(pos);
59+
requestUrl = requestUrl.Remove(pos);
6160

62-
return HashCodeUtility.GetPersistentHashCode(statusCode + "-" + url).ToString("X");
61+
return HashCodeUtility.GetPersistentHashCode(httpCode + "-" + requestUrl).ToString("X");
6362
}
6463
}
6564
}

0 commit comments

Comments
 (0)