an atproto pds written in F# (.NET 9) 🦒
pds fsharp giraffe dotnet atproto

feat: set up initial project structure including editor config

+19
.editorconfig
···
··· 1 + # EditorConfig is awesome: https://EditorConfig.org 2 + root = true 3 + 4 + [*] 5 + indent_style = space 6 + indent_size = 2 7 + end_of_line = lf 8 + charset = utf-8 9 + trim_trailing_whitespace = true 10 + insert_final_newline = true 11 + 12 + # Fantomas Configuration 13 + [*{fs,.fsi,.fsx}] 14 + fsharp_max_record_width = 60 15 + max_line_length = 120 16 + fsharp_space_before_colon = true 17 + fsharp_max_array_or_list_number_of_items = 3 18 + fsharp_multiline_bracket_style = stroustrup 19 + fsharp_newline_before_multiline_computation_expression = false
+2
.gitignore
··· 46 *.VisualState.xml 47 TestResult.xml 48 nunit-*.xml
··· 46 *.VisualState.xml 47 TestResult.xml 48 nunit-*.xml 49 + 50 + .fake
+4
PDSharp.Core/Config.fs
···
··· 1 + namespace PDSharp.Core 2 + 3 + module Config = 4 + type AppConfig = { PublicUrl : string; DidHost : string }
+7 -3
PDSharp.Core/Library.fs
··· 1 namespace PDSharp.Core 2 3 - module Say = 4 - let hello name = 5 - printfn "Hello %s" name
··· 1 namespace PDSharp.Core 2 3 + module Models = 4 + [<CLIMutable>] 5 + type DescribeServerResponse = { 6 + availableUserDomains : string list 7 + did : string 8 + inviteCodeRequired : bool 9 + }
+1
PDSharp.Core/PDSharp.Core.fsproj
··· 6 </PropertyGroup> 7 8 <ItemGroup> 9 <Compile Include="Library.fs"/> 10 </ItemGroup> 11
··· 6 </PropertyGroup> 7 8 <ItemGroup> 9 + <Compile Include="Config.fs"/> 10 <Compile Include="Library.fs"/> 11 </ItemGroup> 12
+26
PDSharp.Tests/PDSharp.Tests.fsproj
···
··· 1 + <Project Sdk="Microsoft.NET.Sdk"> 2 + 3 + <PropertyGroup> 4 + <TargetFramework>net9.0</TargetFramework> 5 + <IsPackable>false</IsPackable> 6 + <GenerateProgramFile>false</GenerateProgramFile> 7 + </PropertyGroup> 8 + 9 + <ItemGroup> 10 + <Compile Include="Tests.fs" /> 11 + <Compile Include="Program.fs" /> 12 + </ItemGroup> 13 + 14 + <ItemGroup> 15 + <PackageReference Include="coverlet.collector" Version="6.0.2" /> 16 + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> 17 + <PackageReference Include="xunit" Version="2.9.2" /> 18 + <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" /> 19 + </ItemGroup> 20 + 21 + <ItemGroup> 22 + <ProjectReference Include="..\PDSharp\PDSharp.fsproj" /> 23 + <ProjectReference Include="..\PDSharp.Core\PDSharp.Core.fsproj" /> 24 + </ItemGroup> 25 + 26 + </Project>
+4
PDSharp.Tests/Program.fs
···
··· 1 + module Program 2 + 3 + [<EntryPoint>] 4 + let main _ = 0
+29
PDSharp.Tests/Tests.fs
···
··· 1 + module Tests 2 + 3 + open System 4 + open Xunit 5 + open PDSharp.Core.Models 6 + open PDSharp.Core.Config 7 + 8 + [<Fact>] 9 + let ``My test`` () = Assert.True(true) 10 + 11 + [<Fact>] 12 + let ``Can instantiate AppConfig`` () = 13 + let config = { 14 + PublicUrl = "https://example.com" 15 + DidHost = "did:web:example.com" 16 + } 17 + 18 + Assert.Equal("did:web:example.com", config.DidHost) 19 + 20 + [<Fact>] 21 + let ``Can instantiate DescribeServerResponse`` () = 22 + let response = { 23 + availableUserDomains = [ "example.com" ] 24 + did = "did:web:example.com" 25 + inviteCodeRequired = true 26 + } 27 + 28 + Assert.Equal("did:web:example.com", response.did) 29 + Assert.Equal(1, response.availableUserDomains.Length)
+7
PDSharp.sln
··· 1  2 Microsoft Visual Studio Solution File, Format Version 12.00 3 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PDSharp", "PDSharp\PDSharp.fsproj", "{FE3C5D60-6A4F-402E-AF13-B37020876850}" 4 EndProject 5 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PDSharp.Core", "PDSharp.Core\PDSharp.Core.fsproj", "{FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}" 6 EndProject 7 Global 8 GlobalSection(SolutionConfigurationPlatforms) = preSolution ··· 18 {FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 {FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 {FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}.Release|Any CPU.Build.0 = Release|Any CPU 21 EndGlobalSection 22 EndGlobal
··· 1  2 Microsoft Visual Studio Solution File, Format Version 12.00 3 + # 4 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PDSharp", "PDSharp\PDSharp.fsproj", "{FE3C5D60-6A4F-402E-AF13-B37020876850}" 5 EndProject 6 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PDSharp.Core", "PDSharp.Core\PDSharp.Core.fsproj", "{FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}" 7 + EndProject 8 + Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PDSharp.Tests", "PDSharp.Tests\PDSharp.Tests.fsproj", "{3212A539-34FB-4A57-8028-DC066904A17D}" 9 EndProject 10 Global 11 GlobalSection(SolutionConfigurationPlatforms) = preSolution ··· 21 {FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 {FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 {FFF8A779-342A-4DC3-92D6-5BB5D5238CB5}.Release|Any CPU.Build.0 = Release|Any CPU 24 + {3212A539-34FB-4A57-8028-DC066904A17D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 + {3212A539-34FB-4A57-8028-DC066904A17D}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 + {3212A539-34FB-4A57-8028-DC066904A17D}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 + {3212A539-34FB-4A57-8028-DC066904A17D}.Release|Any CPU.Build.0 = Release|Any CPU 28 EndGlobalSection 29 EndGlobal
+18 -1
PDSharp/PDSharp.fsproj
··· 6 </PropertyGroup> 7 8 <ItemGroup> 9 - <Compile Include="Program.fs"/> 10 </ItemGroup> 11 12 </Project>
··· 6 </PropertyGroup> 7 8 <ItemGroup> 9 + <Compile Include="Program.fs" /> 10 + </ItemGroup> 11 + 12 + <ItemGroup> 13 + <PackageReference Include="Giraffe" Version="8.2.0" /> 14 + <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.1" /> 15 + <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.1" /> 16 + <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.1" /> 17 + </ItemGroup> 18 + 19 + <ItemGroup> 20 + <ProjectReference Include="..\PDSharp.Core\PDSharp.Core.fsproj" /> 21 + </ItemGroup> 22 + 23 + <ItemGroup> 24 + <Content Include="appsettings.json"> 25 + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 26 + </Content> 27 </ItemGroup> 28 29 </Project>
+59 -2
PDSharp/Program.fs
··· 1 - // For more information see https://aka.ms/fsharp-console-apps 2 - printfn "Hello from F#"
··· 1 + open System 2 + open System.IO 3 + open Microsoft.AspNetCore.Builder 4 + open Microsoft.AspNetCore.Hosting 5 + open Microsoft.Extensions.Hosting 6 + open Microsoft.Extensions.DependencyInjection 7 + open Microsoft.Extensions.Configuration 8 + open Giraffe 9 + open PDSharp.Core.Models 10 + open PDSharp.Core.Config 11 + 12 + module App = 13 + 14 + let describeServerHandler : HttpHandler = 15 + fun next ctx -> 16 + let config = ctx.GetService<AppConfig>() 17 + 18 + // TODO: add to config 19 + let response = { 20 + availableUserDomains = [] 21 + did = config.DidHost 22 + inviteCodeRequired = true 23 + } 24 + 25 + json response next ctx 26 + 27 + let webApp = 28 + choose [ 29 + route "/xrpc/com.atproto.server.describeServer" >=> describeServerHandler 30 + route "/" >=> text "PDSharp PDS is running." 31 + RequestErrors.NOT_FOUND "Not Found" 32 + ] 33 + 34 + let configureApp (app : IApplicationBuilder) = app.UseGiraffe webApp 35 + 36 + let configureServices (config : AppConfig) (services : IServiceCollection) = 37 + services.AddGiraffe() |> ignore 38 + services.AddSingleton<AppConfig>(config) |> ignore 39 + 40 + [<EntryPoint>] 41 + let main args = 42 + let configBuilder = 43 + ConfigurationBuilder() 44 + .SetBasePath(AppContext.BaseDirectory) 45 + .AddJsonFile("appsettings.json", optional = false, reloadOnChange = true) 46 + .AddEnvironmentVariables(prefix = "PDSHARP_") 47 + .Build() 48 + 49 + let appConfig = configBuilder.Get<AppConfig>() 50 + 51 + Host 52 + .CreateDefaultBuilder(args) 53 + .ConfigureWebHostDefaults(fun webHostBuilder -> 54 + webHostBuilder.Configure(configureApp).ConfigureServices(configureServices appConfig) 55 + |> ignore) 56 + .Build() 57 + .Run() 58 + 59 + 0
+4
PDSharp/appsettings.json
···
··· 1 + { 2 + "PublicUrl": "http://localhost:5000", 3 + "DidHost": "did:web:localhost" 4 + }