this repo has no description
at main 2.9 kB view raw
1const std = @import("std"); 2const xev = @import("xev"); 3 4const log = @import("log.zig"); 5 6const HeapArena = @import("HeapArena.zig"); 7const Server = @import("Server.zig"); 8const WorkerQueue = Server.WorkerQueue; 9 10/// Wrapper which authenticates with github 11pub fn authenticate( 12 arena: HeapArena, 13 client: *std.http.Client, 14 queue: *WorkerQueue, 15 fd: xev.TCP, 16 auth_header: []const u8, 17) !void { 18 errdefer { 19 queue.push(.{ .auth_failure = .{ 20 .arena = arena, 21 .fd = fd, 22 .msg = "github authentication failed", 23 } }); 24 } 25 26 log.debug("authenticating with github", .{}); 27 const endpoint = "https://api.github.com/user"; 28 29 var storage = std.ArrayList(u8).init(arena.allocator()); 30 31 const req: std.http.Client.FetchOptions = .{ 32 .response_storage = .{ .dynamic = &storage }, 33 .location = .{ .url = endpoint }, 34 .method = .GET, 35 .headers = .{ 36 .authorization = .{ .override = auth_header }, 37 }, 38 }; 39 const result = try fetch(client, req); 40 41 switch (result.status) { 42 .ok => { 43 const value = try std.json.parseFromSliceLeaky(std.json.Value, arena.allocator(), storage.items, .{}); 44 const resp = value.object; 45 const login = resp.get("login").?.string; 46 const avatar_url = resp.get("avatar_url").?.string; 47 const realname = resp.get("name").?.string; 48 const id = resp.get("id").?.integer; 49 queue.push(.{ 50 .auth_success = .{ 51 .arena = arena, 52 .fd = fd, 53 .nick = login, 54 .user = try std.fmt.allocPrint(arena.allocator(), "{d}", .{id}), 55 .realname = realname, 56 .avatar_url = avatar_url, 57 }, 58 }); 59 }, 60 .unauthorized, .forbidden => { 61 queue.push(.{ 62 .auth_failure = .{ 63 .arena = arena, 64 .fd = fd, 65 .msg = storage.items, 66 }, 67 }); 68 }, 69 else => { 70 log.warn("unexpected github response: {s}", .{storage.items}); 71 return error.UnexpectedResponse; 72 }, 73 } 74} 75 76/// Performs a fetch with retries 77fn fetch( 78 client: *std.http.Client, 79 request: std.http.Client.FetchOptions, 80) !std.http.Client.FetchResult { 81 const max_attempts: u2 = 3; 82 var attempts: u2 = 0; 83 while (true) { 84 const result = client.fetch(request) catch |err| { 85 if (attempts == max_attempts) return err; 86 defer attempts += 1; 87 const delay: u64 = @as(u64, 500 * std.time.ns_per_ms) << (attempts + 1); 88 log.warn("request failed, retrying in {d} ms", .{delay / std.time.ns_per_ms}); 89 std.time.sleep(delay); 90 continue; 91 }; 92 return result; 93 } 94}