Skip to content

Commit

Permalink
Merge pull request #289 from sixwaaaay/valkey
Browse files Browse the repository at this point in the history
feat: integrate valkey
  • Loading branch information
sixwaaaay authored Jan 31, 2025
2 parents cd65058 + 218c12f commit 9cbcf95
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 11 deletions.
2 changes: 1 addition & 1 deletion sharp/content.Tests/DomainTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class DomainTest
{

private (Mock<IVideoRepository>, Mock<IUserRepository> userRepo, Mock<IVoteRepository> voteRepo, Mock<SearchClient> searchClient) Setup() =>
(new Mock<IVideoRepository>(), new Mock<IUserRepository>(), new Mock<IVoteRepository>(), new Mock<SearchClient>(null!));
(new Mock<IVideoRepository>(), new Mock<IUserRepository>(), new Mock<IVoteRepository>(), new Mock<SearchClient>(null!,null!));

[Fact]
public async Task FindById_ReturnsVideoDto_WhenVideoExists()
Expand Down
9 changes: 8 additions & 1 deletion sharp/content.Tests/repository/ClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using content.repository;
using Moq;
using Moq.Protected;
using StackExchange.Redis;

namespace content.Tests.repository;

Expand Down Expand Up @@ -183,7 +184,7 @@ public async Task SimilarSearch_ReturnsListOfVideoIds()
};
mockFactory.Setup(_ => _.CreateClient("Search")).Returns(client);

var searchClient = new SearchClient(mockFactory.Object);
var searchClient = new SearchClient(mockFactory.Object, ConnectionMultiplexer.Connect("localhost").GetDatabase());

mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
Expand All @@ -203,6 +204,12 @@ public async Task SimilarSearch_ReturnsListOfVideoIds()
// Assert
Assert.Equal(expectedResponse.Hits.Select(h => h.Id).ToList(), result);


// Again
result = await searchClient.SimilarSearch(videoId);

// Assert
Assert.Equal(expectedResponse.Hits.Select(h => h.Id).ToList(), result);
}
}

Expand Down
3 changes: 2 additions & 1 deletion sharp/content/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Default": "Server=db; User ID=name; Password=passwd; Database=db;",
"User": "http://user:8080",
"Vote": "http://graph:8088",
"Search": "http://localhost:7700"
"Search": "http://localhost:7700",
"Redis": "localhost:6379"
},
"Secret": "secret",
"Token": "this is a token for search"
Expand Down
1 change: 1 addition & 0 deletions sharp/content/content.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageReference Include="Riok.Mapperly" Version="4.1.0" />
<PackageReference Include="FluentValidation" Version="11.10.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.24" />
</ItemGroup>

<ItemGroup>
Expand Down
31 changes: 23 additions & 8 deletions sharp/content/repository/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Json;
using System.Text.Json.Serialization;
using StackExchange.Redis;

namespace content.repository;

Expand Down Expand Up @@ -57,7 +59,7 @@ public async Task<User> FindById(long id)
var req = new HttpRequestMessage(HttpMethod.Get, $"/users/{id}");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Token);
Console.WriteLine(client.BaseAddress);
var resp = await client.SendAsync(req);
using var resp = await client.SendAsync(req);
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadFromJsonAsync(UserJsonContext.Default.User) ?? new();
}
Expand All @@ -67,7 +69,7 @@ public async Task<IReadOnlyList<User>> FindAllByIds(IEnumerable<long> ids)
var req = new HttpRequestMessage(HttpMethod.Get,
$"/users?{string.Join("&", ids.Distinct().Select(id => $"ids={id}"))}");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Token);
var resp = await client.SendAsync(req);
using var resp = await client.SendAsync(req);
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadFromJsonAsync(UserJsonContext.Default.IReadOnlyListUser) ?? [];
}
Expand Down Expand Up @@ -113,7 +115,7 @@ public async Task<IReadOnlyList<long>> VotedOfVideos(List<long> videoIds)
}


var resp = await client.SendAsync(req);
using var resp = await client.SendAsync(req);
resp.EnsureSuccessStatusCode();

var result = await resp.Content.ReadFromJsonAsync(VoteJsonContext.Default.ListInt64) ?? [];
Expand All @@ -128,7 +130,7 @@ public async Task<IReadOnlyList<long>> VotedOfVideos(List<long> videoIds)
req.Headers.Authorization = auth;
}

var resp = await client.SendAsync(req);
using var resp = await client.SendAsync(req);

resp.EnsureSuccessStatusCode();

Expand All @@ -150,20 +152,29 @@ public record InQuery(List<long> ObjectIds);
[JsonSerializable(typeof(InQuery))]
internal partial class VoteJsonContext : JsonSerializerContext;

public class SearchClient(IHttpClientFactory clientFactory)
public class SearchClient(IHttpClientFactory clientFactory, IDatabase db)
{
public async Task<IReadOnlyList<long>> SimilarSearch(long videoId)
{
var cache = await db.StringGetAsync($"similar:{videoId}");
if (cache.HasValue)
{
return JsonSerializer.Deserialize(cache!, SearchContext.Default.ListInt64) ?? [];
}

using var client = clientFactory.CreateClient("Search");
var body = new RequestBody(videoId, ["id"]);
var content = JsonContent.Create(body, SearchContext.Default.RequestBody);
var req = new HttpRequestMessage(HttpMethod.Post, "/indexes/videos/similar") { Content = content };
var resp = await client.SendAsync(req);
using var resp = await client.SendAsync(req);
resp.EnsureSuccessStatusCode();

var result = await resp.Content.ReadFromJsonAsync(SearchContext.Default.Response) ?? new Response();

return result.Hits.Select(h => h.Id).ToList();
var ids = result.Hits.Select(h => h.Id).ToList();
await db.StringSetAsync($"similar:{videoId}", JsonSerializer.Serialize(ids, SearchContext.Default.ListInt64), TimeSpan.FromSeconds(60));

return ids;
}
}

Expand All @@ -179,8 +190,10 @@ public record Response()

public record SimilarVideo([property: JsonPropertyName("id")] long Id);


[JsonSerializable(typeof(Response))]
[JsonSerializable(typeof(RequestBody))]
[JsonSerializable(typeof(List<long>))]
public partial class SearchContext : JsonSerializerContext;

public static class Extension
Expand All @@ -193,11 +206,13 @@ public static IServiceCollection AddVoteRepository(this IServiceCollection servi
.GetConnectionString("Vote").EnsureNotNull("Vote connection string is null").TrimEnd('/'))).Services;

public static IServiceCollection AddSearchClient(this IServiceCollection services) => services
.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(sp.GetRequiredService<IConfiguration>().GetConnectionString("Redis").EnsureNotNull("Redis connection string is null")))
.AddSingleton(sp => sp.GetRequiredService<IConnectionMultiplexer>().GetDatabase())
.AddScoped<SearchClient>().AddHttpClient("Search", (sp, client) =>
{
var baseAddress = sp.GetRequiredService<IConfiguration>().GetConnectionString("Search")
.EnsureNotNull("Search connection string is null");
var token = sp.GetRequiredService<IConfiguration>().GetConnectionString("Token");
var token = sp.GetRequiredService<IConfiguration>()["Token"];
client.BaseAddress = new Uri(baseAddress.TrimEnd('/'));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}).Services;
Expand Down

0 comments on commit 9cbcf95

Please sign in to comment.