Skip to content

Commit 6495d7d

Browse files
author
Jaben Cargman
committedDec 17, 2015
Added Conditional Forward Rule with Retry.
1 parent 27c7751 commit 6495d7d

32 files changed

+773
-272
lines changed
 

‎Papercut.Core/Helper/EnumerableExtensions.cs

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
namespace Papercut.Core.Helper
1919
{
20+
using System;
2021
using System.Collections.Generic;
2122
using System.Linq;
2223

@@ -29,5 +30,12 @@ public static IEnumerable<T> IfNullEmpty<T>(this IEnumerable<T> enumerable)
2930

3031
return enumerable;
3132
}
33+
34+
public static IEnumerable<string> ToFormattedPairs(this IEnumerable<KeyValuePair<string, Lazy<object>>> keyValuePairs)
35+
{
36+
return keyValuePairs.IfNullEmpty().Select(s => KeyValuePair.Create(s.Key, string.Format("{0}", s.Value.Value)))
37+
.Where(s => s.Value.IsSet())
38+
.Select(s => $"{s.Key}: {s.Value}");
39+
}
3240
}
3341
}

‎Papercut.Core/Helper/KeyValuePair.cs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Papercut
2+
//
3+
// Copyright © 2008 - 2012 Ken Robertson
4+
// Copyright © 2013 - 2015 Jaben Cargman
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
// ReSharper disable once CheckNamespace
19+
// want this to be in this namespace to match KeyValuePair namespace
20+
namespace System.Collections.Generic
21+
{
22+
internal static class KeyValuePair
23+
{
24+
public static KeyValuePair<TKey, TValue> Create<TKey, TValue>(TKey key, TValue value)
25+
{
26+
return new KeyValuePair<TKey, TValue>(key, value);
27+
}
28+
}
29+
}

‎Papercut.Core/Helper/MessageHelper.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static string GetStringDump([NotNull] this MimeMessage mimeMessage)
6363

6464
public static bool IsContentHtml([NotNull] this TextPart textPart)
6565
{
66-
return textPart.ContentType.Matches("text", "html");
66+
return textPart.ContentType.IsMimeType("text", "html");
6767
}
6868

6969
public static string GetExtension([NotNull] this ContentType contentType)
@@ -87,7 +87,7 @@ public static IEnumerable<MimePart> GetImages([NotNull] this IEnumerable<MimePar
8787
if (prefilteredMimeParts == null)
8888
throw new ArgumentNullException(nameof(prefilteredMimeParts));
8989

90-
return prefilteredMimeParts.Where(e => e.ContentType.Matches("image", "*"));
90+
return prefilteredMimeParts.Where(e => e.ContentType.IsMimeType("image", "*"));
9191
}
9292

9393
public static IEnumerable<MimePart> GetAttachments([NotNull] this IEnumerable<MimePart> prefilteredMimeParts)

‎Papercut.Core/Helper/ObjectExtensions.cs

+42-9
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
// See the License for the specific language governing permissions and
1616
// limitations under the License.
1717

18+
using System;
19+
using System.Collections.Generic;
20+
using System.ComponentModel;
21+
using System.Linq;
22+
using Papercut.Core.Annotations;
23+
1824
namespace Papercut.Core.Helper
1925
{
20-
using System;
21-
using System.Collections.Generic;
22-
using System.ComponentModel;
23-
24-
using Papercut.Core.Annotations;
26+
using System.Reflection;
2527

2628
public static class ObjectExtensions
2729
{
@@ -46,15 +48,16 @@ public static T ToType<T>([CanBeNull] this object instance)
4648
else if (!(instance is IConvertible) && !instance.GetType().IsValueType)
4749
{
4850
// just cast since it's a class....
49-
return (T)instance;
51+
return (T) instance;
5052
}
5153

52-
Type conversionType = typeof(T);
54+
var conversionType = typeof (T);
5355

5456
if (conversionType.IsGenericType
55-
&& conversionType.GetGenericTypeDefinition() == typeof(Nullable<>)) conversionType = (new NullableConverter(conversionType)).UnderlyingType;
57+
&& conversionType.GetGenericTypeDefinition() == typeof (Nullable<>))
58+
conversionType = new NullableConverter(conversionType).UnderlyingType;
5659

57-
return (T)Convert.ChangeType(instance, conversionType);
60+
return (T) Convert.ChangeType(instance, conversionType);
5861
}
5962

