an atproto pds written in F# (.NET 9) 馃
pds
fsharp
giraffe
dotnet
atproto
1锘縪pen System
2open Microsoft.AspNetCore.Builder
3open Microsoft.AspNetCore.Hosting
4open Microsoft.Extensions.Hosting
5open Microsoft.Extensions.DependencyInjection
6open Giraffe
7open PDSharp.Core
8open PDSharp.Core.Auth
9open PDSharp.Core.BlockStore
10open PDSharp.Core.SqliteStore
11open PDSharp.Core.BlobStore
12open PDSharp.Core.Config
13open PDSharp.Handlers
14
15let getConfig () =
16 let env (k : string) (def : string) =
17 match Environment.GetEnvironmentVariable k with
18 | null -> def
19 | v -> v
20
21 let publicUrl = env "PDSHARP_PublicUrl" "http://localhost:5000"
22 let dbPath = env "PDSHARP_DbPath" "pdsharp.db"
23
24 {
25 PublicUrl = publicUrl
26 DidHost = env "PDSHARP_DidHost" "did:web:localhost"
27 JwtSecret = env "PDSHARP_JwtSecret" "development-secret-do-not-use-in-prod"
28 SqliteConnectionString = $"Data Source={dbPath}"
29 BlobStore = Disk "blobs" // Default to disk for now
30 }
31
32let config = getConfig ()
33
34SqliteStore.initialize config.SqliteConnectionString
35
36module App =
37 let webApp =
38 choose [
39 GET
40 >=> choose [
41 route "/" >=> Server.indexHandler
42 route "/xrpc/com.atproto.server.describeServer" >=> Server.describeServerHandler
43 ]
44 POST
45 >=> route "/xrpc/com.atproto.server.createAccount"
46 >=> Auth.createAccountHandler
47 POST
48 >=> route "/xrpc/com.atproto.server.createSession"
49 >=> Auth.createSessionHandler
50 POST
51 >=> route "/xrpc/com.atproto.server.refreshSession"
52 >=> Auth.refreshSessionHandler
53 POST
54 >=> route "/xrpc/com.atproto.repo.createRecord"
55 >=> Repo.createRecordHandler
56 GET >=> route "/xrpc/com.atproto.repo.getRecord" >=> Repo.getRecordHandler
57 POST >=> route "/xrpc/com.atproto.repo.putRecord" >=> Repo.putRecordHandler
58 GET >=> route "/xrpc/com.atproto.sync.getRepo" >=> Sync.getRepoHandler
59 GET >=> route "/xrpc/com.atproto.sync.getBlocks" >=> Sync.getBlocksHandler
60 GET >=> route "/xrpc/com.atproto.sync.getBlob" >=> Sync.getBlobHandler
61 GET
62 >=> route "/xrpc/com.atproto.sync.subscribeRepos"
63 >=> Sync.subscribeReposHandler
64 route "/" >=> text "PDSharp PDS is running."
65 RequestErrors.NOT_FOUND "Not Found"
66 ]
67
68 let configureApp (app : IApplicationBuilder) =
69 app.UseWebSockets() |> ignore
70 app.UseGiraffe webApp
71
72 let configureServices (config : AppConfig) (services : IServiceCollection) =
73 services.AddGiraffe() |> ignore
74 services.AddSingleton<AppConfig>(config) |> ignore
75
76 let blockStore = new SqliteBlockStore(config.SqliteConnectionString)
77 let accountStore = new SqliteAccountStore(config.SqliteConnectionString)
78 let repoStore = new SqliteRepoStore(config.SqliteConnectionString)
79
80 services.AddSingleton<IBlockStore>(blockStore) |> ignore
81 services.AddSingleton<IAccountStore>(accountStore) |> ignore
82 services.AddSingleton<IRepoStore>(repoStore) |> ignore
83
84 let blobStore : IBlobStore =
85 match config.BlobStore with
86 | Disk path -> new DiskBlobStore(path) :> IBlobStore
87 | S3 s3Config -> new S3BlobStore(s3Config) :> IBlobStore
88
89 services.AddSingleton<IBlobStore>(blobStore) |> ignore
90 services.AddSingleton<FirehoseState>(new FirehoseState()) |> ignore
91 services.AddSingleton<SigningKeyStore>(new SigningKeyStore()) |> ignore
92
93 [<EntryPoint>]
94 let main args =
95 Host
96 .CreateDefaultBuilder(args)
97 .ConfigureWebHostDefaults(fun webHostBuilder ->
98 webHostBuilder.Configure(configureApp).ConfigureServices(configureServices config)
99 |> ignore)
100 .Build()
101 .Run()
102
103 0