╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │28 │ │29 pub const SessionHandler = struct { │ │30 admin_repo_path: []const u8, │ │31 - users_dir: []const u8, │ │31 + // where event writes go │ │32 + server: evt.Host.Server, │ │33 wui_port: u16, // port the web UI is served on, shown in the TUI footer's url│ │34 git_http_port: ?u16, │ │35 git_ssh_port: ?u16, │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────╮ │237 ui_session.data.git_ssh_prefix = handler.git_ssh_prefix;│ │238 // let page builders open on-disk repos │ │239 ui_session.io = io; │ │239 - ui_session.users_dir = handler.users_dir; │ │240 + ui_session.users_dir = handler.server.users_dir; │ │241 + ui_session.dirty_repos = handler.server.dirty_repos; │ │242 │ │243 var nav = try ui.Nav.init(allocator, &ui_session); │ │244 defer nav.deinit(allocator); │ ╰─────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │386 const owner_repo = evt.parseOwnerRepoPath(repo_identity) orelse return writeError(sess, "repo path must be <owner>:<repo>"); │ │387 var author_arena = std.heap.ArenaAllocator.init(allocator); │ │388 defer author_arena.deinit(); │ │387 - const author = switch (try authorizeRepoKey(io, &author_arena, handler.admin_repo_path, handler.users_dir, owner_repo.owner, owner_repo.name, parsed.service, &sess.fingerprint)) { │ │389 + const author = switch (try authorizeRepoKey(io, &author_arena, handler.admin_repo_path, handler.server.users_dir, owner_repo.owner, owner_repo.name, parsed.service, &sess.fingerprint)) {│ │390 .allowed => |user| user, │ │391 .create => |creator| return runCreatingPush(handler, sess, &creator, owner_repo.name, protocol_version, &reader.interface, &writer.interface), │ │392 .denied => return switch (parsed.service) { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │396 .not_found => return writeError(sess, "repo not found"), │ │397 }; │ │398 │ │397 - const repo_path = switch (try serve_common.resolveRepoPath(io, allocator, handler.users_dir, handler.admin_repo_path, repo_identity)) { │ │399 + const repo_path = switch (try serve_common.resolveRepoPath(io, allocator, handler.server.users_dir, handler.admin_repo_path, repo_identity)) {│ │400 .ok => |p| p, │ │401 .invalid => unreachable, // parsed above │ │402 .not_found => return writeError(sess, "repo not found"), │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │412 var sideband = progress.Sideband{ .writer = &writer.interface, .sess = sess }; │ │413 try repo.uploadPack(io, allocator, &reader.interface, &writer.interface, .{ .protocol_version = protocol_version }, &sideband); │ │414 }, │ │413 - .receive_pack => try push.receivePackAndConsume(repo.self_repo_opts, io, allocator, repo, &reader.interface, &writer.interface, .{ .protocol_version = protocol_version }, author, handler.users_dir, handler.err, sess),│ │415 + .receive_pack => try push.receivePackAndConsume(repo.self_repo_opts, io, allocator, repo, &reader.interface, &writer.interface, .{ .protocol_version = protocol_version }, author, handler.server, handler.err, sess), │ │416 }, │ │417 } │ │418 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │438 // a client with nothing to push creates nothing │ │439 const hash_kind = (try xit.net_server_receive_pack.peekObjectFormat(reader)) orelse return; │ │440 │ │439 - const location = evt.createRepo(io, allocator, handler.users_dir, &creator.owner_id, creator.owner, name, "", .private, hash_kind) catch |err| switch (err) { │ │441 + const location = evt.createRepo(io, allocator, handler.server.users_dir, &creator.owner_id, creator.owner, name, "", .private, hash_kind) catch |err| switch (err) {│ │442 error.NameTaken => return writeError(sess, "repo was just created by another push, try again"), │ │443 else => |e| return e, │ │444 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │443 - const repo_path = try evt.repoPath(allocator, handler.users_dir, &location.owner_id, &location.repo_id); │ │445 + const repo_path = try evt.repoPath(allocator, handler.server.users_dir, &location.owner_id, &location.repo_id);│ │446 defer allocator.free(repo_path); │ │447 │ │448 switch (hash_kind) { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │450 var repo = try rp.Repo(.xit, any_repo_opts.toRepoOptsWithHash(kind)).open(io, allocator, .{ .path = repo_path }); │ │451 defer repo.deinit(io, allocator); │ │452 // stateless since the advertisement already went out │ │451 - try push.receivePackAndConsume(repo.self_repo_opts, io, allocator, &repo, reader, writer, .{ .protocol_version = protocol_version, .is_stateless = true }, creator.owner, handler.users_dir, handler.err, sess);│ │453 + try push.receivePackAndConsume(repo.self_repo_opts, io, allocator, &repo, reader, writer, .{ .protocol_version = protocol_version, .is_stateless = true }, creator.owner, handler.server, handler.err, sess); │ │454 }, │ │455 } │ │456 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │480 const fork_id = try evt.parseEventId(&route.id); │ │481 const forker_id = (try evt.User.readIdByName(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, forker_repo.owner)) orelse │ │482 return writeError(sess, "patch draft not found"); │ │481 - const fork_record = (try evt.readForkById(io, allocator, &admin_arena, handler.users_dir, &forker_id, &fork_id)) orelse │ │483 + const fork_record = (try evt.readForkById(io, allocator, &admin_arena, handler.server.users_dir, &forker_id, &fork_id)) orelse│ │484 return writeError(sess, "patch draft not found"); │ │485 if (fork_record.removed) return writeError(sess, "patch draft not found"); │ │486 const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &admin_arena, &forker_id)) orelse │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │489 if (service == .receive_pack and !isKeyInAuthorizedKeys(user.event.ssh_keys, &sess.fingerprint)) │ │490 return writeError(sess, "unauthorized: this SSH key is not registered to the patch author"); │ │491 │ │490 - const target = (try evt.readRepoById(io, allocator, &admin_arena, handler.users_dir, fork_record.event.repo_user_id[0..evt.event_id_size], fork_record.event.repo_id[0..evt.event_id_size], forker_id)) orelse │ │492 + const target = (try evt.readRepoById(io, allocator, &admin_arena, handler.server.users_dir, fork_record.event.repo_user_id[0..evt.event_id_size], fork_record.event.repo_id[0..evt.event_id_size], forker_id)) orelse│ │493 return writeError(sess, "repo not found"); │ │494 // patches that are off take their drafts with them │ │495 const patch_role = target.repo.event.patch_role orelse return writeError(sess, "patch draft not found"); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