6063
/// <summary>
@@ -92,5 +95,35 @@ public static IEnumerable<T> ToEnumerable<T>(this T obj)
9295
{
9396
if (!obj.IsDefault()) yield return obj;
9497
}
98+
99+
/// <summary>
100+
/// Gets all properties on T obj as an IEnumerable of key/value pairs.
101+
/// </summary>
102+
/// <typeparam name="T"></typeparam>
103+
/// <param name="obj"></param>
104+
/// <returns></returns>
105+
public static IEnumerable<KeyValuePair<string, Lazy<object>>> GetProperties<T>([NotNull] this T obj)
106+
where T : class
107+
{
108+
if (obj == null) throw new ArgumentNullException(nameof(obj));
109+
110+
var type = typeof (T);
111+
112+
var properties =
113+
type.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance |
114+
BindingFlags.GetProperty);
115+
116+
foreach (var prop in properties)
117+
{
118+
var displayName =
119+
prop.GetCustomAttributes(typeof (DisplayNameAttribute), false)
120+
.OfType<DisplayNameAttribute>()
121+
.FirstOrDefault();
122+
123+
yield return
124+
KeyValuePair.Create(displayName?.DisplayName ?? prop.Name,
125+
new Lazy<object>(() => prop.GetValue(obj, null)));
126+
}
127+
}
95128
}
96129
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Papercut
2+
//
3+
// Copyright © 2008 - 2012 Ken Robertson
4+
// Copyright © 2013 - 2015 Jaben Cargman
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
namespace Papercut.Core.Helper
19+
{
20+
using System;
21+
using System.Reactive.Linq;
22+
23+
public static class ObservableExtensions
24+
{
25+
public static IObservable<T> RetryWithDelay<T>(this IObservable<T> source, int retryCount, TimeSpan timeSpan)
26+
{
27+
if (source == null)
28+
throw new ArgumentNullException("source");
29+
if (timeSpan < TimeSpan.Zero)
30+
throw new ArgumentOutOfRangeException("timeSpan");
31+
if (timeSpan == TimeSpan.Zero)
32+
return source.Retry(retryCount);
33+
34+
return source.Catch(Observable.Timer(timeSpan).SelectMany(_ => source).Retry(retryCount));
35+
}
36+
}
37+
}

‎Papercut.Core/Helper/StringHelpers.cs

+7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// limitations under the License.
1717

1818

19+
using System.Collections.Generic;
20+
1921
namespace Papercut.Core.Helper
2022
{
2123
using System;
@@ -42,6 +44,11 @@ public static bool IsSet([CanBeNull] this string str)
4244
return !string.IsNullOrWhiteSpace(str);
4345
}
4446

47+
public static string Join([CanBeNull] this IEnumerable<string> strings, string seperator)
48+
{
49+
return string.Join(seperator, strings.IfNullEmpty());
50+
}
51+
4552
public static string ToTitleCase([CanBeNull] this string str, CultureInfo culture = null)
4653
{
4754
if (str.IsNullOrWhiteSpace())

‎Papercut.Core/Message/MimeMessageLoader.cs

+10-6
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ public IObservable<MimeMessage> Get(MessageEntry messageEntry)
5858
o =>
5959
{
6060
// in case of multiple subscriptions...
61-
var observer = Observer.Synchronize(o);
62-
61+
var observer = Observer.Synchronize(o, true);
6362
var disposable = new CancellationDisposable();
6463

64+
MimeMessage message = null;
65+
6566
try
6667
{
67-
var message = MimeMessageCache.GetOrSet(
68+
message = MimeMessageCache.GetOrSet(
6869
messageEntry.File,
6970
() =>
7071
{
@@ -98,9 +99,6 @@ public IObservable<MimeMessage> Get(MessageEntry messageEntry)
9899

99100
MimeMessageCache.Add(messageEntry.File, m, policy);
100101
});
101-
102-
observer.OnNext(message);
103-
observer.OnCompleted();
104102
}
105103
catch (OperationCanceledException)
106104
{
@@ -112,6 +110,12 @@ public IObservable<MimeMessage> Get(MessageEntry messageEntry)
112110
observer.OnError(ex);
113111
}
114112

113+
if (message != null)
114+
{
115+
observer.OnNext(message);
116+
observer.OnCompleted();
117+
}
118+
115119
return disposable;
116120
}).SubscribeOn(TaskPoolScheduler.Default);
117121
}

‎Papercut.Core/Papercut.Core.csproj

