Skip to content

Commit 3331d8d

Browse files
authored
Merge pull request #678 from noopman/cdnsupport
Adding CDN support for binary content. Configurable via the Admin page
2 parents ddb8c8d + 8e715df commit 3331d8d

File tree

10 files changed

+117
-22
lines changed

10 files changed

+117
-22
lines changed

source/DasBlog.Services/ConfigFile/Interfaces/ISiteConfig.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,12 @@ public interface ISiteConfig
6161

6262
string Root { get; set; }
6363

64-
string Copyright { get; set; }
64+
string CdnFrom { get; set; }
65+
string CdnTo { get; set; }
6566

66-
int RssDayCount { get; set; }
67+
string Copyright { get; set; }
68+
69+
int RssDayCount { get; set; }
6770

6871
int RssMainEntryCount { get; set; }
6972

source/DasBlog.Services/ConfigFile/SiteConfig.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ namespace DasBlog.Services.ConfigFile
5252
public class SiteConfig : ISiteConfig
5353
{
5454
private string _root;
55+
private string _cdnFrom;
56+
private string _cdnTo;
5557

56-
public SiteConfig() { }
58+
public SiteConfig() { }
5759

5860
public string Title { get; set; }
5961
public string Subtitle { get; set; }
@@ -77,6 +79,9 @@ public string Root {
7779
}
7880
}
7981
}
82+
public string CdnFrom { get; set; }
83+
public string CdnTo { get; set; }
84+
8085
public string AllowedHosts { get; set; }
8186
public string Copyright { get; set; }
8287
public int RssDayCount { get; set; }

source/DasBlog.Tests/UnitTests/SiteConfigTest.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
using DasBlog.Services.ConfigFile.Interfaces;
44
using newtelligence.DasBlog.Runtime;
55
using System;
6-
using System.Collections.Generic;
7-
using System.Text;
86
using System.Xml;
97

