Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions API/Scoop/Converters/LicenseJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Text.Json.Serialization;
using System.Text.Json;
using Scoop.Responses;
using System.Linq;
using System.Collections.Generic;

namespace Scoop.Converters;

internal class LicenseJsonConverter : JsonConverter<LicenseInfo>
{
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(string) || base.CanConvert(typeToConvert);

public override LicenseInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType is JsonTokenType.Null)
return null;

if (reader.TokenType is JsonTokenType.String)
{
var singleString = reader.GetString();
if (Uri.TryCreate(singleString, UriKind.Absolute, out var licenseUri))
{
return new()
{
Url = licenseUri
};
}

return new()
{
MultiLicenses = ParseIdentifiers(singleString!)
};
}

if (reader.TokenType is not JsonTokenType.StartObject)
throw new JsonException($"Expected the start of an object.");

Dictionary<string, string> properties = [];

while (reader.TokenType is not JsonTokenType.EndObject)
{
if (!reader.Read() || reader.TokenType is not JsonTokenType.PropertyName)
break;
var propertyName = reader.GetString();

if (!reader.Read() || reader.TokenType is not JsonTokenType.String)
throw new JsonException("Expected property value");
var propertyValue = reader.GetString();

properties[propertyName!] = propertyValue!;
}

LicenseInfo license = new();

if (properties.TryGetValue("identifier", out var identifierStr))
license.MultiLicenses = ParseIdentifiers(identifierStr);

if (properties.TryGetValue("url", out var urlStr) && Uri.TryCreate(urlStr, UriKind.Absolute, out var url))
license.Url = url;

return license;
}

public override void Write(Utf8JsonWriter writer, LicenseInfo value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}

private static List<List<string>> ParseIdentifiers(string value)
{
// Apps can be dual-licensed, and their different files within them can have different licenses.
// Dual-licenses are split by '|', and internal licenses by ','.

return value
.Split('|')
.Select(d => d.Split(',').ToList())
.ToList();
}
}
57 changes: 57 additions & 0 deletions API/Scoop/Converters/StringOrArrayJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Scoop.Responses;

namespace Scoop.Converters;

internal class StringOrArrayJsonConverter : JsonConverter<StringOrArray>
{
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(string) || base.CanConvert(typeToConvert);

public override StringOrArray? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType is JsonTokenType.Null)
return [];

if (reader.TokenType is JsonTokenType.String)
return [reader.GetString()];

if (reader.TokenType is not JsonTokenType.StartArray)
throw new JsonException($"Expected the start of a string array.");

StringOrArray list = [];

while (reader.Read() && reader.TokenType is not JsonTokenType.EndArray)
{
var str = JsonSerializer.Deserialize<string>(ref reader, options)
?? throw new JsonException($"Unexpected null value could not be converted to List<string>.");

list.Add(str);
}

return list;
}

public override void Write(Utf8JsonWriter writer, StringOrArray value, JsonSerializerOptions options)
{
if (value is null)
{
writer.WriteNullValue();
return;
}

if (value.Count == 1)
{
writer.WriteStringValue(value[0]);
return;
}

writer.WriteStartArray();

foreach (var str in value)
writer.WriteStringValue(str);

writer.WriteEndArray();
}
}
20 changes: 20 additions & 0 deletions API/Scoop/IScoopAppManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Scoop;

public interface IScoopAppManager
{
Task InstallAsync(string name, CancellationToken token = default);

Task DownloadAsync(string name, CancellationToken token = default);

Task UpdateAsync(string name, CancellationToken token = default);

Task UninstallAsync(string name, CancellationToken token = default);

IAsyncEnumerable<object> GetInstalledAppsAsync(string name, CancellationToken token = default);

Task<object> GetAppInfoAsync(string name, CancellationToken token = default);
}
17 changes: 17 additions & 0 deletions API/Scoop/IScoopBucketManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Scoop.Responses;

namespace Scoop;

public interface IScoopBucketManager
{
Task AddBucketAsync(string name, string? repo = null, CancellationToken token = default);

Task RemoveBucketAsync(string name, CancellationToken token = default);

IAsyncEnumerable<string> GetKnownBucketsAsync(CancellationToken token = default);

IAsyncEnumerable<Bucket> GetBucketsAsync(CancellationToken token = default);
}
13 changes: 13 additions & 0 deletions API/Scoop/IScoopMetadataService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Scoop.Responses;
using System.Threading.Tasks;
using System.Threading;
using Flurl;

namespace Scoop;

public interface IScoopMetadataService
{
Task<Manifest> GetManifestAsync(SearchResultMetadata metadata, CancellationToken token = default);

Task<Manifest> GetManifestAsync(Url metadataUrl, CancellationToken token = default);
}
10 changes: 10 additions & 0 deletions API/Scoop/IScoopSearchService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using System.Threading;
using Scoop.Responses;

namespace Scoop;

public interface IScoopSearchService
{
Task<SearchResponse> SearchAsync(string query, int count = 20, int skip = 0, CancellationToken token = default);
}
44 changes: 44 additions & 0 deletions API/Scoop/Requests/SearchRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Scoop.Requests;

public class SearchRequest
{
[JsonPropertyName("count")]
public bool Count { get; set; }

[JsonPropertyName("search")]
public string Search { get; set; }

[JsonPropertyName("searchMode")]
public string SearchMode { get; set; }

[JsonPropertyName("filter")]
public string Filter { get; set; }

[JsonPropertyName("orderby")]
public string OrderBy { get; set; }

[JsonPropertyName("skip")]
public int Skip { get; set; }

[JsonPropertyName("top")]
public int Top { get; set; } = 20;

[JsonPropertyName("select")]
public string Select { get; set; }

[JsonPropertyName("facets")]
public List<string> Facets { get; set; } = [];

[JsonPropertyName("highlight")]
public string Highlight { get; set; } = string.Empty;

[JsonPropertyName("highlightPreTag")]
public string HighlightPreTag { get; set; } = string.Empty;

[JsonPropertyName("highlightPostTag")]
public string HighlightPostTag { get; set; } = string.Empty;
}

14 changes: 14 additions & 0 deletions API/Scoop/Responses/Bucket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Scoop.Responses;

public class Bucket
{
public string Name { get; set; }

public string Source { get; set; }

public DateTime Updated { get; set; }

public int Manifests { get; set; }
}
Loading