Skip to content

Commit 818b9b4

Browse files
committed
Adding generation of followers
1 parent a8a3bcd commit 818b9b4

File tree

4 files changed

+118
-3
lines changed

4 files changed

+118
-3
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System.Security.Cryptography;
2+
using System.Text;
3+
using System.Text.Json;
4+
using Azure.Data.Tables;
5+
using Azure.Storage.Blobs;
6+
using Azure.Storage.Blobs.Models;
7+
8+
namespace ActivityPubDotNet.Core.Storage
9+
{
10+
public class FollowersGenerator(TableServiceClient tableServiceClient, BlobServiceClient blobServiceClient)
11+
{
12+
internal class ContextNamePolicy : JsonNamingPolicy
13+
{
14+
public override string ConvertName(string name)
15+
{
16+
if (name.Equals("_context"))
17+
{
18+
return "@context";
19+
}
20+
21+
return name;
22+
}
23+
}
24+
25+
private readonly TableServiceClient tableServiceClient = tableServiceClient;
26+
27+
private readonly BlobServiceClient blobServiceClient = blobServiceClient;
28+
29+
private const string FollowersTable = "followers";
30+
31+
public string Domain { get; set; } = default!;
32+
33+
public async Task Generate()
34+
{
35+
var table = tableServiceClient.GetTableClient(FollowersTable);
36+
37+
var query = table.QueryAsync<Reply>();
38+
39+
var items = new List<string>();
40+
41+
await foreach (var item in query)
42+
{
43+
items.Add(item.Id);
44+
}
45+
46+
var repliesPage = new
47+
{
48+
_context = "https://www.w3.org/ns/activitystreams",
49+
// generate Id
50+
id = $"{Domain!}/socialweb/followers",
51+
type = "CollectionPage",
52+
items
53+
};
54+
55+
//Store into a blob in the container $web, and path "/socialweb/replies/{noteId}"
56+
57+
var containerClient = blobServiceClient.GetBlobContainerClient("$web");
58+
59+
// Serialize the repliesPage object to JSON
60+
string jsonContent = JsonSerializer.Serialize(repliesPage, new JsonSerializerOptions
61+
{
62+
PropertyNamingPolicy = new ContextNamePolicy(),
63+
WriteIndented = true
64+
});
65+
66+
// Generate blob name using MD5 hash of the noteUrl
67+
string blobName = $"socialweb/followers";
68+
69+
// Get a reference to the blob
70+
var blobClient = containerClient.GetBlobClient(blobName);
71+
72+
var blobHttpHeaders = new BlobHttpHeaders
73+
{
74+
ContentType = "application/activity+json" // Set your custom content type here
75+
};
76+
77+
// Upload the JSON content to the blob
78+
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonContent)))
79+
{
80+
await blobClient.UploadAsync(stream,
81+
new BlobUploadOptions
82+
{
83+
HttpHeaders = blobHttpHeaders,
84+
Conditions = default
85+
});
86+
}
87+
}
88+
}
89+
}

src/ActivityPubFunctions/FollowService.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,16 @@
66

77
namespace ActivityPubDotNet
88
{
9-
public class FollowService(TableServiceClient tableServiceClient, ActorHelper actorHelper)
9+
public class FollowService(TableServiceClient tableServiceClient, ActorHelper actorHelper, FollowersGenerator followersGenerator)
1010
{
11+
private readonly FollowersGenerator _followersGenerator = followersGenerator;
12+
13+
public string Domain { get; set; } = default!;
14+
15+
public string FollowersUrl => $"{Domain}/socialweb/followers";
16+
17+
public string FollowersPath => $"/socialweb/followers";
18+
1119
public ILogger? Logger { get; set; }
1220

1321
private readonly string FollowersTable = "followers";
@@ -56,6 +64,11 @@ public async Task CreateFollower(InboxMessage message)
5664
}
5765
}
5866

67+
public async Task UpdateFollowersCollection()
68+
{
69+
await _followersGenerator.Generate();
70+
}
71+
5972
public async Task DeleteFollower(InboxMessage message)
6073
{
6174
await _tableServiceClient.CreateTableIfNotExistsAsync(FollowersTable);
@@ -111,7 +124,7 @@ public async Task<AcceptRequest> SendAcceptedFollowRequest(InboxMessage message)
111124
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
112125
};
113126

114-
await _actorHelper.SendSignedRequest(JsonSerializer.Serialize(acceptRequest, options), new Uri(actor.Inbox));
127+
await _actorHelper.SendPostSignedRequest(JsonSerializer.Serialize(acceptRequest, options), new Uri(actor.Inbox));
115128

116129
return acceptRequest;
117130
}

src/ActivityPubFunctions/Inbox.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymou
6060
if (message?.IsFollow() ?? false)
6161
{
6262
await _followService.Follow(message);
63+
64+
await _followService.UpdateFollowersCollection();
6365
}
6466
else if (message?.IsUndoFollow() ?? false)
6567
{
@@ -85,6 +87,8 @@ public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymou
8587
_logger?.LogInformation($"Sending accept request to {actor.Inbox} - {document}");
8688

8789
await _actorHelper.SendPostSignedRequest(document, new Uri(actor.Inbox));
90+
91+
await _followService.UpdateFollowersCollection();
8892
}
8993
else if (message?.IsCreateActivity() ?? false)
9094
{

src/ActivityPubFunctions/Program.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@
4040
provider.GetRequiredService<RepliesGenerator>(),
4141
domain);
4242
}).AddSingleton(provider =>
43+
{
44+
return new FollowersGenerator(
45+
provider.GetRequiredService<TableServiceClient>(),
46+
provider.GetRequiredService<BlobServiceClient>())
47+
{
48+
Domain = hostContext.Configuration.GetSection("BaseDomain").Value!
49+
};
50+
}).AddSingleton(provider =>
4351
{
4452
var privatePem = hostContext.Configuration.GetSection("ActorPrivatePEMKey").Value;
4553
var keyId = hostContext.Configuration.GetSection("ActorKeyId").Value;
@@ -49,7 +57,8 @@
4957
{
5058
return new FollowService(
5159
provider.GetRequiredService<TableServiceClient>(),
52-
provider.GetRequiredService<ActorHelper>());
60+
provider.GetRequiredService<ActorHelper>(),
61+
provider.GetRequiredService<FollowersGenerator>());
5362
}).AddSingleton(provider =>
5463
{
5564
return new ServerConfig()

0 commit comments

Comments
 (0)