108
namespace DasBlog.Tests.UnitTests
@@ -17,10 +15,11 @@ public class SiteConfigTest : ISiteConfig
1715
public string Description { get => "Description"; set => throw new NotImplementedException(); }
1816
public string Contact { get => "Contact"; set => throw new NotImplementedException(); }
1917
public string Root { get => "http://www.poppastring.com/"; set => throw new NotImplementedException(); }
18+
public string CdnFrom{ get => ""; set => throw new NotImplementedException(); }
19+
public string CdnTo{ get => ""; set => throw new NotImplementedException(); }
2020
public string Copyright { get => "CopyRight"; set => throw new NotImplementedException(); }
2121
public int RssDayCount { get => 100; set => throw new NotImplementedException(); }
2222
public bool ShowCommentCount { get => true; set => throw new NotImplementedException(); }
23-
2423
public int RssMainEntryCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
2524
public int RssEntryCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
2625
public bool EnableRssItemFooters { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

source/DasBlog.Web.Repositories/FileSystemBinaryManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using DasBlog.Managers.Interfaces;
22
using DasBlog.Services;
33
using DasBlog.Services.ConfigFile;
4-
using DasBlog.Services.ConfigFile.Interfaces;
54
using DasBlog.Services.FileManagement;
65
using DasBlog.Services.FileManagement.Interfaces;
76
using Microsoft.Extensions.Options;
@@ -36,7 +35,9 @@ public FileSystemBinaryManager(IDasBlogSettings dasBlogSettings, IConfigFileServ
3635

3736
var loggingDataService = LoggingDataServiceFactory.GetService(Path.Combine(dasBlogSettings.WebRootDirectory, dasBlogSettings.SiteConfiguration.LogDir));
3837

39-
this.binaryDataService = BinaryDataServiceFactory.GetService(options.BinaryFolder, physBinaryPathUrl, loggingDataService);
38+
var cdnManager = CdnManagerFactory.GetService(dasBlogSettings.SiteConfiguration.CdnFrom, dasBlogSettings.SiteConfiguration.CdnTo);
39+
40+
binaryDataService = BinaryDataServiceFactory.GetService(options.BinaryFolder, physBinaryPathUrl, loggingDataService, cdnManager);
4041
}
4142

4243
public string SaveFile(Stream inputFile, string fileName)

source/DasBlog.Web.UI/Config/site.config

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@
5656
<LogDir>logs</LogDir>
5757
<BinariesDir>content/binary</BinariesDir>
5858

59+
<!-- OPTIONAL: Content Delivery Network (CDN)
60+
The two CDN settings below (CdnFrom/CdnTo) is a search and replace pattern.
61+
* Default binaries storage is <Root>/<BinariesDir>.
62+
* Note: This setting will not work from localhost when posting a new blog post.
63+
-->
64+
<!-- The part of your <Root>/<BinariesDir> hosting path you want to replace (ex. http://example.com/content/binary/): -->
65+
<CdnFrom></CdnFrom>
66+
<!-- The URL of the cdn servcie you are replacing to (ex. http://cdn.example.com/content/binary/): -->
67+
<CdnTo></CdnTo>
68+
5969
<EnableTitlePermaLink>true</EnableTitlePermaLink>
6070
<EnableTitlePermaLinkUnique>false</EnableTitlePermaLinkUnique>
6171
<EnableTitlePermaLinkSpaces>false</EnableTitlePermaLinkSpaces>

source/DasBlog.Web.UI/Models/AdminViewModels/SiteViewModel.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,16 @@ public class SiteViewModel
240240

241241
[DisplayName("Time zone index")]
242242
[Description("")]
243-
244243
public int DisplayTimeZoneIndex { get; set; }
245244

245+
[DisplayName("CDN from")]
246+
[Description("The part of your Root URL to replace with the CDN URL. (optional)")]
247+
public string CdnFrom { get; set; }
248+
249+
[DisplayName("CDN to")]
250+
[Description("The CDN URL that will replace 'CDN from'. (optional)")]
251+
public string CdnTo { get; set; }
252+
246253
[DisplayName("Comments require approval")]
247254
[Description("")]
248255
public bool CommentsRequireApproval { get; set; }

source/DasBlog.Web.UI/Views/Admin/Settings.cshtml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,22 @@
694694
@Html.ValidationMessageFor(m => m.SiteConfig.DisplayTimeZoneIndex, null, new { @class = "text-danger" })
695695

696696
</div>
697+
698+
<div class="form-group row mb-3">
699+
700+
@Html.LabelFor(m => @Model.SiteConfig.CdnFrom, null, new { @class = "col-form-label col-sm-2" })
701+
<div class="col-sm-5">
702+
@Html.TextBoxFor(m => @Model.SiteConfig.CdnFrom, null, new { @class = "form-control sm-10" })
703+
</div>
704+
@Html.ValidationMessageFor(m => m.SiteConfig.CdnFrom, null, new { @class = "text-danger" })
705+
706+
@Html.LabelFor(m => @Model.SiteConfig.CdnTo, null, new { @class = "col-form-label col-sm-2" })
707+
<div class="col-sm-5">
708+
@Html.TextBoxFor(m => @Model.SiteConfig.CdnTo, null, new { @class = "form-control sm-10" })
709+
</div>
710+
@Html.ValidationMessageFor(m => m.SiteConfig.CdnTo, null, new { @class = "text-danger" })
711+
712+
</div>
697713

698714
<h3>Security</h3>
699715

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
3+
namespace newtelligence.DasBlog.Runtime
4+
{
5+
public static class CdnManagerFactory
6+
{
7+
public static ICdnManager GetService(string cdnFrom, string cdnTo)
8+
{
9+
return new CdnManager(cdnFrom, cdnTo);
10+
}
11+
}
12+
13+
internal sealed class CdnManager : ICdnManager
14+
{
15+
private readonly string cdnFrom;
16+
private readonly string cdnTo;
17+
18+
/// <summary>
19+
/// Setting up the cdn manager to return cdn uris when that is configured.
20+
/// </summary>
21+
/// <param name="cdnFrom">The binary hosting path to be replaced.</param>
22+
/// <param name="cdnTo">The cdn binary hosting path to change to.</param>
23+
public CdnManager(string cdnFrom, string cdnTo)
24+
{
25+
this.cdnFrom = string.IsNullOrWhiteSpace(cdnFrom) ? null : cdnFrom;
26+
this.cdnTo = string.IsNullOrWhiteSpace(cdnTo) || this.cdnFrom == null ? null : cdnTo;
27+
}
28+
29+
public string ApplyCdnUri(string uri)
30+
{
31+
// If the cdnUri is null then we can just return the uri.
32+
return cdnTo == null ? uri : uri.Replace(cdnFrom, cdnTo);
33+
}
34+
}
35+
}

source/newtelligence.DasBlog.Runtime/FileSystemBinaryDataService.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ public static class BinaryDataServiceFactory
1919
/// </summary>
2020
/// <param name="contentLocation"></param>
2121
/// <returns></returns>
22-
public static IBinaryDataService GetService(string contentLocation, Uri rootUrl, ILoggingDataService loggingService)
22+
public static IBinaryDataService GetService(string contentLocation, Uri rootUrl, ILoggingDataService loggingService, ICdnManager cdnManager)
2323
{
2424
IBinaryDataService service;
2525

2626
lock (serviceLock)
2727
{
2828
if (!services.TryGetValue(contentLocation, out service))
2929
{
30-
service = new FileSystemBinaryDataService(contentLocation, rootUrl, loggingService);
30+
service = new FileSystemBinaryDataService(contentLocation, rootUrl, loggingService, cdnManager);
3131
services.Add(contentLocation, service);
3232
}
3333
}
@@ -50,14 +50,14 @@ public static bool RemoveService(string contentLocation)
5050

5151
internal sealed class FileSystemBinaryDataService : IBinaryDataService
5252
{
53-
54-
/// <summary>
55-
///
56-
/// </summary>
57-
/// <param name="contentLocation">The location of the content on disk.</param>
58-
/// <param name="binaryRelativeUrl">The relative url to the binary content from the root of the site.</param>
59-
/// <param name="loggingService">The logging service.</param>
60-
internal FileSystemBinaryDataService(string contentLocation, Uri binaryRootUrl, ILoggingDataService loggingService)
53+
/// <summary>
54+
///
55+
/// </summary>
56+
/// <param name="contentLocation">The location of the content on disk.</param>
57+
/// <param name="binaryRootUrl">The relative url to the binary content from the root of the site.</param>
58+
/// <param name="loggingService">The logging service.</param>
59+
/// <param name="cdnManager">Creates content URis for CDN locations.</param>
60+
internal FileSystemBinaryDataService(string contentLocation, Uri binaryRootUrl, ILoggingDataService loggingService, ICdnManager cdnManager)
6161
{
6262
// parameter validation
6363
if (string.IsNullOrEmpty(contentLocation))
@@ -82,6 +82,7 @@ internal FileSystemBinaryDataService(string contentLocation, Uri binaryRootUrl,
8282

8383
this.contentLocation = contentLocation;
8484
this.loggingService = loggingService;
85+
this.cdnManager = cdnManager;
8586
this.binaryRoot = binaryRootUrl;
8687
}
8788

@@ -144,9 +145,11 @@ public string SaveFile(System.IO.Stream inputFile, ref string fileName)
144145

145146
string absUri = GetAbsoluteFileUri(file.FullName, out relUri);
146147

147-
fileName = relUri;
148+
fileName = relUri;
149+
150+
absUri = cdnManager.ApplyCdnUri(absUri);
148151

149-
return absUri;
152+
return absUri;
150153
}
151154

152155
private string GetAbsoluteFileUri(string fullPath, out string relFileUri)
@@ -218,6 +221,6 @@ private bool EqualBuffers(byte[] buf1, byte[] buf2)
218221
private string contentLocation;
219222
private Uri binaryRoot;
220223
private ILoggingDataService loggingService;
221-
224+
private readonly ICdnManager cdnManager;
222225
}
223226
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace newtelligence.DasBlog.Runtime
2+
{
3+
/// <summary>
4+
/// When the site is configured with a "CdnRoot" setting,
5+
/// this manager is used to create content URIs for the CDN location.
6+
/// </summary>
7+
public interface ICdnManager
8+
{
9+
/// <summary>
10+
/// Manages URI creation for resources when CDN is configured.
11+
/// </summary>
12+
/// <param name="uri">The URI of a file hosted locally.</param>
13+
/// <returns>The URI of a file when it is hosted in CDN.</returns>
14+
string ApplyCdnUri(string uri);
15+
}
16+
}

0 commit comments

Comments
 (0)