╭ changed ───╮ │src/push.zig│ ╰────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │11 const srch_cmmt = @import("search_commit.zig"); │ │12 const fork = @import("fork.zig"); │ │13 const serve_common = @import("serve_common.zig"); │ │14 - │ │15 -pub const PushProgress = struct { │ │16 - response: *xit.net_server_receive_pack.Response, │ │17 - writer: *std.Io.Writer, │ │18 - label: []const u8 = "Processing commits", │ │19 - count: usize = 0, │ │20 - total: usize = 0, │ │21 - // the last reported step, so a line is sent only when it changes │ │22 - step: usize = 0, │ │23 - │ │24 - // how many items a phase with no total advances between reports │ │25 - const report_every = 1000; │ │26 - │ │27 - // the phases a push reports: the objects unpacked from the pack it │ │28 - // received, then everything counted after it │ │29 - fn reported(kind: rp.ProgressKind) bool { │ │30 - return kind == .writing_object_from_pack or kind == .writing_patch; │ │31 - } │ │14 +const ssh = @import("serve_ssh_protocol.zig"); │ │15 │ │33 - pub fn run(self: *PushProgress, _: std.Io, event: rp.ProgressEvent) !void { │ │34 - switch (event) { │ │35 - .start => |start| { │ │36 - if (!reported(start.kind)) return; │ │37 - // the unpack phase sends no label of its own │ │38 - if (start.kind == .writing_object_from_pack) self.label = "Unpacking objects"; │ │39 - self.total = start.estimated_total_items; │ │40 - self.count = 0; │ │41 - self.step = 0; │ │42 - }, │ │43 - .complete_one => |kind| { │ │44 - if (!reported(kind)) return; │ │45 - self.count += 1; │ │46 - }, │ │47 - .end => |kind| { │ │48 - if (!reported(kind)) return; │ │49 - }, │ │50 - // each phase names itself before reporting its count │ │51 - .text => |text| { │ │52 - self.label = text; │ │53 - return; │ │54 - }, │ │55 - else => return, │ │56 - } │ │57 - // a phase that knows no total counts instead, and stays quiet until it │ │58 - // has something to count │ │59 - if (self.total == 0 and self.count == 0) return; │ │60 - │ │61 - // every report flushes, so one is sent per percent, or per block of │ │62 - // items when there is no total to turn into one │ │63 - const step: usize = if (self.total > 0) @intCast(@as(u128, self.count) * 100 / self.total) else self.count / report_every;│ │64 - if (event == .complete_one and step == self.step) return; │ │65 - self.step = step; │ │66 - │ │67 - var buffer: [128]u8 = undefined; │ │68 - const suffix = if (event == .end) "\n" else "\r"; │ │69 - const text = if (self.total > 0) │ │70 - try std.fmt.bufPrint(&buffer, "{s}: {d}% ({d}/{d}){s}", .{ self.label, step, self.count, self.total, suffix }) │ │71 - else │ │72 - try std.fmt.bufPrint(&buffer, "{s}: {d}{s}", .{ self.label, self.count, suffix }); │ │73 - try self.response.progress(self.writer, text); │ │74 - } │ │75 -}; │ │76 - │ │16 // prepare all reachable commits, including history received before patch │ │17 // generation was enabled. this shares the receive-pack transaction. │ │18 pub fn writeReceivedPatches( │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │ 36 try iter.include(&oid); │ │ 37 } │ │ 38 } │ │100 - var progress = PushProgress{ .response = response, .writer = writer }; │ │ 39 + var progress = serve_common.PushProgress{ .response = response, .writer = writer };│ │ 40 try xit.patch.writePatches(repo_opts, state, io, allocator, &iter, &progress); │ │ 41 } │ │ 42 │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────╮ │121 author: ?evt.CommitAuthor, │ │122 repo_root_path: []const u8, │ │123 error_writer: *std.Io.Writer, │ │124 + sess: ?*ssh.SessionCtx, │ │125 ) !void { │ │126 const DB = rp.Repo(.xit, repo_opts).DB; │ │127 const State = rp.Repo(.xit, repo_opts).State;│ ╰──────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │132 var updates = xit.net_server_receive_pack.AppliedRefUpdates.init(allocator); │ │133 defer updates.deinit(); │ │134 │ │195 - var progress = PushProgress{ .response = &response, .writer = writer }; │ │135 + var progress = serve_common.PushProgress{ .response = &response, .writer = writer, .sess = sess };│ │136 const Ctx = struct { │ │137 updates: *xit.net_server_receive_pack.AppliedRefUpdates, │ │138 core: *rp.Repo(.xit, repo_opts).Core, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │145 response: *xit.net_server_receive_pack.Response, │ │146 repo_root_path: []const u8, │ │147 error_writer: *std.Io.Writer, │ │208 - progress: *PushProgress, │ │148 + progress: *serve_common.PushProgress, │ │149 │ │150 pub fn run(ctx: @This(), cursor: *DB.Cursor(.read_write)) !void {│ │151 var moment = try DB.HashMap(.read_write).init(cursor.*); │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │156 receive_options.deferred_response = ctx.response; │ │157 try xit.net_server_receive_pack.run(.xit, repo_opts, state, ctx.io, ctx.allocator, ctx.reader, ctx.writer, receive_options, ctx.progress);│ │158 try writeReceivedPatches(repo_opts, state, ctx.io, ctx.allocator, ctx.response, ctx.writer); │ │159 + if (ctx.progress.gone) return error.ClientGone; │ │160 │ │161 // a repo without an events branch has no events to consume. a │ │162 // no-op consume must not cancel here, since the push shares the │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │169 _ = try pch.refreshBranchesInTransaction(.server, repo_opts, state, &moment, ctx.io, ctx.allocator, ctx.updates.items.items, null, ctx.progress);│ │170 } │ │171 │ │172 + if (ctx.progress.gone) return error.ClientGone; │ │173 + │ │174 // the indexes the pushed refs invalidate belong to the push too │ │175 _ = try find.refreshInTransaction(repo_opts, state, &moment, ctx.io, ctx.allocator, ctx.progress); │ │176 _ = try srch_cmmt.refreshInTransaction(repo_opts, state, &moment, ctx.io, ctx.allocator, ctx.updates.items.items, ctx.progress); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────╮ │227 reader: *std.Io.Reader, │ │228 writer: *std.Io.Writer, │ │229 error_writer: *std.Io.Writer, │ │230 + sess: ?*ssh.SessionCtx, │ │231 ) !void { │ │232 const patch_id = try evt.parseEventId(id); │ │233 var arena = std.heap.ArenaAllocator.init(allocator);│ ╰─────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │260 var revision_id_maybe: ?[evt.event_id_size]u8 = null; │ │261 var response = xit.net_server_receive_pack.Response.init(allocator); │ │262 defer response.deinit(); │ │319 - var progress = PushProgress{ .response = &response, .writer = writer }; │ │263 + var progress = serve_common.PushProgress{ .response = &response, .writer = writer, .sess = sess };│ │264 │ │265 // execute a transaction that receives the push and materializes its revision │ │266 const result = blk: { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │283 timestamp: u64, │ │284 newest: ?evt.PatchRev.WithId, │ │285 revision_id_maybe: *?[evt.event_id_size]u8, │ │342 - progress: *PushProgress, │ │286 + progress: *serve_common.PushProgress, │ │287 │ │288 pub fn run(ctx: @This(), cursor: *DB.Cursor(.read_write)) !void {│ │289 // receive the branch update │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