forked from Tacodiva/Motely
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEndpoints.cs
More file actions
166 lines (139 loc) · 5.57 KB
/
Endpoints.cs
File metadata and controls
166 lines (139 loc) · 5.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using Microsoft.AspNetCore.Mvc;
using Motely.API.Services;
using Microsoft.AspNetCore.Http;
using System.Text.Json;
using Motely;
using Motely.API;
using Motely.API.Models;
namespace Motely.API;
public static class Endpoints
{
public static IResult GetFilters()
{
try
{
var filters = FilterService.LoadFiltersFromDisk(MotelyPaths.JamlFiltersDir, cfg => false);
return Results.Ok(filters);
}
catch (Exception ex)
{
return Results.Problem($"Error loading filters: {ex.Message}");
}
}
public static IResult GetSeedSources()
{
var results = new List<object>
{
new { key = "all", label = "All Seeds", kind = "builtin" }
};
var seedSourcesDir = MotelyPaths.SeedSourcesDir;
if (Directory.Exists(seedSourcesDir))
{
foreach (var file in Directory.GetFiles(seedSourcesDir, "*.*")
.Where(f => f.EndsWith(".db") || f.EndsWith(".txt") || f.EndsWith(".csv"))
.Select(Path.GetFileName)
.Where(f => f != null)
.Cast<string>())
{
var ext = Path.GetExtension(file).TrimStart('.').ToLowerInvariant();
var (category, displayName) = SeedSourceHelper.ParseCategoryFromFileName(file);
results.Add(new
{
key = $"{ext}:{file}",
label = displayName,
kind = ext,
fileName = file
});
}
}
return Results.Ok(new { sources = results });
}
public static IResult GetSearches()
{
var allSearches = SearchManager.Instance.GetActiveSearchesStatus();
var searches = allSearches.Select(s => new
{
id = s.SearchId,
searchId = s.SearchId,
filterName = s.FilterName,
deck = s.Deck,
stake = s.Stake,
completedBatches = s.CompletedBatches,
totalBatches = s.TotalBatches,
seedsSearched = s.SeedsSearched,
seedsPerSecond = s.SeedsPerSecond,
resultsFound = s.ResultsFound,
isRunning = s.IsRunning,
isFastLane = s.IsFastLane,
inQueue = s.InQueue,
stopReason = s.StopReason
}).ToList();
return Results.Ok(new { searches });
}
public static async Task<IResult> StartSearch(HttpRequest req)
{
var request = await req.ReadFromJsonAsync<SearchStartRequest>();
if (request?.FilterId == null) return Results.BadRequest();
var filterJaml = FilterService.GetFilterJaml(request.FilterId);
if (string.IsNullOrEmpty(filterJaml))
return Results.BadRequest("Filter not found");
(List<SearchResult> immediateResults, string searchId) = await SearchManager.Instance.StartSearchAsync(
filterJaml, "Red", "White",
(int)(request.SeedCount ?? 0),
request.StartBatch, request.Cutoff, request.SeedSource);
return Results.Ok(new { searchId });
}
public static IResult GetSearch(string id)
{
var (results, progress) = SearchManager.Instance.GetSearchStatus(id);
return Results.Ok(new { results, progress });
}
public static async Task<IResult> StopSearch(string id)
{
await SearchManager.Instance.StopSearchAsync(id);
return Results.Ok();
}
public static async Task<IResult> SaveFilter(string id, HttpRequest req)
{
var request = await req.ReadFromJsonAsync<FilterSaveRequest>();
if (request?.FilterJaml == null) return Results.BadRequest();
var jamlFiltersDir = MotelyPaths.JamlFiltersDir;
// Use id from route, or extract name from JAML
string? name = id;
if (JamlConfigLoader.TryLoadFromJamlString(request.FilterJaml, out var cfg, out _) && cfg != null)
{
name = cfg.Name ?? id;
}
// Sanitize name to prevent path traversal attacks
if (!FilterService.TrySanitizeFilterName(name, out var safeName))
return Results.BadRequest("Invalid filter name");
var fileName = $"{safeName}.jaml";
var filePath = Path.Combine(jamlFiltersDir, fileName);
// Validate that the resolved path is within the expected directory
if (!FilterService.IsPathWithinDirectory(filePath, jamlFiltersDir, out var fullFilePath))
{
return Results.BadRequest("Invalid filter path");
}
File.WriteAllText(fullFilePath, request.FilterJaml);
return Results.Ok(new { filePath = fileName });
}
public static IResult DeleteFilter(string id)
{
// Sanitize id to prevent path traversal attacks
if (!FilterService.TrySanitizeFilterName(id, out var safeName))
return Results.BadRequest("Invalid filter name");
var fileName = $"{safeName}.jaml";
var filePath = Path.Combine(MotelyPaths.JamlFiltersDir, fileName);
// Validate that the resolved path is within the expected directory
if (!FilterService.IsPathWithinDirectory(filePath, MotelyPaths.JamlFiltersDir, out var fullFilePath))
{
return Results.BadRequest("Invalid filter path");
}
if (File.Exists(fullFilePath))
{
File.Delete(fullFilePath);
return Results.Ok();
}
return Results.NotFound();
}
}