+15-6
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,28 @@
3838
<SpecificVersion>False</SpecificVersion>
3939
<HintPath>..\packages\Autofac.3.5.2\lib\net40\Autofac.dll</HintPath>
4040
</Reference>
41-
<Reference Include="BouncyCastle, Version=1.8.5727.25141, Culture=neutral, PublicKeyToken=eec3120e64a3fcba, processorArchitecture=MSIL">
42-
<HintPath>..\packages\MimeKit.1.2.11.0\lib\net40\BouncyCastle.dll</HintPath>
41+
<Reference Include="BouncyCastle, Version=1.8.0.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
42+
<HintPath>..\packages\MimeKit.1.2.18\lib\net40\BouncyCastle.dll</HintPath>
4343
<Private>True</Private>
4444
</Reference>
4545
<Reference Include="MailKit, Version=1.2.0.0, Culture=neutral, PublicKeyToken=4e064fe7c44a8f1b, processorArchitecture=MSIL">
46-
<HintPath>..\packages\MailKit.1.2.11.1\lib\net40\MailKit.dll</HintPath>
46+
<HintPath>..\packages\MailKit.1.2.15\lib\net40\MailKit.dll</HintPath>
4747
<Private>True</Private>
4848
</Reference>
4949
<Reference Include="MimeKit, Version=1.2.0.0, Culture=neutral, PublicKeyToken=bede1c8a46c66814, processorArchitecture=MSIL">
50-
<HintPath>..\packages\MimeKit.1.2.11.0\lib\net40\MimeKit.dll</HintPath>
50+
<HintPath>..\packages\MimeKit.1.2.18\lib\net40\MimeKit.dll</HintPath>
5151
<Private>True</Private>
5252
</Reference>
5353
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
5454
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
5555
<Private>True</Private>
5656
</Reference>
5757
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
58-
<HintPath>..\packages\Serilog.1.5.11\lib\net40\Serilog.dll</HintPath>
58+
<HintPath>..\packages\Serilog.1.5.14\lib\net40\Serilog.dll</HintPath>
5959
<Private>True</Private>
6060
</Reference>
6161
<Reference Include="Serilog.FullNetFx, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
62-
<HintPath>..\packages\Serilog.1.5.11\lib\net40\Serilog.FullNetFx.dll</HintPath>
62+
<HintPath>..\packages\Serilog.1.5.14\lib\net40\Serilog.FullNetFx.dll</HintPath>
6363
<Private>True</Private>
6464
</Reference>
6565
<Reference Include="System" />
@@ -124,10 +124,12 @@
124124
<Compile Include="Configuration\IPathTemplatesProvider.cs" />
125125
<Compile Include="Helper\AutofacRegistrationExtensions.cs" />
126126
<Compile Include="Helper\AutofacServiceProvider.cs" />
127+
<Compile Include="Helper\ObservableExtensions.cs" />
127128
<Compile Include="Helper\EnumerableExtensions.cs" />
128129
<Compile Include="Helper\EnvironmentEnricher.cs" />
129130
<Compile Include="Helper\FileInfoExtensions.cs" />
130131
<Compile Include="Helper\JsonHelpers.cs" />
132+
<Compile Include="Helper\KeyValuePair.cs" />
131133
<Compile Include="Helper\MemoryCacheExtensions.cs" />
132134
<Compile Include="Helper\NameValueCollectionHelpers.cs" />
133135
<Compile Include="Helper\NetworkHelper.cs" />
@@ -156,8 +158,11 @@
156158
<Compile Include="Network\SmtpContext.cs" />
157159
<Compile Include="Network\ISmtpCommand.cs" />
158160
<Compile Include="Network\ISmtpContext.cs" />
161+
<Compile Include="Rules\Implementations\BaseRelayRuleDispatch.cs" />
162+
<Compile Include="Rules\Implementations\ConditionalForwardRuleExtensions.cs" />
159163
<Compile Include="Rules\Implementations\ConditionalForwardRule.cs" />
160164
<Compile Include="Rules\Implementations\ConditionalForwardRuleDispatch.cs" />
165+
<Compile Include="Rules\Implementations\ConditionalForwardWithRetryRuleDispatch.cs" />
161166
<Compile Include="Rules\Implementations\ForwardRule.cs" />
162167
<Compile Include="Network\Connection.cs" />
163168
<Compile Include="Helper\ConnectionExtensions.cs" />
@@ -184,7 +189,11 @@
184189
<Compile Include="Network\SmtpProtocol.cs" />
185190
<Compile Include="Network\SmtpSession.cs" />
186191
<Compile Include="Rules\Implementations\ForwardRuleDispatch.cs" />
192+
<Compile Include="Rules\Implementations\RelayRuleDispatch.cs" />
187193
<Compile Include="Rules\Implementations\ForwardRuleExtensions.cs" />
194+
<Compile Include="Rules\Implementations\RelayRule.cs" />
195+
<Compile Include="Rules\Implementations\RelayRuleExtensions.cs" />
196+
<Compile Include="Rules\Implementations\ConditionalForwardWithRetryRule.cs" />
188197
<Compile Include="Rules\IRule.cs" />
189198
<Compile Include="Rules\IRuleDispatcher.cs" />
190199
<Compile Include="Rules\IRulesRunner.cs" />

0 commit comments

Comments
 (0)
Please sign in to comment.