Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { AbstractModule } from '../../../core/abstract-module'
import type { Archon } from '../types'

export class ArchonBackupRepositoriesInternalModule extends AbstractModule {
public getModuleID(): string {
return 'archon_backup_repositories_internal'
}

/**
* List the latest reparation runs of a backup repository with their operations, newest first.
* GET /_internal/backups/repositories/:id/reparation
*/
public async getReparations(
repositoryId: number,
): Promise<Archon.BackupRepositories.Internal.ReparationRun[]> {
return this.client.request<Archon.BackupRepositories.Internal.ReparationRun[]>(
`/backups/repositories/${repositoryId}/reparation`,
{
api: 'archon',
version: 'internal',
method: 'GET',
},
)
}

/**
* Start a reparation run of a backup repository by checking it.
* POST /_internal/backups/repositories/:id/reparation
*/
public async startReparation(
repositoryId: number,
options?: Archon.BackupRepositories.Internal.StartReparationQuery,
): Promise<Archon.BackupRepositories.Internal.ReparationRun> {
return this.client.request<Archon.BackupRepositories.Internal.ReparationRun>(
`/backups/repositories/${repositoryId}/reparation`,
{
api: 'archon',
version: 'internal',
method: 'POST',
params: options?.read ? { read: true } : undefined,
},
)
}

/**
* Start an operation in the backup repository's latest reparation run.
* POST /_internal/backups/repositories/:id/reparation/:operation
*/
public async startOperation(
repositoryId: number,
operationType: Archon.BackupRepositories.Internal.RunnableOperationType,
): Promise<Archon.BackupRepositories.Internal.ReparationOperation> {
return this.client.request<Archon.BackupRepositories.Internal.ReparationOperation>(
`/backups/repositories/${repositoryId}/reparation/${operationType}`,
{
api: 'archon',
version: 'internal',
method: 'POST',
},
)
}
}
1 change: 1 addition & 0 deletions packages/api-client/src/modules/archon/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './actions/v1'
export * from './backup-repositories/internal'
export * from './backups/v1'
export * from './backups-queue/v1'
export * from './content/v1'
Expand Down
116 changes: 116 additions & 0 deletions packages/api-client/src/modules/archon/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,8 @@ export namespace Archon {
tags: string[]
location: ServerLocation
worlds: WorldFull[]
/** IDs of the server's backup repositories. Only returned to support agents. */
repository_ids?: number[]
}

export type SftpCredentials = {
Expand Down Expand Up @@ -998,6 +1000,120 @@ export namespace Archon {
}
}

export namespace BackupRepositories {
export namespace Internal {
export type OperationType =
| 'check'
| 'check-read-data'
| 'repair-index'
| 'repair-packs'
| 'repair-snapshots'
| 'prune'
| 'restore-hidden-versions'

/** Operations started in an existing run. Checks start a new run instead. */
export type RunnableOperationType = Exclude<OperationType, 'check' | 'check-read-data'>

/**
* `completed` when the operation ran, regardless of what it found, or `failed` when it
* couldn't run.
*/
export type OperationStatus = 'pending' | 'ongoing' | 'completed' | 'failed'

export type StartReparationQuery = {
/** Whether the run's check reads all pack data, which is much slower. */
read?: boolean
}

export type RepairCheckOutput = {
type: 'check'
exit_code: number | null
num_errors: number
broken_packs: string[]
suggest_repair_index: boolean
suggest_prune: boolean
/** The first reported errors, capped to keep the result small. */
errors: string[]
/** Whether more errors were reported than included in `errors`. */
errors_truncated: boolean
}

export type RepairSnapshot = {
id: string
time: string
original?: string
tags: string[]
}

export type RepairOutput =
| RepairCheckOutput
| {
type: 'snapshots'
snapshots: RepairSnapshot[]
}
| {
type: 'command'
exit_code: number | null
output_tail: string
}

/** Results of a completed `repair-snapshots` operation. */
export type RepairSnapshotsResults = {
repair: RepairOutput
remapped_backups: {
backup_id: string
original_snapshot_id: string
snapshot_id: string
}[]
missing_snapshot_backups: string[]
}

/** Results of a `restore-hidden-versions` operation. Only the destination is set while it runs. */
export type RestoreHiddenVersionsResults = {
destination_repository_id: number
packs?: number
hidden_packs?: number
snapshots?: number
hidden_snapshots?: number
bytes?: number
copied_objects?: number
skipped_objects?: number
missing_objects?: string[]
repair_index?: RepairOutput
imported_backups?: number
matched_backups?: number
}

export type ReparationOperation = {
id: number
operation_type: OperationType
status: OperationStatus
params: Record<string, unknown>
/**
* A {@link RepairOutput} for checks, `repair-index`, `repair-packs` and `prune`, a
* {@link RepairSnapshotsResults} for `repair-snapshots`, and a
* {@link RestoreHiddenVersionsResults} for `restore-hidden-versions`.
*/
results: RepairOutput | RepairSnapshotsResults | RestoreHiddenVersionsResults | null
error: string | null
node_id: string | null
created_by: string | null
created_at: string
started_at: string | null
completed_at: string | null
}

export type ReparationRun = {
id: number
repository_id: number
server_id: string | null
created_by: string | null
created_at: string
operations: ReparationOperation[]
}
}
}

export namespace Sync {
export namespace v1 {
export type SyncCategory = 'backup' | 'users' | 'server' | 'protocol' | 'world'
Expand Down
2 changes: 2 additions & 0 deletions packages/api-client/src/modules/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AbstractModrinthClient } from '../core/abstract-client'
import type { AbstractModule } from '../core/abstract-module'
import { ArchonActionsV1Module } from './archon/actions/v1'
import { ArchonBackupRepositoriesInternalModule } from './archon/backup-repositories/internal'
import { ArchonBackupsV1Module } from './archon/backups/v1'
import { ArchonBackupsQueueV1Module } from './archon/backups-queue/v1'
import { ArchonContentV1Module } from './archon/content/v1'
Expand Down Expand Up @@ -81,6 +82,7 @@ type ModuleConstructor = new (client: AbstractModrinthClient) => AbstractModule
*/
export const MODULE_REGISTRY = {
archon_actions_v1: ArchonActionsV1Module,
archon_backup_repositories_internal: ArchonBackupRepositoriesInternalModule,
archon_backups_queue_v1: ArchonBackupsQueueV1Module,
archon_backups_v1: ArchonBackupsV1Module,
archon_content_v1: ArchonContentV1Module,
Expand Down
Loading
Loading