Skip to content

Commit

Permalink
Adding support for CDN rewrites
Browse files Browse the repository at this point in the history
  • Loading branch information
Dzoukr committed Jan 19, 2022
1 parent 36dab83 commit 848658b
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 10 deletions.
10 changes: 9 additions & 1 deletion src/Funcaster/Domain.fs
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,12 @@ type Channel = {
Category : string option
Type : ChannelType
Restrictions : string list
}
}

type CdnSetup = {
IsEnabled : bool
CdnUrl : Uri
}

module CdnSetup =
let none = { IsEnabled = false; CdnUrl = Uri("https://www.example.com") }
23 changes: 23 additions & 0 deletions src/Funcaster/DomainExtensions.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Funcaster.DomainExtensions

open System
open Funcaster.Domain

module CdnSetup =
let private _rewriteUrl (old:Uri) (new':Uri) =
let builder = UriBuilder(old)
builder.Host <- new'.Host
builder.Uri

let rewriteUrl (cdn:CdnSetup) (url:Uri) =
if cdn.IsEnabled then _rewriteUrl url cdn.CdnUrl else url

let rewriteItem (cdn:CdnSetup) (item:Item) =
{ item
with
Enclosure = { item.Enclosure with Url = rewriteUrl cdn item.Enclosure.Url }
Image = item.Image |> Option.map (rewriteUrl cdn)
}

let rewriteChannel (cdn:CdnSetup) (channel:Channel) =
{ channel with Image = rewriteUrl cdn channel.Image }
1 change: 1 addition & 0 deletions src/Funcaster/Funcaster.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<ItemGroup>
<Compile Include="Xml.fs" />
<Compile Include="Domain.fs" />
<Compile Include="DomainExtensions.fs" />
<Compile Include="Storage.fs" />
<Compile Include="RssXml.fs" />
<Compile Include="Functions.fs" />
Expand Down
23 changes: 20 additions & 3 deletions src/Funcaster/Functions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Funcaster.Functions
open System
open System.Net
open Funcaster.Domain
open Funcaster.DomainExtensions
open Funcaster.RssXml
open Funcaster.Storage
open Microsoft.Azure.Functions.Worker
Expand All @@ -26,15 +27,31 @@ module Stubs =
Restrictions = []
}

type Functions(log:ILogger<Functions>, podcast:PodcastTable, episodes:EpisodesTable) =
type Functions(log:ILogger<Functions>, podcast:PodcastTable, episodes:EpisodesTable, cdn:CdnSetupTable) =

[<Function("RssFeed")>]
member _.RssFeed ([<HttpTrigger(AuthorizationLevel.Anonymous, "get", "head", Route = "rss")>] req: HttpRequestData, ctx: FunctionContext) =
task {
// get CDN info
let! cdnSetupOpt = getCdnSetup cdn ()
let cdnSetup = cdnSetupOpt |> Option.defaultValue CdnSetup.none

// get Channel
let! channelOpt = getPodcast podcast ()
let channel = channelOpt |> Option.defaultValue Stubs.getEmptyChannel
let channel =
channelOpt
|> Option.defaultValue Stubs.getEmptyChannel
|> CdnSetup.rewriteChannel cdnSetup

// get Episodes
let! allItems = getEpisodes episodes ()
let items = allItems |> List.filter (fun x -> x.Publish <= DateTimeOffset.UtcNow) |> List.sortByDescending (fun x -> x.Publish)
let items =
allItems
|> List.filter (fun x -> x.Publish <= DateTimeOffset.UtcNow)
|> List.sortByDescending (fun x -> x.Publish)
|> List.map (CdnSetup.rewriteItem cdnSetup)

// write response
let res = req.CreateResponse(HttpStatusCode.OK)
res.Headers.Add("Content-Type", "application/rss+xml; charset=utf-8");
RssXml.getDoc channel items |> RssXml.toString |> res.WriteString
Expand Down
6 changes: 4 additions & 2 deletions src/Funcaster/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ open Funcaster.Storage

let configureServices (ctx:HostBuilderContext) (svcs:IServiceCollection) =
let connString = ctx.Configuration.["PodcastStorage"]
let episodes = EpisodesTable.create connString
let podcast = PodcastTable.create connString
let episodes = EpisodesTable.createSafe connString
let podcast = PodcastTable.createSafe connString
let cdnSetup = CdnSetupTable.createSafe connString
svcs.AddSingleton<EpisodesTable>(episodes) |> ignore
svcs.AddSingleton<PodcastTable>(podcast) |> ignore
svcs.AddSingleton<CdnSetupTable>(cdnSetup) |> ignore
()

[<EntryPoint>]
Expand Down
53 changes: 49 additions & 4 deletions src/Funcaster/Storage.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ module private Helpers =
type PodcastTable = PodcastTable of TableClient

module PodcastTable =
let create (conn:string) =
TableClient(conn, "Podcast") |> PodcastTable
let createSafe (conn:string) =
let client = TableClient(conn, "Podcast")
let _ = client.CreateIfNotExists()
client |> PodcastTable

module Channel =
let toEntity (c:Channel) : TableEntity =
Expand Down Expand Up @@ -83,8 +85,10 @@ let upsertPodcast (PodcastTable podcastTable) (channel:Channel) =
type EpisodesTable = EpisodesTable of TableClient

module EpisodesTable =
let create (conn:string) =
TableClient(conn, "Episodes") |> EpisodesTable
let createSafe (conn:string) =
let client = TableClient(conn, "Episodes")
let _ = client.CreateIfNotExists()
client |> EpisodesTable

module Item =
let toPartialEnclosureEntity (guid:string) (c:Enclosure) : TableEntity =
Expand Down Expand Up @@ -169,4 +173,45 @@ let updateEnclosure (EpisodesTable episodesTable) (guid:string) (enc:Enclosure)
let entity = enc |> Item.toPartialEnclosureEntity (guid |> key)
let! _ = episodesTable.UpsertEntityAsync(entity, TableUpdateMode.Merge)
return ()
}

type CdnSetupTable = CdnSetupTable of TableClient

module CdnSetupTable =
let createSafe (conn:string) =
let client = TableClient(conn, "CdnSetup")
let _ = client.CreateIfNotExists()
client |> CdnSetupTable

module CdnSetup =
let toEntity (c:CdnSetup) : TableEntity =
let e = TableEntity()
e.PartitionKey <- "cdn"
e.RowKey <- "cdn"
e.["CdnUrl"] <- c.CdnUrl |> string
e.["IsEnabled"] <- c.IsEnabled
e

let fromEntity (e:TableEntity) : CdnSetup =
{
CdnUrl = e.GetString("CdnUrl") |> Uri
IsEnabled = e.GetBoolean("IsEnabled") |> Option.ofNullable |> Option.defaultValue false
}

let getCdnSetup (CdnSetupTable cdnTable) () =
task {
return
tableQuery {
filter (pk "cdn" + rk "cdn")
}
|> cdnTable.Query<TableEntity>
|> Seq.tryHead
|> Option.map CdnSetup.fromEntity
}

let upsertCdnSetup (CdnSetupTable cdnTable) (cdnSetup:CdnSetup) =
task {
let entity = cdnSetup |> CdnSetup.toEntity
let! _ = cdnTable.UpsertEntityAsync(entity, TableUpdateMode.Merge)
return ()
}

0 comments on commit 848658b

Please sign in to comment.