chore: group API endpoints
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
LordMZTE 2023-08-06 22:15:12 +02:00
parent b6ca760a58
commit 25ac4c2fa3
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
3 changed files with 105 additions and 103 deletions

View file

@ -5,7 +5,7 @@ function onClick() {
Util.paused = !Util.paused;
var xhr = new XMLHttpRequest();
xhr.open("POST", Util.resolveUrl("set_paused"));
xhr.open("POST", Util.resolveUrl("api/set_paused"));
xhr.send(Std.string(Util.paused));
updateDisplay();

View file

@ -140,10 +140,10 @@ fn tryHandleRequest(state: *State, res_: std.http.Server.Response) !void {
if (std.mem.eql(u8, path, "/") or std.mem.eql(u8, path, "/index.html")) {
try routes.indexRoute(state, &res);
} else if (std.mem.eql(u8, path, "/index.json")) {
try routes.indexJsonRoute(state, &res);
} else if (std.mem.eql(u8, path, "/set_paused")) {
try routes.setPausedRoute(state, &res);
} else if (std.mem.eql(u8, path, "/api/index.json")) {
try routes.api.indexJsonRoute(state, &res);
} else if (std.mem.eql(u8, path, "/api/set_paused")) {
try routes.api.setPausedRoute(state, &res);
} else if (std.mem.eql(u8, path, "/static/index.js")) {
try routes.static(&res, assets.@"index.js", "application/javascript");
} else if (std.mem.eql(u8, path, "/static/index.css")) {

View file

@ -31,6 +31,106 @@ pub fn static(res: *std.http.Server.Response, data: []const u8, mime: ?[]const u
try res.finish();
}
pub const api = struct {
pub fn indexJsonRoute(
state: *State,
res: *std.http.Server.Response,
) !void {
const alloc = res.allocator;
const Response = struct {
active_task: ?DownloadQueue.Task,
tasks: []DownloadQueue.Task,
vids: [][]u8,
paused: bool,
};
var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit();
const arena_alloc = arena.allocator();
// TODO: optimize
const tasks = try alloc.alloc(DownloadQueue.Task, state.downloads.tasks.len());
defer alloc.free(tasks);
var cur_task = state.downloads.tasks.first;
var i: usize = 0;
while (cur_task) |t| : (i += 1) {
tasks[i] = t.data;
cur_task = t.next;
}
const vids_dir_path = try std.fs.path.join(alloc, &.{ state.conf.data_dir, "vids" });
defer alloc.free(vids_dir_path);
var vids_dir = try std.fs.cwd().openIterableDir(vids_dir_path, .{});
defer vids_dir.close();
var iter = vids_dir.iterate();
var vids = std.ArrayList([]u8).init(alloc);
defer vids.deinit();
while (try iter.next()) |ent| {
if (ent.kind != .file)
continue;
const quote = try std.Uri.escapeString(arena_alloc, ent.name);
try vids.append(try std.fmt.allocPrint(
alloc,
"{s}/vids/{s}",
.{ state.conf.base_url, quote },
));
}
try res.headers.append("Content-Type", "application/json");
// Streaming serialization to HTTP!
res.transfer_encoding = .chunked;
const data = Response{
.active_task = state.downloads.active_task,
.tasks = tasks,
.vids = vids.items,
.paused = state.downloads.paused,
};
try res.do();
var buf_writer = std.io.bufferedWriter(res.writer());
try std.json.stringify(data, .{}, buf_writer.writer());
try buf_writer.flush();
try res.finish();
}
pub fn setPausedRoute(
state: *State,
res: *std.http.Server.Response,
) !void {
const alloc = res.allocator;
if (res.request.method != .POST) {
try status_response.sendJsonResponseText(res, .method_not_allowed);
return;
}
const data = try res.reader().readAllAlloc(alloc, 1024);
defer alloc.free(data);
const paused = if (std.mem.eql(u8, data, "true"))
true
else if (std.mem.eql(u8, data, "false"))
false
else {
try status_response.sendJsonResponseText(res, .bad_request);
return;
};
std.log.info("setting paused state to {}", .{paused});
state.downloads.setPaused(paused);
try status_response.sendJsonResponseText(res, .ok);
}
};
pub fn indexRoute(
state: *State,
res: *std.http.Server.Response,
@ -180,75 +280,6 @@ pub fn indexRoute(
try res.finish();
}
pub fn indexJsonRoute(
state: *State,
res: *std.http.Server.Response,
) !void {
const alloc = res.allocator;
const Response = struct {
active_task: ?DownloadQueue.Task,
tasks: []DownloadQueue.Task,
vids: [][]u8,
paused: bool,
};
var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit();
const arena_alloc = arena.allocator();
// TODO: optimize
const tasks = try alloc.alloc(DownloadQueue.Task, state.downloads.tasks.len());
defer alloc.free(tasks);
var cur_task = state.downloads.tasks.first;
var i: usize = 0;
while (cur_task) |t| : (i += 1) {
tasks[i] = t.data;
cur_task = t.next;
}
const vids_dir_path = try std.fs.path.join(alloc, &.{ state.conf.data_dir, "vids" });
defer alloc.free(vids_dir_path);
var vids_dir = try std.fs.cwd().openIterableDir(vids_dir_path, .{});
defer vids_dir.close();
var iter = vids_dir.iterate();
var vids = std.ArrayList([]u8).init(alloc);
defer vids.deinit();
while (try iter.next()) |ent| {
if (ent.kind != .file)
continue;
const quote = try std.Uri.escapeString(arena_alloc, ent.name);
try vids.append(try std.fmt.allocPrint(
alloc,
"{s}/vids/{s}",
.{ state.conf.base_url, quote },
));
}
try res.headers.append("Content-Type", "application/json");
// Streaming serialization to HTTP!
res.transfer_encoding = .chunked;
const data = Response{
.active_task = state.downloads.active_task,
.tasks = tasks,
.vids = vids.items,
.paused = state.downloads.paused,
};
try res.do();
var buf_writer = std.io.bufferedWriter(res.writer());
try std.json.stringify(data, .{}, buf_writer.writer());
try buf_writer.flush();
try res.finish();
}
pub const ApiTask = struct {
url: []const u8,
outname: ?[]const u8,
@ -366,32 +397,3 @@ pub fn vidsRoute(
},
}
}
pub fn setPausedRoute(
state: *State,
res: *std.http.Server.Response,
) !void {
const alloc = res.allocator;
if (res.request.method != .POST) {
try status_response.sendJsonResponseText(res, .method_not_allowed);
return;
}
const data = try res.reader().readAllAlloc(alloc, 1024);
defer alloc.free(data);
const paused = if (std.mem.eql(u8, data, "true"))
true
else if (std.mem.eql(u8, data, "false"))
false
else {
try status_response.sendJsonResponseText(res, .bad_request);
return;
};
std.log.info("setting paused state to {}", .{paused});
state.downloads.setPaused(paused);
try status_response.sendJsonResponseText(res, .ok);
}