feat(proxy): proxy app and refactor
- added a centralized proxy app - proxy supports auth via query param, header or JWT cookie - added a proxy to the daemon - runner now proxies everything to daemon instead of directly to container port Signed-off-by: Toma Puljak <toma.puljak@hotmail.com>
This commit is contained in:
Vendored
+16
@@ -16,6 +16,12 @@
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "yarn serve:skip-proxy",
|
||||
"name": "Debug - Skip Proxy",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"name": "Runner",
|
||||
"type": "go",
|
||||
@@ -35,6 +41,16 @@
|
||||
"program": "${workspaceFolder}/apps/daemon/cmd/daemon",
|
||||
"console": "integratedTerminal",
|
||||
"output": "${workspaceFolder}/dist/apps/daemon"
|
||||
},
|
||||
{
|
||||
"name": "Proxy",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "${workspaceFolder}/apps/proxy/cmd/proxy",
|
||||
"console": "integratedTerminal",
|
||||
"envFile": "${workspaceFolder}/apps/proxy/.env",
|
||||
"output": "${workspaceFolder}/dist/apps/proxy"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -58,3 +58,7 @@ OTEL_ENABLED=true
|
||||
OTEL_COLLECTOR_URL=http://jaeger:4318/v1/traces
|
||||
|
||||
MAINTENANCE_MODE=false
|
||||
|
||||
PROXY_DOMAIN=proxy.localhost:4000
|
||||
PROXY_PROTOCOL=http
|
||||
PROXY_API_KEY=super_secret_key
|
||||
|
||||
@@ -9,6 +9,8 @@ import { Strategy } from 'passport-http-bearer'
|
||||
import { ApiKeyService } from '../api-key/api-key.service'
|
||||
import { UserService } from '../user/user.service'
|
||||
import { AuthContext } from '../common/interfaces/auth-context.interface'
|
||||
import { TypedConfigService } from '../config/typed-config.service'
|
||||
import { ProxyContext } from '../common/interfaces/proxy-context.interface'
|
||||
|
||||
@Injectable()
|
||||
export class ApiKeyStrategy extends PassportStrategy(Strategy, 'api-key') implements OnModuleInit {
|
||||
@@ -17,6 +19,7 @@ export class ApiKeyStrategy extends PassportStrategy(Strategy, 'api-key') implem
|
||||
constructor(
|
||||
private readonly apiKeyService: ApiKeyService,
|
||||
private readonly userService: UserService,
|
||||
private readonly configService: TypedConfigService,
|
||||
) {
|
||||
super()
|
||||
this.logger.log('ApiKeyStrategy constructor called')
|
||||
@@ -26,10 +29,18 @@ export class ApiKeyStrategy extends PassportStrategy(Strategy, 'api-key') implem
|
||||
this.logger.log('ApiKeyStrategy initialized')
|
||||
}
|
||||
|
||||
async validate(token: string): Promise<AuthContext> {
|
||||
async validate(token: string): Promise<AuthContext | ProxyContext> {
|
||||
this.logger.debug('Validate method called')
|
||||
this.logger.debug(`Validating API key: ${token.substring(0, 8)}...`)
|
||||
|
||||
const proxyApiKey = this.configService.getOrThrow('proxy.apiKey')
|
||||
if (proxyApiKey === token) {
|
||||
return {
|
||||
proxy: true,
|
||||
role: 'admin',
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const apiKey = await this.apiKeyService.getApiKeyByValue(token)
|
||||
this.logger.debug(`API key found for userId: ${apiKey.userId}`)
|
||||
|
||||
@@ -16,7 +16,6 @@ import { firstValueFrom } from 'rxjs'
|
||||
import { UserService } from '../user/user.service'
|
||||
import { TypedConfigModule } from '../config/typed-config.module'
|
||||
import { catchError, map } from 'rxjs/operators'
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
PassportModule.register({
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0
|
||||
*/
|
||||
|
||||
import { ExecutionContext, UnauthorizedException } from '@nestjs/common'
|
||||
import { IAuthContext } from '../common/interfaces/auth-context.interface'
|
||||
|
||||
export function getAuthContext<T extends IAuthContext>(
|
||||
context: ExecutionContext,
|
||||
isFunction: (user: IAuthContext) => user is T,
|
||||
): T {
|
||||
const request = context.switchToHttp().getRequest()
|
||||
|
||||
if (request.user && isFunction(request.user)) {
|
||||
return request.user
|
||||
}
|
||||
|
||||
throw new UnauthorizedException('Unauthorized')
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0
|
||||
*/
|
||||
|
||||
import { Injectable, ExecutionContext, Logger, CanActivate } from '@nestjs/common'
|
||||
import { getAuthContext } from './get-auth-context'
|
||||
import { isProxyContext } from '../common/interfaces/proxy-context.interface'
|
||||
|
||||
@Injectable()
|
||||
export class ProxyGuard implements CanActivate {
|
||||
protected readonly logger = new Logger(ProxyGuard.name)
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
// Throws if not proxy context
|
||||
getAuthContext(context, isProxyContext)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,11 @@ import { OrganizationUser } from '../../organization/entities/organization-user.
|
||||
import { Organization } from '../../organization/entities/organization.entity'
|
||||
import { SystemRole } from '../../user/enums/system-role.enum'
|
||||
|
||||
export interface AuthContext {
|
||||
export interface IAuthContext {
|
||||
role: string
|
||||
}
|
||||
|
||||
export interface AuthContext extends IAuthContext {
|
||||
userId: string
|
||||
email: string
|
||||
role: SystemRole
|
||||
@@ -16,8 +20,16 @@ export interface AuthContext {
|
||||
organizationId?: string
|
||||
}
|
||||
|
||||
export function isAuthContext(user: IAuthContext): user is AuthContext {
|
||||
return 'userId' in user
|
||||
}
|
||||
|
||||
export interface OrganizationAuthContext extends AuthContext {
|
||||
organizationId: string
|
||||
organization: Organization
|
||||
organizationUser?: OrganizationUser
|
||||
}
|
||||
|
||||
export function isOrganizationAuthContext(user: IAuthContext): user is OrganizationAuthContext {
|
||||
return 'organizationId' in user
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0
|
||||
*/
|
||||
|
||||
import { IAuthContext } from './auth-context.interface'
|
||||
|
||||
export interface ProxyContext extends IAuthContext {
|
||||
proxy: boolean
|
||||
}
|
||||
|
||||
export function isProxyContext(user: IAuthContext): user is ProxyContext {
|
||||
return 'proxy' in user
|
||||
}
|
||||
@@ -70,6 +70,11 @@ const configuration = {
|
||||
skipConnections: process.env.SKIP_CONNECTIONS === 'true',
|
||||
maxAutoArchiveInterval: parseInt(process.env.MAX_AUTO_ARCHIVE_INTERVAL || '43200', 10),
|
||||
maintananceMode: process.env.MAINTENANCE_MODE === 'true',
|
||||
proxy: {
|
||||
domain: process.env.PROXY_DOMAIN,
|
||||
protocol: process.env.PROXY_PROTOCOL,
|
||||
apiKey: process.env.PROXY_API_KEY,
|
||||
},
|
||||
}
|
||||
|
||||
export { configuration }
|
||||
|
||||
@@ -25,9 +25,7 @@ export class OrganizationResourceActionGuard extends OrganizationAccessGuard {
|
||||
super(organizationService, organizationUserService)
|
||||
}
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
if (!(await super.canActivate(context))) {
|
||||
return false
|
||||
}
|
||||
const canActivate = await super.canActivate(context)
|
||||
|
||||
const request = context.switchToHttp().getRequest()
|
||||
// TODO: initialize authContext safely
|
||||
@@ -37,6 +35,10 @@ export class OrganizationResourceActionGuard extends OrganizationAccessGuard {
|
||||
return true
|
||||
}
|
||||
|
||||
if (!canActivate) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!authContext.organizationUser) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -7,15 +7,17 @@ import { Body, Controller, Get, Post, Param, Patch, UseGuards } from '@nestjs/co
|
||||
import { CreateRunnerDto } from '../dto/create-runner.dto'
|
||||
import { Runner } from '../entities/runner.entity'
|
||||
import { RunnerService } from '../services/runner.service'
|
||||
import { AuthGuard } from '@nestjs/passport'
|
||||
import { ApiOAuth2, ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'
|
||||
import { ApiOAuth2, ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger'
|
||||
import { SystemActionGuard } from '../../auth/system-action.guard'
|
||||
import { RequiredSystemRole } from '../../common/decorators/required-system-role.decorator'
|
||||
import { SystemRole } from '../../user/enums/system-role.enum'
|
||||
import { ProxyGuard } from '../../auth/proxy.guard'
|
||||
import { RunnerDto } from '../dto/runner.dto'
|
||||
|
||||
import { CombinedAuthGuard } from '../../auth/combined-auth.guard'
|
||||
@ApiTags('runners')
|
||||
@Controller('runners')
|
||||
@UseGuards(AuthGuard('jwt'), SystemActionGuard)
|
||||
@UseGuards(CombinedAuthGuard, SystemActionGuard, ProxyGuard)
|
||||
@RequiredSystemRole(SystemRole.ADMIN)
|
||||
@ApiOAuth2(['openid', 'profile', 'email'])
|
||||
@ApiBearerAuth()
|
||||
@@ -51,4 +53,19 @@ export class RunnerController {
|
||||
): Promise<Runner> {
|
||||
return this.runnerService.updateSchedulingStatus(id, unschedulable)
|
||||
}
|
||||
|
||||
@Get('/by-sandbox/:sandboxId')
|
||||
@ApiOperation({
|
||||
summary: 'Get runner by sandbox ID',
|
||||
operationId: 'getRunnerBySandboxId',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Runner found',
|
||||
type: RunnerDto,
|
||||
})
|
||||
async getRunnerBySandboxId(@Param('sandboxId') sandboxId: string): Promise<RunnerDto> {
|
||||
const runner = await this.runnerService.findBySandboxId(sandboxId)
|
||||
return RunnerDto.fromRunner(runner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ import { IncomingMessage, ServerResponse } from 'http'
|
||||
import { NextFunction } from 'http-proxy-middleware/dist/types'
|
||||
import { LogProxy } from '../proxy/log-proxy'
|
||||
import { BadRequestError } from '../../exceptions/bad-request.exception'
|
||||
import { TypedConfigService } from '../../config/typed-config.service'
|
||||
|
||||
@ApiTags('sandbox')
|
||||
@Controller('sandbox')
|
||||
@@ -72,6 +73,7 @@ export class SandboxController {
|
||||
@InjectRedis() private readonly redis: Redis,
|
||||
private readonly runnerService: RunnerService,
|
||||
private readonly sandboxService: SandboxService,
|
||||
private readonly configService: TypedConfigService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@@ -426,6 +428,27 @@ export class SandboxController {
|
||||
@Param('sandboxId') sandboxId: string,
|
||||
@Param('port') port: number,
|
||||
): Promise<PortPreviewUrlDto> {
|
||||
if (port < 1 || port > 65535) {
|
||||
throw new BadRequestError('Invalid port')
|
||||
}
|
||||
|
||||
const proxyDomain = this.configService.get('proxy.domain')
|
||||
const proxyProtocol = this.configService.get('proxy.protocol')
|
||||
if (proxyDomain && proxyProtocol) {
|
||||
const sandbox = await this.sandboxService.findOne(sandboxId)
|
||||
if (!sandbox) {
|
||||
throw new NotFoundException(`Sandbox with ID ${sandboxId} not found`)
|
||||
}
|
||||
|
||||
// Return new preview url only for updated sandboxes
|
||||
if (sandbox.daemonVersion) {
|
||||
return {
|
||||
url: `${proxyProtocol}://${port}-${sandboxId}.${proxyDomain}`,
|
||||
token: sandbox.authToken,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.sandboxService.getPortPreviewUrl(sandboxId, port)
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ import { IncomingMessage, ServerResponse } from 'http'
|
||||
import { NextFunction } from 'http-proxy-middleware/dist/types'
|
||||
import { LogProxy } from '../proxy/log-proxy'
|
||||
import { CreateWorkspaceDto } from '../dto/create-workspace.deprecated.dto'
|
||||
import { TypedConfigService } from '../../config/typed-config.service'
|
||||
import { BadRequestError } from '../../exceptions/bad-request.exception'
|
||||
|
||||
@ApiTags('workspace')
|
||||
@Controller('workspace')
|
||||
@@ -73,6 +75,7 @@ export class WorkspaceController {
|
||||
@InjectRedis() private readonly redis: Redis,
|
||||
private readonly runnerService: RunnerService,
|
||||
private readonly workspaceService: WorkspaceService,
|
||||
private readonly configService: TypedConfigService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@@ -448,6 +451,27 @@ export class WorkspaceController {
|
||||
@Param('workspaceId') workspaceId: string,
|
||||
@Param('port') port: number,
|
||||
): Promise<PortPreviewUrlDto> {
|
||||
if (port < 1 || port > 65535) {
|
||||
throw new BadRequestError('Invalid port')
|
||||
}
|
||||
|
||||
const proxyDomain = this.configService.get('proxy.domain')
|
||||
const proxyProtocol = this.configService.get('proxy.protocol')
|
||||
if (proxyDomain && proxyProtocol) {
|
||||
const workspace = await this.workspaceService.findOne(workspaceId)
|
||||
if (!workspace) {
|
||||
throw new NotFoundException(`Workspace with ID ${workspaceId} not found`)
|
||||
}
|
||||
|
||||
// Return new preview url only for updated workspaces/sandboxes
|
||||
if (workspace.daemonVersion) {
|
||||
return {
|
||||
url: `${proxyProtocol}://${port}-${workspaceId}.${proxyDomain}`,
|
||||
token: workspace.authToken,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.workspaceService.getPortPreviewUrl(workspaceId, port)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0
|
||||
*/
|
||||
|
||||
import { ApiProperty, ApiPropertyOptional, ApiSchema } from '@nestjs/swagger'
|
||||
import { IsEnum, IsOptional } from 'class-validator'
|
||||
import { Runner } from '../entities/runner.entity'
|
||||
import { RunnerRegion } from '../enums/runner-region.enum'
|
||||
import { SandboxClass } from '../enums/sandbox-class.enum'
|
||||
import { RunnerState } from '../enums/runner-state.enum'
|
||||
|
||||
@ApiSchema({ name: 'Runner' })
|
||||
export class RunnerDto {
|
||||
@ApiProperty({
|
||||
description: 'The ID of the runner',
|
||||
example: 'runner123',
|
||||
})
|
||||
id: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The domain of the runner',
|
||||
example: 'runner1.example.com',
|
||||
})
|
||||
domain: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The API URL of the runner',
|
||||
example: 'https://api.runner1.example.com',
|
||||
})
|
||||
apiUrl: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The API key for the runner',
|
||||
example: 'api-key-123',
|
||||
})
|
||||
apiKey: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The CPU capacity of the runner',
|
||||
example: 8,
|
||||
})
|
||||
cpu: number
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The memory capacity of the runner in GB',
|
||||
example: 16,
|
||||
})
|
||||
memory: number
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The disk capacity of the runner in GB',
|
||||
example: 100,
|
||||
})
|
||||
disk: number
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The GPU capacity of the runner',
|
||||
example: 1,
|
||||
})
|
||||
gpu: number
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The type of GPU',
|
||||
})
|
||||
gpuType: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The class of the runner',
|
||||
enum: SandboxClass,
|
||||
enumName: 'SandboxClass',
|
||||
example: SandboxClass.SMALL,
|
||||
})
|
||||
@IsEnum(SandboxClass)
|
||||
class: SandboxClass
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The current usage of the runner',
|
||||
example: 2,
|
||||
})
|
||||
used: number
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The capacity of the runner',
|
||||
example: 10,
|
||||
})
|
||||
capacity: number
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The region of the runner',
|
||||
enum: RunnerRegion,
|
||||
enumName: 'RunnerRegion',
|
||||
example: RunnerRegion.EU,
|
||||
})
|
||||
@IsEnum(RunnerRegion)
|
||||
region: RunnerRegion
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The state of the runner',
|
||||
enum: RunnerState,
|
||||
enumName: 'RunnerState',
|
||||
example: RunnerState.INITIALIZING,
|
||||
})
|
||||
@IsEnum(RunnerState)
|
||||
state: RunnerState
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'The last time the runner was checked',
|
||||
example: '2024-10-01T12:00:00Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
lastChecked?: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Whether the runner is unschedulable',
|
||||
example: false,
|
||||
})
|
||||
unschedulable: boolean
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The creation timestamp of the runner',
|
||||
example: '2023-10-01T12:00:00Z',
|
||||
})
|
||||
createdAt: string
|
||||
|
||||
@ApiProperty({
|
||||
description: 'The last update timestamp of the runner',
|
||||
example: '2023-10-01T12:00:00Z',
|
||||
})
|
||||
updatedAt: string
|
||||
|
||||
static fromRunner(runner: Runner): RunnerDto {
|
||||
return {
|
||||
id: runner.id,
|
||||
domain: runner.domain,
|
||||
apiUrl: runner.apiUrl,
|
||||
apiKey: runner.apiKey,
|
||||
cpu: runner.cpu,
|
||||
memory: runner.memory,
|
||||
disk: runner.disk,
|
||||
gpu: runner.gpu,
|
||||
gpuType: runner.gpuType,
|
||||
class: runner.class,
|
||||
used: runner.used,
|
||||
capacity: runner.capacity,
|
||||
region: runner.region,
|
||||
state: runner.state,
|
||||
lastChecked: runner.lastChecked?.toISOString(),
|
||||
unschedulable: runner.unschedulable,
|
||||
createdAt: runner.createdAt.toISOString(),
|
||||
updatedAt: runner.updatedAt.toISOString(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0
|
||||
*/
|
||||
|
||||
import { Injectable, Logger } from '@nestjs/common'
|
||||
import { Injectable, Logger, NotFoundException } from '@nestjs/common'
|
||||
import { InjectRepository } from '@nestjs/typeorm'
|
||||
import { Cron } from '@nestjs/schedule'
|
||||
import { FindOptionsWhere, In, Not, Raw, Repository } from 'typeorm'
|
||||
@@ -67,10 +67,22 @@ export class RunnerService {
|
||||
return this.runnerRepository.find()
|
||||
}
|
||||
|
||||
findOne(id: string): Promise<Runner | null> {
|
||||
async findOne(id: string): Promise<Runner | null> {
|
||||
return this.runnerRepository.findOneBy({ id })
|
||||
}
|
||||
|
||||
async findBySandboxId(sandboxId: string): Promise<Runner | null> {
|
||||
const sandbox = await this.sandboxRepository.findOneBy({ id: sandboxId })
|
||||
if (!sandbox) {
|
||||
throw new NotFoundException(`Sandbox with ID ${sandboxId} not found`)
|
||||
}
|
||||
if (!sandbox.runnerId) {
|
||||
throw new NotFoundException(`Sandbox with ID ${sandboxId} does not have a runner`)
|
||||
}
|
||||
|
||||
return this.runnerRepository.findOneBy({ id: sandbox.runnerId })
|
||||
}
|
||||
|
||||
async findAvailableRunners(params: GetRunnerParams): Promise<Runner[]> {
|
||||
const runnerFilter: FindOptionsWhere<Runner> = {
|
||||
state: RunnerState.READY,
|
||||
|
||||
+7
-2
@@ -18,7 +18,7 @@ replace github.com/daytonaio/daytona/daytonaapiclient => ../../libs/api-client-g
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/catppuccin/go v0.2.0 // indirect
|
||||
@@ -27,6 +27,7 @@ require (
|
||||
github.com/charmbracelet/x/term v0.2.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/creack/pty v1.1.23 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
@@ -41,11 +42,13 @@ require (
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/minio/crc64nvme v1.0.1 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
@@ -59,6 +62,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.1 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
@@ -70,6 +74,7 @@ require (
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
@@ -85,7 +90,7 @@ require (
|
||||
github.com/coreos/go-oidc/v3 v3.12.0
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/minio/minio-go/v7 v7.0.90
|
||||
github.com/minio/minio-go/v7 v7.0.91
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
golang.org/x/term v0.30.0
|
||||
|
||||
+11
-25
@@ -2,8 +2,7 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
@@ -36,8 +35,7 @@ github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc
|
||||
github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -81,10 +79,10 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -101,10 +99,10 @@ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2J
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.90 h1:TmSj1083wtAD0kEYTx7a5pFsv3iRYMsOJ6A4crjA1lE=
|
||||
github.com/minio/minio-go/v7 v7.0.90/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go=
|
||||
github.com/minio/minio-go/v7 v7.0.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5JQc=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
@@ -125,7 +123,6 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -136,11 +133,11 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
@@ -149,8 +146,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
@@ -179,8 +174,7 @@ go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -188,37 +182,29 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
|
||||
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
|
||||
+18
-17
@@ -10,19 +10,19 @@ replace github.com/samber/lo => github.com/samber/lo v1.39.0
|
||||
|
||||
require (
|
||||
github.com/creack/pty v1.1.23
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/gliderlabs/ssh v0.3.7
|
||||
github.com/go-git/go-git/v5 v5.12.1-0.20240617075238-c127d1b35535
|
||||
github.com/go-playground/validator/v10 v10.19.0
|
||||
github.com/go-playground/validator/v10 v10.24.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1
|
||||
github.com/pkg/sftp v1.13.6
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/sourcegraph/jsonrpc2 v0.2.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/crypto v0.36.0
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
)
|
||||
|
||||
@@ -31,24 +31,25 @@ require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.0.0 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/bytedance/sonic v1.11.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/bytedance/sonic v1.12.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.1-0.20240427054813-8453aa90c6ec // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -57,22 +58,22 @@ require (
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
golang.org/x/arch v0.12.0 // indirect
|
||||
google.golang.org/protobuf v1.36.3 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
+19
-43
@@ -10,20 +10,13 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A=
|
||||
github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
|
||||
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
|
||||
github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
@@ -36,12 +29,10 @@ github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcej
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
@@ -58,10 +49,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
|
||||
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
@@ -70,8 +59,7 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
@@ -81,8 +69,7 @@ github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
@@ -117,8 +104,7 @@ github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Q
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
@@ -138,8 +124,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
@@ -147,17 +132,14 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -168,8 +150,7 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -187,16 +168,14 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -204,15 +183,13 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
@@ -227,4 +204,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
common_errors "github.com/daytonaio/common-go/pkg/errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetProxyTarget(ctx *gin.Context) (*url.URL, string, map[string]string, error) {
|
||||
targetPort := ctx.Param("port")
|
||||
if targetPort == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("target port is required")))
|
||||
return nil, "", nil, errors.New("target port is required")
|
||||
}
|
||||
|
||||
// Build the target URL
|
||||
targetURL := fmt.Sprintf("http://localhost:%s", targetPort)
|
||||
target, err := url.Parse(targetURL)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to parse target URL: %w", err)))
|
||||
return nil, "", nil, fmt.Errorf("failed to parse target URL: %w", err)
|
||||
}
|
||||
|
||||
// Get the wildcard path and normalize it
|
||||
path := ctx.Param("path")
|
||||
|
||||
// Ensure path always has a leading slash but not duplicate slashes
|
||||
if path == "" {
|
||||
path = "/"
|
||||
} else if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
// Create the complete target URL with path
|
||||
fullTargetURL := fmt.Sprintf("%s%s", targetURL, path)
|
||||
if ctx.Request.URL.RawQuery != "" {
|
||||
fullTargetURL = fmt.Sprintf("%s?%s", fullTargetURL, ctx.Request.URL.RawQuery)
|
||||
}
|
||||
|
||||
return target, fullTargetURL, nil, nil
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
common_proxy "github.com/daytonaio/common-go/pkg/proxy"
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/config"
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/fs"
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/git"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/port"
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/process"
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/process/session"
|
||||
"github.com/daytonaio/daemon/pkg/toolbox/proxy"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
@@ -146,6 +148,11 @@ func (s *Server) Start() error {
|
||||
portController.GET("/:port/in-use", portDetector.IsPortInUse)
|
||||
}
|
||||
|
||||
proxyController := r.Group("/proxy")
|
||||
{
|
||||
proxyController.Any("/:port/*path", common_proxy.NewProxyRequestHandler(proxy.GetProxyTarget))
|
||||
}
|
||||
|
||||
go portDetector.Start(context.Background())
|
||||
|
||||
httpServer := &http.Server{
|
||||
|
||||
@@ -13,3 +13,5 @@ VITE_ANNOUNCEMENT_BANNER_TEXT=
|
||||
VITE_ANNOUNCEMENT_BANNER_LEARN_MORE_URL=
|
||||
|
||||
VITE_PYLON_APP_ID=
|
||||
|
||||
VITE_PROXY_TEMPLATE_URL=http://{{PORT}}-{{sandboxId}}.proxy.localhost:4000
|
||||
|
||||
@@ -584,13 +584,17 @@ const getColumns = ({
|
||||
id: 'access',
|
||||
header: 'Access',
|
||||
cell: ({ row }) => {
|
||||
if (!row.original.runnerDomain || row.original.state !== SandboxState.STARTED) return ''
|
||||
if (row.original.state !== SandboxState.STARTED) return ''
|
||||
|
||||
const terminalUrl = import.meta.env.VITE_PROXY_TEMPLATE_URL?.replace('{{PORT}}', '22222').replace(
|
||||
'{{sandboxId}}',
|
||||
row.original.id,
|
||||
)
|
||||
if (!terminalUrl) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<a
|
||||
href={`https://22222-${row.original.id}.${row.original.runnerDomain}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<a href={terminalUrl} target="_blank" rel="noopener noreferrer">
|
||||
<Terminal className="w-4 h-4" />
|
||||
</a>
|
||||
)
|
||||
|
||||
Vendored
+1
@@ -22,6 +22,7 @@ interface ImportMetaEnv {
|
||||
readonly VITE_ANNOUNCEMENT_BANNER_TEXT: string | undefined
|
||||
readonly VITE_ANNOUNCEMENT_BANNER_LEARN_MORE_URL: string | undefined
|
||||
readonly VITE_PYLON_APP_ID: string | undefined
|
||||
readonly VITE_PROXY_TEMPLATE_URL: string | undefined
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
DAYTONA_API_URL=http://localhost:3001/api
|
||||
|
||||
PROXY_PORT=4000
|
||||
PROXY_DOMAIN=proxy.localhost:4000
|
||||
PROXY_API_KEY=super_secret_key
|
||||
|
||||
OIDC_CLIENT_ID=daytona
|
||||
OIDC_CLIENT_SECRET=
|
||||
OIDC_DOMAIN=http://localhost:5556/dex
|
||||
OIDC_AUDIENCE=daytona
|
||||
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ProxyPort int `envconfig:"PROXY_PORT" validate:"required"`
|
||||
ProxyDomain string `envconfig:"PROXY_DOMAIN" validate:"required"`
|
||||
ProxyApiKey string `envconfig:"PROXY_API_KEY" validate:"required"`
|
||||
TLSCertFile string `envconfig:"TLS_CERT_FILE"`
|
||||
TLSKeyFile string `envconfig:"TLS_KEY_FILE"`
|
||||
EnableTLS bool `envconfig:"ENABLE_TLS"`
|
||||
DaytonaApiUrl string `envconfig:"DAYTONA_API_URL" validate:"required"`
|
||||
Oidc OidcConfig `envconfig:"OIDC"`
|
||||
Redis *RedisConfig `envconfig:"REDIS"`
|
||||
}
|
||||
|
||||
type OidcConfig struct {
|
||||
ClientId string `envconfig:"CLIENT_ID" validate:"required"`
|
||||
ClientSecret string `envconfig:"CLIENT_SECRET"`
|
||||
Domain string `envconfig:"DOMAIN" validate:"required"`
|
||||
Audience string `envconfig:"AUDIENCE" validate:"required"`
|
||||
}
|
||||
|
||||
type RedisConfig struct {
|
||||
Host *string `envconfig:"HOST"`
|
||||
Port *int `envconfig:"PORT"`
|
||||
Password *string `envconfig:"PASSWORD"`
|
||||
}
|
||||
|
||||
var DEFAULT_PROXY_PORT int = 4000
|
||||
|
||||
var config *Config
|
||||
|
||||
func GetConfig() (*Config, error) {
|
||||
if config != nil {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
config = &Config{}
|
||||
|
||||
// Load .env files
|
||||
err := godotenv.Overload(".env", ".env.local", ".env.production")
|
||||
if err != nil {
|
||||
log.Println("Warning: Error loading .env file:", err)
|
||||
// Continue anyway, as environment variables might be set directly
|
||||
}
|
||||
|
||||
err = envconfig.Process("", config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var validate = validator.New()
|
||||
err = validate.Struct(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.ProxyPort == 0 {
|
||||
config.ProxyPort = DEFAULT_PROXY_PORT
|
||||
}
|
||||
|
||||
if config.Redis != nil {
|
||||
if config.Redis.Host == nil && config.Redis.Port == nil && config.Redis.Password == nil {
|
||||
config.Redis = nil
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/daytonaio/proxy/cmd/proxy/config"
|
||||
"github.com/daytonaio/proxy/pkg/proxy"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config, err := config.GetConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
proxy.StartProxy(config)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
module github.com/daytonaio/proxy
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require github.com/gin-gonic/gin v1.10.1
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/cors v1.7.5 // indirect
|
||||
github.com/gin-contrib/sessions v1.0.4 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/gorilla/context v1.1.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/gorilla/sessions v1.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/redis/go-redis/v9 v9.10.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,133 @@
|
||||
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk=
|
||||
github.com/gin-contrib/cors v1.7.5/go.mod h1:4q3yi7xBEDDWKapjT2o1V7mScKDDr8k+jZ0fSquGoy0=
|
||||
github.com/gin-contrib/sessions v1.0.4 h1:ha6CNdpYiTOK/hTp05miJLbpTSNfOnFg5Jm2kbcqy8U=
|
||||
github.com/gin-contrib/sessions v1.0.4/go.mod h1:ccmkrb2z6iU2osiAHZG3x3J4suJK+OU27oqzlWOqQgs=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
||||
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
|
||||
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
|
||||
golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
|
||||
golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ICache[T any] interface {
|
||||
Get(ctx context.Context, key string) (*T, error)
|
||||
Set(ctx context.Context, key string, value T, expiration time.Duration) error
|
||||
Delete(ctx context.Context, key string) error
|
||||
Has(ctx context.Context, key string) (bool, error)
|
||||
}
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
cmap "github.com/orcaman/concurrent-map/v2"
|
||||
)
|
||||
|
||||
type MapCache[T any] struct {
|
||||
cacheMap cmap.ConcurrentMap[string, T]
|
||||
}
|
||||
|
||||
func (c *MapCache[T]) Set(ctx context.Context, key string, value T, expiration time.Duration) error {
|
||||
c.cacheMap.Set(key, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MapCache[T]) Has(ctx context.Context, key string) (bool, error) {
|
||||
_, ok := c.cacheMap.Get(key)
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (c *MapCache[T]) Get(ctx context.Context, key string) (*T, error) {
|
||||
value, ok := c.cacheMap.Get(key)
|
||||
if !ok {
|
||||
return nil, errors.New("key not found")
|
||||
}
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func (c *MapCache[T]) Delete(ctx context.Context, key string) error {
|
||||
c.cacheMap.Remove(key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewMapCache[T any]() *MapCache[T] {
|
||||
return &MapCache[T]{
|
||||
cacheMap: cmap.New[T](),
|
||||
}
|
||||
}
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/daytonaio/proxy/cmd/proxy/config"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type RedisCache[T any] struct {
|
||||
redis *redis.Client
|
||||
keyPrefix string
|
||||
}
|
||||
|
||||
type ValueObject[T any] struct {
|
||||
Value T `json:"value"`
|
||||
}
|
||||
|
||||
var client *redis.Client
|
||||
|
||||
func (c *RedisCache[T]) Set(ctx context.Context, key string, value T, expiration time.Duration) error {
|
||||
jsonValue, err := json.Marshal(ValueObject[T]{Value: value})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.redis.Set(ctx, c.keyPrefix+key, string(jsonValue), expiration).Err()
|
||||
}
|
||||
|
||||
func (c *RedisCache[T]) Has(ctx context.Context, key string) (bool, error) {
|
||||
err := c.redis.Get(ctx, c.keyPrefix+key).Err()
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if err == redis.Nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (c *RedisCache[T]) Get(ctx context.Context, key string) (*T, error) {
|
||||
value, err := c.redis.Get(ctx, c.keyPrefix+key).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result ValueObject[T]
|
||||
err = json.Unmarshal([]byte(value), &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result.Value, nil
|
||||
}
|
||||
|
||||
func (c *RedisCache[T]) Delete(ctx context.Context, key string) error {
|
||||
return c.redis.Del(ctx, c.keyPrefix+key).Err()
|
||||
}
|
||||
|
||||
func NewRedisCache[T any](config *config.RedisConfig, keyPrefix string) (*RedisCache[T], error) {
|
||||
if config.Host == nil || config.Port == nil {
|
||||
return nil, errors.New("host and port are required")
|
||||
}
|
||||
|
||||
password := ""
|
||||
if config.Password != nil {
|
||||
password = *config.Password
|
||||
}
|
||||
|
||||
if client == nil {
|
||||
client = redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", *config.Host, *config.Port),
|
||||
Password: password,
|
||||
})
|
||||
}
|
||||
|
||||
return &RedisCache[T]{
|
||||
redis: client,
|
||||
keyPrefix: keyPrefix,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (p *Proxy) Authenticate(ctx *gin.Context, sandboxId string) (err error, didRedirect bool) {
|
||||
authKey := ctx.Request.Header.Get(DAYTONA_SANDBOX_AUTH_KEY_HEADER)
|
||||
if authKey == "" {
|
||||
if ctx.Query(DAYTONA_SANDBOX_AUTH_KEY_QUERY_PARAM) != "" {
|
||||
authKey = ctx.Query(DAYTONA_SANDBOX_AUTH_KEY_QUERY_PARAM)
|
||||
newQuery := ctx.Request.URL.Query()
|
||||
newQuery.Del(DAYTONA_SANDBOX_AUTH_KEY_QUERY_PARAM)
|
||||
ctx.Request.URL.RawQuery = newQuery.Encode()
|
||||
} else {
|
||||
// Check for cookie
|
||||
cookieSandboxId, err := ctx.Cookie(DAYTONA_SANDBOX_AUTH_COOKIE_NAME + sandboxId)
|
||||
if err == nil && cookieSandboxId != "" {
|
||||
decodedValue := ""
|
||||
err = p.secureCookie.Decode(DAYTONA_SANDBOX_AUTH_COOKIE_NAME+sandboxId, cookieSandboxId, &decodedValue)
|
||||
if err != nil {
|
||||
return errors.New("sandbox not found"), false
|
||||
}
|
||||
|
||||
if decodedValue != sandboxId {
|
||||
return errors.New("sandbox not found"), false
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
} else {
|
||||
authUrl, err := p.getAuthUrl(ctx, sandboxId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get auth URL: %w", err), false
|
||||
}
|
||||
|
||||
ctx.Redirect(http.StatusTemporaryRedirect, authUrl)
|
||||
|
||||
return errors.New("auth key is required"), true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if authKey != "" {
|
||||
isValid, err := p.getSandboxAuthKeyValid(ctx, sandboxId, authKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get sandbox auth key valid status: %w", err), false
|
||||
}
|
||||
|
||||
if !*isValid {
|
||||
return errors.New("invalid auth key"), false
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("auth key is required. Authenticate via a Header, Query Param or Cookie"), false
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
common_errors "github.com/daytonaio/common-go/pkg/errors"
|
||||
"github.com/daytonaio/daytona/daytonaapiclient"
|
||||
)
|
||||
|
||||
func (p *Proxy) AuthCallback(ctx *gin.Context) {
|
||||
if ctx.Query("error") != "" {
|
||||
err := ctx.Query("error")
|
||||
if ctx.Query("error_description") != "" {
|
||||
err = ctx.Query("error_description")
|
||||
}
|
||||
ctx.Error(common_errors.NewUnauthorizedError(errors.New(err)))
|
||||
return
|
||||
}
|
||||
|
||||
code := ctx.Query("code")
|
||||
if code == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("no code in callback")))
|
||||
return
|
||||
}
|
||||
|
||||
state := ctx.Query("state")
|
||||
if state == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("no state in callback")))
|
||||
return
|
||||
}
|
||||
|
||||
// Decode state
|
||||
stateJson, err := base64.URLEncoding.DecodeString(state)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to decode state: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
var stateData map[string]string
|
||||
err = json.Unmarshal(stateJson, &stateData)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to unmarshal state: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
returnTo := stateData["returnTo"]
|
||||
if returnTo == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("no returnTo in state")))
|
||||
return
|
||||
}
|
||||
|
||||
sandboxId := stateData["sandboxId"]
|
||||
if sandboxId == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("no sandboxId in state")))
|
||||
return
|
||||
}
|
||||
|
||||
// Exchange code for token
|
||||
provider, err := oidc.NewProvider(ctx, p.config.Oidc.Domain)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to initialize OIDC provider: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
oauth2Config := oauth2.Config{
|
||||
ClientID: p.config.Oidc.ClientId,
|
||||
ClientSecret: p.config.Oidc.ClientSecret,
|
||||
RedirectURL: fmt.Sprintf("http://%s/callback", ctx.Request.Host),
|
||||
Endpoint: provider.Endpoint(),
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile"},
|
||||
}
|
||||
|
||||
token, err := oauth2Config.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to exchange token: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
hasAccess := p.hasSandboxAccess(ctx, sandboxId, token.AccessToken)
|
||||
if !hasAccess {
|
||||
ctx.Error(common_errors.NewUnauthorizedError(errors.New("sandbox not found")))
|
||||
return
|
||||
}
|
||||
|
||||
// Set the sandboxId in a cookie for cached access
|
||||
cookieDomain := p.config.ProxyDomain
|
||||
cookieDomain = strings.Split(cookieDomain, ":")[0]
|
||||
cookieDomain = fmt.Sprintf(".%s", cookieDomain)
|
||||
|
||||
encoded, err := p.secureCookie.Encode(DAYTONA_SANDBOX_AUTH_COOKIE_NAME+sandboxId, sandboxId)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to encode cookie: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetCookie(DAYTONA_SANDBOX_AUTH_COOKIE_NAME+sandboxId, encoded, 3600, "/", cookieDomain, p.config.EnableTLS, true)
|
||||
|
||||
// Redirect back to the original URL
|
||||
ctx.Redirect(http.StatusFound, returnTo)
|
||||
}
|
||||
|
||||
func (p *Proxy) getAuthUrl(ctx *gin.Context, sandboxId string) (string, error) {
|
||||
provider, err := oidc.NewProvider(ctx, p.config.Oidc.Domain)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to initialize OIDC provider: %w", err)
|
||||
}
|
||||
|
||||
scheme := "http"
|
||||
if p.config.EnableTLS {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
oauth2Config := oauth2.Config{
|
||||
ClientID: p.config.Oidc.ClientId,
|
||||
ClientSecret: p.config.Oidc.ClientSecret,
|
||||
RedirectURL: fmt.Sprintf("%s://%s/callback", scheme, p.config.ProxyDomain),
|
||||
Endpoint: provider.Endpoint(),
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile"},
|
||||
}
|
||||
|
||||
state, err := GenerateRandomState()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate random state: %w", err)
|
||||
}
|
||||
|
||||
// Store the original request URL in the state
|
||||
stateData := map[string]string{
|
||||
"state": state,
|
||||
"returnTo": fmt.Sprintf("%s://%s%s", scheme, ctx.Request.Host, ctx.Request.URL.String()),
|
||||
"sandboxId": sandboxId,
|
||||
}
|
||||
stateJson, err := json.Marshal(stateData)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal state: %w", err)
|
||||
}
|
||||
encodedState := base64.URLEncoding.EncodeToString(stateJson)
|
||||
|
||||
authURL := oauth2Config.AuthCodeURL(
|
||||
encodedState,
|
||||
oauth2.SetAuthURLParam("audience", p.config.Oidc.Audience),
|
||||
)
|
||||
|
||||
return authURL, nil
|
||||
}
|
||||
|
||||
func (p *Proxy) hasSandboxAccess(ctx context.Context, sandboxId string, authToken string) bool {
|
||||
clientConfig := daytonaapiclient.NewConfiguration()
|
||||
clientConfig.Servers = daytonaapiclient.ServerConfigurations{
|
||||
{
|
||||
URL: p.config.DaytonaApiUrl,
|
||||
},
|
||||
}
|
||||
clientConfig.AddDefaultHeader("Authorization", "Bearer "+authToken)
|
||||
|
||||
apiClient := daytonaapiclient.NewAPIClient(clientConfig)
|
||||
|
||||
res, _ := apiClient.PreviewAPI.HasSandboxAccess(ctx, sandboxId).Execute()
|
||||
|
||||
return res != nil && res.StatusCode == http.StatusOK
|
||||
}
|
||||
|
||||
func GenerateRandomState() (string, error) {
|
||||
b := make([]byte, 32)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return base64.URLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
common_errors "github.com/daytonaio/common-go/pkg/errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (p *Proxy) GetProxyTarget(ctx *gin.Context) (*url.URL, string, map[string]string, error) {
|
||||
// Extract port and sandbox ID from the host header
|
||||
// Expected format: 1234-some-id-uuid.proxy.domain
|
||||
host := ctx.Request.Host
|
||||
if host == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("host header is required")))
|
||||
return nil, "", nil, errors.New("host header is required")
|
||||
}
|
||||
|
||||
// Split the host to extract the port and sandbox ID
|
||||
parts := strings.Split(host, ".")
|
||||
if len(parts) == 0 {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("invalid host format")))
|
||||
return nil, "", nil, errors.New("invalid host format")
|
||||
}
|
||||
|
||||
// Extract port from the first part (e.g., "1234-some-id-uuid")
|
||||
hostPrefix := parts[0]
|
||||
dashIndex := strings.Index(hostPrefix, "-")
|
||||
if dashIndex == -1 {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("invalid host format: port and sandbox ID not found")))
|
||||
return nil, "", nil, errors.New("invalid host format: port and sandbox ID not found")
|
||||
}
|
||||
|
||||
targetPort := hostPrefix[:dashIndex]
|
||||
sandboxID := hostPrefix[dashIndex+1:]
|
||||
|
||||
if targetPort == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("target port is required")))
|
||||
return nil, "", nil, errors.New("target port is required")
|
||||
}
|
||||
|
||||
if sandboxID == "" {
|
||||
ctx.Error(common_errors.NewBadRequestError(errors.New("sandbox ID is required")))
|
||||
return nil, "", nil, errors.New("sandbox ID is required")
|
||||
}
|
||||
|
||||
isPublic, err := p.getSandboxPublic(ctx, sandboxID)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to get sandbox public status: %w", err)))
|
||||
return nil, "", nil, fmt.Errorf("failed to get sandbox public status: %w", err)
|
||||
}
|
||||
|
||||
if !*isPublic || targetPort == "22222" {
|
||||
err, didRedirect := p.Authenticate(ctx, sandboxID)
|
||||
if err != nil {
|
||||
if !didRedirect {
|
||||
ctx.Error(common_errors.NewUnauthorizedError(err))
|
||||
}
|
||||
return nil, "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
runnerInfo, err := p.getRunnerInfo(ctx, sandboxID)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to get runner info: %w", err)))
|
||||
return nil, "", nil, fmt.Errorf("failed to get runner info: %w", err)
|
||||
}
|
||||
|
||||
// Build the target URL
|
||||
targetURL := fmt.Sprintf("%s/sandboxes/%s/toolbox/proxy/%s", runnerInfo.ApiUrl, sandboxID, targetPort)
|
||||
target, err := url.Parse(targetURL)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to parse target URL: %w", err)))
|
||||
return nil, "", nil, fmt.Errorf("failed to parse target URL: %w", err)
|
||||
}
|
||||
|
||||
// Get the wildcard path and normalize it
|
||||
path := ctx.Param("path")
|
||||
|
||||
// Ensure path always has a leading slash but not duplicate slashes
|
||||
if path == "" {
|
||||
path = "/"
|
||||
} else if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
// Create the complete target URL with path
|
||||
fullTargetURL := fmt.Sprintf("%s%s", targetURL, path)
|
||||
if ctx.Request.URL.RawQuery != "" {
|
||||
fullTargetURL = fmt.Sprintf("%s?%s", fullTargetURL, ctx.Request.URL.RawQuery)
|
||||
}
|
||||
|
||||
return target, fullTargetURL, map[string]string{
|
||||
"X-Daytona-Authorization": fmt.Sprintf("Bearer %s", runnerInfo.ApiKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Proxy) getRunnerInfo(ctx context.Context, sandboxId string) (*RunnerInfo, error) {
|
||||
has, err := p.runnerCache.Has(ctx, sandboxId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if has {
|
||||
return p.runnerCache.Get(ctx, sandboxId)
|
||||
}
|
||||
|
||||
runner, _, err := p.daytonaApiClient.RunnersAPI.GetRunnerBySandboxId(context.Background(), sandboxId).Execute()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := RunnerInfo{
|
||||
ApiUrl: runner.ApiUrl,
|
||||
ApiKey: runner.ApiKey,
|
||||
}
|
||||
|
||||
p.runnerCache.Set(ctx, sandboxId, info, 1*time.Hour)
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (p *Proxy) getSandboxPublic(ctx context.Context, sandboxId string) (*bool, error) {
|
||||
has, err := p.sandboxPublicCache.Has(ctx, sandboxId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if has {
|
||||
return p.sandboxPublicCache.Get(ctx, sandboxId)
|
||||
}
|
||||
|
||||
isPublic := false
|
||||
_, resp, _ := p.daytonaApiClient.PreviewAPI.IsSandboxPublic(context.Background(), sandboxId).Execute()
|
||||
if resp != nil && resp.StatusCode == http.StatusOK {
|
||||
isPublic = true
|
||||
}
|
||||
|
||||
p.sandboxPublicCache.Set(ctx, sandboxId, isPublic, 2*time.Minute)
|
||||
|
||||
return &isPublic, nil
|
||||
}
|
||||
|
||||
func (p *Proxy) getSandboxAuthKeyValid(ctx context.Context, sandboxId string, authKey string) (*bool, error) {
|
||||
has, err := p.sandboxAuthKeyValidCache.Has(ctx, authKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if has {
|
||||
return p.sandboxAuthKeyValidCache.Get(ctx, authKey)
|
||||
}
|
||||
|
||||
isValid := false
|
||||
_, resp, _ := p.daytonaApiClient.PreviewAPI.IsValidAuthToken(context.Background(), sandboxId, authKey).Execute()
|
||||
if resp != nil && resp.StatusCode == http.StatusOK {
|
||||
isValid = true
|
||||
}
|
||||
|
||||
p.sandboxAuthKeyValidCache.Set(ctx, authKey, isValid, 2*time.Minute)
|
||||
|
||||
return &isValid, nil
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/daytonaio/daytona/daytonaapiclient"
|
||||
"github.com/daytonaio/proxy/cmd/proxy/config"
|
||||
"github.com/daytonaio/proxy/pkg/cache"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/securecookie"
|
||||
|
||||
common_errors "github.com/daytonaio/common-go/pkg/errors"
|
||||
common_proxy "github.com/daytonaio/common-go/pkg/proxy"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type RunnerInfo struct {
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
const DAYTONA_SANDBOX_AUTH_KEY_HEADER = "X-Daytona-Preview-Token"
|
||||
const DAYTONA_SANDBOX_AUTH_KEY_QUERY_PARAM = "DAYTONA_SANDBOX_AUTH_KEY"
|
||||
const DAYTONA_SANDBOX_AUTH_COOKIE_NAME = "daytona-sandbox-auth-"
|
||||
|
||||
type Proxy struct {
|
||||
config *config.Config
|
||||
secureCookie *securecookie.SecureCookie
|
||||
|
||||
daytonaApiClient *daytonaapiclient.APIClient
|
||||
runnerCache cache.ICache[RunnerInfo]
|
||||
sandboxPublicCache cache.ICache[bool]
|
||||
sandboxAuthKeyValidCache cache.ICache[bool]
|
||||
}
|
||||
|
||||
func StartProxy(config *config.Config) error {
|
||||
proxy := &Proxy{
|
||||
config: config,
|
||||
}
|
||||
|
||||
proxy.secureCookie = securecookie.New([]byte(config.ProxyApiKey), nil)
|
||||
|
||||
clientConfig := daytonaapiclient.NewConfiguration()
|
||||
clientConfig.Servers = daytonaapiclient.ServerConfigurations{
|
||||
{
|
||||
URL: config.DaytonaApiUrl,
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig.AddDefaultHeader("Authorization", "Bearer "+config.ProxyApiKey)
|
||||
|
||||
proxy.daytonaApiClient = daytonaapiclient.NewAPIClient(clientConfig)
|
||||
|
||||
proxy.daytonaApiClient.GetConfig().HTTPClient = &http.Client{
|
||||
Transport: http.DefaultTransport,
|
||||
}
|
||||
|
||||
if config.Redis != nil {
|
||||
var err error
|
||||
proxy.runnerCache, err = cache.NewRedisCache[RunnerInfo](config.Redis, "proxy:sandbox-runner-info:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proxy.sandboxPublicCache, err = cache.NewRedisCache[bool](config.Redis, "proxy:sandbox-public:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proxy.sandboxAuthKeyValidCache, err = cache.NewRedisCache[bool](config.Redis, "proxy:sandbox-auth-key-valid:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
proxy.runnerCache = cache.NewMapCache[RunnerInfo]()
|
||||
proxy.sandboxPublicCache = cache.NewMapCache[bool]()
|
||||
proxy.sandboxAuthKeyValidCache = cache.NewMapCache[bool]()
|
||||
}
|
||||
|
||||
router := gin.New()
|
||||
router.Use(gin.Recovery())
|
||||
|
||||
corsConfig := cors.DefaultConfig()
|
||||
corsConfig.AllowAllOrigins = true
|
||||
corsConfig.AllowCredentials = true
|
||||
router.Use(cors.New(corsConfig))
|
||||
|
||||
router.Use(common_errors.NewErrorMiddleware(func(ctx *gin.Context, err error) common_errors.ErrorResponse {
|
||||
return common_errors.ErrorResponse{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}))
|
||||
|
||||
router.Any("/*path", func(ctx *gin.Context) {
|
||||
if ctx.Request.Host == config.ProxyDomain && ctx.Request.Method == "GET" && ctx.Request.URL.Path == "/callback" {
|
||||
proxy.AuthCallback(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
common_proxy.NewProxyRequestHandler(proxy.GetProxyTarget)(ctx)
|
||||
})
|
||||
|
||||
httpServer := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", config.ProxyPort),
|
||||
Handler: router,
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", httpServer.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Proxy server is running on port %d", config.ProxyPort)
|
||||
|
||||
if config.EnableTLS {
|
||||
err = httpServer.ServeTLS(listener, config.TLSCertFile, config.TLSKeyFile)
|
||||
} else {
|
||||
err = httpServer.Serve(listener)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "proxy",
|
||||
"$schema": "../../runner_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "apps/proxy",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx-go/nx-go:build",
|
||||
"options": {
|
||||
"main": "{projectRoot}/cmd/proxy/main.go",
|
||||
"outputPath": "dist/apps/proxy"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nx-go/nx-go:serve",
|
||||
"options": {
|
||||
"cmd": "gow",
|
||||
"cwd": ".",
|
||||
"main": "{projectRoot}/cmd/proxy/main.go"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {}
|
||||
}
|
||||
},
|
||||
"format": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "cd {projectRoot} && go fmt ./..."
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx-go/nx-go:test"
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx-go/nx-go:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -4,7 +4,7 @@ go 1.23.2
|
||||
|
||||
require (
|
||||
github.com/docker/docker v27.5.1+incompatible
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/go-playground/validator/v10 v10.24.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/joho/godotenv v1.5.1
|
||||
@@ -19,7 +19,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
@@ -29,6 +29,8 @@ require (
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/creack/pty v1.1.23 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
@@ -59,7 +61,7 @@ require (
|
||||
github.com/minio/crc64nvme v1.0.1 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
@@ -68,6 +70,7 @@ require (
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
@@ -75,7 +78,7 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
|
||||
+7
-12
@@ -1,5 +1,4 @@
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
@@ -22,11 +21,10 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8=
|
||||
@@ -45,8 +43,7 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d
|
||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -125,8 +122,7 @@ github.com/minio/minio-go/v7 v7.0.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5
|
||||
github.com/minio/minio-go/v7 v7.0.91/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -144,8 +140,8 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
@@ -188,8 +184,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
|
||||
@@ -6,3 +6,5 @@ package constants
|
||||
const BEARER_AUTH_HEADER = "Bearer"
|
||||
|
||||
const AUTHORIZATION_HEADER = "Authorization"
|
||||
|
||||
const DAYTONA_AUTHORIZATION_HEADER = "X-Daytona-Authorization"
|
||||
|
||||
@@ -5,21 +5,36 @@ package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/daytonaio/runner/pkg/common"
|
||||
"github.com/daytonaio/common-go/pkg/errors"
|
||||
"github.com/daytonaio/common-go/pkg/proxy"
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
func ProxyCommandLogsStream(ctx *gin.Context, fullTargetURL string) {
|
||||
func ProxyCommandLogsStream(ctx *gin.Context) {
|
||||
targetURL, fullTargetURL, extraHeaders, err := getProxyTarget(ctx)
|
||||
if err != nil {
|
||||
// Error already sent to the context
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Query("follow") != "true" {
|
||||
proxy.NewProxyRequestHandler(func(ctx *gin.Context) (*url.URL, string, map[string]string, error) {
|
||||
return targetURL, fullTargetURL, extraHeaders, nil
|
||||
})(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
fullTargetURL = strings.Replace(fullTargetURL, "http://", "ws://", 1)
|
||||
|
||||
ws, _, err := websocket.DefaultDialer.DialContext(ctx, fullTargetURL, nil)
|
||||
if err != nil {
|
||||
ctx.Error(common.NewBadRequestError(fmt.Errorf("failed to create outgoing request: %w", err)))
|
||||
ctx.Error(errors.NewBadRequestError(fmt.Errorf("failed to create outgoing request: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -6,57 +6,16 @@ package controllers
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
proxy "github.com/daytonaio/common-go/pkg/proxy"
|
||||
"github.com/daytonaio/runner/pkg/common"
|
||||
"github.com/daytonaio/runner/pkg/runner"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var proxyTransport = &http.Transport{
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext,
|
||||
}
|
||||
|
||||
// Custom HTTP client that follows redirects while maintaining original headers
|
||||
var proxyClient = &http.Client{
|
||||
Transport: proxyTransport,
|
||||
// Create a custom redirect policy
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
// Copy headers from original request
|
||||
if len(via) > 0 {
|
||||
// Copy the headers from the original request
|
||||
for key, values := range via[0].Header {
|
||||
// Skip certain headers that shouldn't be copied
|
||||
if key != "Authorization" && key != "Cookie" {
|
||||
for _, value := range values {
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limit the number of redirects to prevent infinite loops
|
||||
if len(via) >= 10 {
|
||||
return errors.New("stopped after 10 redirects")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// ProxyRequest handles proxying requests to a sandbox's container
|
||||
//
|
||||
// @Tags toolbox
|
||||
@@ -72,86 +31,30 @@ var proxyClient = &http.Client{
|
||||
// @Failure 500 {object} string "Internal server error"
|
||||
// @Router /sandboxes/{sandboxId}/toolbox/{path} [get]
|
||||
func ProxyRequest(ctx *gin.Context) {
|
||||
target, fullTargetURL, err := getProxyTarget(ctx)
|
||||
if err != nil {
|
||||
// Error already sent to the context
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(ctx.Param("path"))
|
||||
|
||||
if regexp.MustCompile(`^/process/session/.+/command/.+/logs$`).MatchString(ctx.Param("path")) {
|
||||
if ctx.Query("follow") == "true" {
|
||||
ProxyCommandLogsStream(ctx, fullTargetURL)
|
||||
ProxyCommandLogsStream(ctx)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new outgoing request
|
||||
outReq, err := http.NewRequestWithContext(
|
||||
ctx.Request.Context(),
|
||||
ctx.Request.Method,
|
||||
fullTargetURL,
|
||||
ctx.Request.Body,
|
||||
)
|
||||
if err != nil {
|
||||
ctx.Error(common.NewBadRequestError(fmt.Errorf("failed to create outgoing request: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
// Copy headers from original request
|
||||
for key, values := range ctx.Request.Header {
|
||||
// Skip the Connection header
|
||||
if key != "Connection" {
|
||||
for _, value := range values {
|
||||
outReq.Header.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Host header to the target
|
||||
outReq.Host = target.Host
|
||||
outReq.Header.Set("Connection", "keep-alive")
|
||||
|
||||
// Execute the request with our custom client that handles redirects
|
||||
resp, err := proxyClient.Do(outReq)
|
||||
if err != nil {
|
||||
ctx.Error(fmt.Errorf("proxy request failed: %w", err))
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Copy response headers
|
||||
for key, values := range resp.Header {
|
||||
for _, value := range values {
|
||||
ctx.Writer.Header().Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Set the status code
|
||||
ctx.Writer.WriteHeader(resp.StatusCode)
|
||||
|
||||
// Copy the response body
|
||||
if _, err := io.Copy(ctx.Writer, resp.Body); err != nil {
|
||||
log.Errorf("Error copying response body: %v", err)
|
||||
// Error already sent to client, just log here
|
||||
}
|
||||
proxy.NewProxyRequestHandler(getProxyTarget)(ctx)
|
||||
}
|
||||
|
||||
func getProxyTarget(ctx *gin.Context) (*url.URL, string, error) {
|
||||
func getProxyTarget(ctx *gin.Context) (*url.URL, string, map[string]string, error) {
|
||||
runner := runner.GetInstance(nil)
|
||||
|
||||
sandboxId := ctx.Param("sandboxId")
|
||||
if sandboxId == "" {
|
||||
ctx.Error(common.NewBadRequestError(errors.New("sandbox ID is required")))
|
||||
return nil, "", errors.New("sandbox ID is required")
|
||||
return nil, "", nil, errors.New("sandbox ID is required")
|
||||
}
|
||||
|
||||
// Get container details
|
||||
container, err := runner.Docker.ContainerInspect(ctx.Request.Context(), sandboxId)
|
||||
if err != nil {
|
||||
ctx.Error(common.NewNotFoundError(fmt.Errorf("sandbox container not found: %w", err)))
|
||||
return nil, "", fmt.Errorf("sandbox container not found: %w", err)
|
||||
return nil, "", nil, fmt.Errorf("sandbox container not found: %w", err)
|
||||
}
|
||||
|
||||
var containerIP string
|
||||
@@ -161,8 +64,8 @@ func getProxyTarget(ctx *gin.Context) (*url.URL, string, error) {
|
||||
}
|
||||
|
||||
if containerIP == "" {
|
||||
ctx.Error(errors.New("container has no IP address, it might not be running"))
|
||||
return nil, "", errors.New("container has no IP address, it might not be running")
|
||||
ctx.Error(common.NewBadRequestError(errors.New("container has no IP address, it might not be running")))
|
||||
return nil, "", nil, errors.New("container has no IP address, it might not be running")
|
||||
}
|
||||
|
||||
// Build the target URL
|
||||
@@ -170,7 +73,7 @@ func getProxyTarget(ctx *gin.Context) (*url.URL, string, error) {
|
||||
target, err := url.Parse(targetURL)
|
||||
if err != nil {
|
||||
ctx.Error(common.NewBadRequestError(fmt.Errorf("failed to parse target URL: %w", err)))
|
||||
return nil, "", fmt.Errorf("failed to parse target URL: %w", err)
|
||||
return nil, "", nil, fmt.Errorf("failed to parse target URL: %w", err)
|
||||
}
|
||||
|
||||
// Get the wildcard path and normalize it
|
||||
@@ -189,5 +92,5 @@ func getProxyTarget(ctx *gin.Context) (*url.URL, string, error) {
|
||||
fullTargetURL = fmt.Sprintf("%s?%s", fullTargetURL, ctx.Request.URL.RawQuery)
|
||||
}
|
||||
|
||||
return target, fullTargetURL, nil
|
||||
return target, fullTargetURL, nil, nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ import (
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
authHeader := ctx.GetHeader(constants.AUTHORIZATION_HEADER)
|
||||
if authHeader == "" {
|
||||
authHeader = ctx.GetHeader(constants.DAYTONA_AUTHORIZATION_HEADER)
|
||||
}
|
||||
|
||||
if authHeader == "" {
|
||||
ctx.Error(common.NewUnauthorizedError(errors.New("authorization header required")))
|
||||
ctx.Abort()
|
||||
|
||||
@@ -3,6 +3,8 @@ go 1.23.4
|
||||
use (
|
||||
./apps/cli
|
||||
./apps/daemon
|
||||
./apps/proxy
|
||||
./apps/runner
|
||||
./libs/api-client-go
|
||||
./libs/common-go
|
||||
)
|
||||
|
||||
+43
-12
@@ -37,10 +37,16 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/antonlindstrom/pgstore v0.0.0-20220421113606-e3a6e3fed12a/go.mod h1:Sdr/tmSOLEnncCuXS5TwZRxuk7deH1WXVY8cve3eVBM=
|
||||
github.com/boj/redistore v1.4.1/go.mod h1:c0Tvw6aMjslog4jHIAcNv6EtJM849YoOAhMY7JBbWpI=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20240916143655-c0e34fd2f304/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -52,10 +58,11 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -82,6 +89,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -93,6 +102,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
@@ -109,37 +119,52 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
||||
github.com/laziness-coders/mongostore v0.0.14/go.mod h1:Rh+yJax2Vxc2QY62clIM/kRnLk+TxivgSLHOXENXPtk=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
||||
github.com/memcachier/mc/v3 v3.0.3/go.mod h1:GzjocBahcXPxt2cmqzknrgqCOmMxiSzhVKPOe90Tpug=
|
||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc=
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/wader/gormstore/v2 v2.0.3/go.mod h1:sr3N3a8F1+PBc3fHoKaphFqDXLRJ9Oe6Yow0HxKFbbg=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -193,8 +218,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -207,6 +232,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -230,16 +257,18 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -359,9 +388,10 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -370,6 +400,7 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
||||
@@ -74,7 +74,11 @@ model_range.go
|
||||
model_registry_push_access_dto.go
|
||||
model_replace_request.go
|
||||
model_replace_result.go
|
||||
model_runner.go
|
||||
model_runner_region.go
|
||||
model_runner_state.go
|
||||
model_sandbox.go
|
||||
model_sandbox_class.go
|
||||
model_sandbox_info.go
|
||||
model_sandbox_labels.go
|
||||
model_sandbox_state.go
|
||||
|
||||
@@ -1696,6 +1696,33 @@ paths:
|
||||
summary: Update runner scheduling status
|
||||
tags:
|
||||
- runners
|
||||
/runners/by-sandbox/{sandboxId}:
|
||||
get:
|
||||
operationId: getRunnerBySandboxId
|
||||
parameters:
|
||||
- explode: false
|
||||
in: path
|
||||
name: sandboxId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
style: simple
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Runner'
|
||||
description: Runner found
|
||||
security:
|
||||
- bearer: []
|
||||
- oauth2:
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
summary: Get runner by sandbox ID
|
||||
tags:
|
||||
- runners
|
||||
/toolbox/{sandboxId}/toolbox/project-dir:
|
||||
get:
|
||||
operationId: getProjectDir
|
||||
@@ -6023,6 +6050,143 @@ components:
|
||||
- memory
|
||||
- region
|
||||
type: object
|
||||
SandboxClass:
|
||||
description: The class of the runner
|
||||
enum:
|
||||
- small
|
||||
- medium
|
||||
- large
|
||||
type: string
|
||||
RunnerRegion:
|
||||
description: The region of the runner
|
||||
enum:
|
||||
- eu
|
||||
- us
|
||||
- asia
|
||||
type: string
|
||||
RunnerState:
|
||||
description: The state of the runner
|
||||
enum:
|
||||
- initializing
|
||||
- ready
|
||||
- disabled
|
||||
- decommissioned
|
||||
- unresponsive
|
||||
type: string
|
||||
Runner:
|
||||
example:
|
||||
memory: 16
|
||||
apiKey: api-key-123
|
||||
cpu: 8
|
||||
used: 2
|
||||
gpu: 1
|
||||
capacity: 10
|
||||
createdAt: 2023-10-01T12:00:00Z
|
||||
disk: 100
|
||||
apiUrl: https://api.runner1.example.com
|
||||
domain: runner1.example.com
|
||||
id: runner123
|
||||
state: initializing
|
||||
region: eu
|
||||
unschedulable: false
|
||||
class: small
|
||||
lastChecked: 2024-10-01T12:00:00Z
|
||||
gpuType: gpuType
|
||||
updatedAt: 2023-10-01T12:00:00Z
|
||||
properties:
|
||||
id:
|
||||
description: The ID of the runner
|
||||
example: runner123
|
||||
type: string
|
||||
domain:
|
||||
description: The domain of the runner
|
||||
example: runner1.example.com
|
||||
type: string
|
||||
apiUrl:
|
||||
description: The API URL of the runner
|
||||
example: https://api.runner1.example.com
|
||||
type: string
|
||||
apiKey:
|
||||
description: The API key for the runner
|
||||
example: api-key-123
|
||||
type: string
|
||||
cpu:
|
||||
description: The CPU capacity of the runner
|
||||
example: 8
|
||||
type: number
|
||||
memory:
|
||||
description: The memory capacity of the runner in GB
|
||||
example: 16
|
||||
type: number
|
||||
disk:
|
||||
description: The disk capacity of the runner in GB
|
||||
example: 100
|
||||
type: number
|
||||
gpu:
|
||||
description: The GPU capacity of the runner
|
||||
example: 1
|
||||
type: number
|
||||
gpuType:
|
||||
description: The type of GPU
|
||||
type: string
|
||||
class:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/SandboxClass'
|
||||
description: The class of the runner
|
||||
example: small
|
||||
used:
|
||||
description: The current usage of the runner
|
||||
example: 2
|
||||
type: number
|
||||
capacity:
|
||||
description: The capacity of the runner
|
||||
example: 10
|
||||
type: number
|
||||
region:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RunnerRegion'
|
||||
description: The region of the runner
|
||||
example: eu
|
||||
state:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RunnerState'
|
||||
description: The state of the runner
|
||||
example: initializing
|
||||
lastChecked:
|
||||
description: The last time the runner was checked
|
||||
example: 2024-10-01T12:00:00Z
|
||||
type: string
|
||||
unschedulable:
|
||||
description: Whether the runner is unschedulable
|
||||
example: false
|
||||
type: boolean
|
||||
createdAt:
|
||||
description: The creation timestamp of the runner
|
||||
example: 2023-10-01T12:00:00Z
|
||||
type: string
|
||||
updatedAt:
|
||||
description: The last update timestamp of the runner
|
||||
example: 2023-10-01T12:00:00Z
|
||||
type: string
|
||||
required:
|
||||
- apiKey
|
||||
- apiUrl
|
||||
- capacity
|
||||
- class
|
||||
- cpu
|
||||
- createdAt
|
||||
- disk
|
||||
- domain
|
||||
- gpu
|
||||
- gpuType
|
||||
- id
|
||||
- memory
|
||||
- region
|
||||
- state
|
||||
- unschedulable
|
||||
- updatedAt
|
||||
- used
|
||||
type: object
|
||||
ProjectDirResponse:
|
||||
example:
|
||||
dir: dir
|
||||
|
||||
@@ -36,6 +36,19 @@ type RunnersAPI interface {
|
||||
// CreateRunnerExecute executes the request
|
||||
CreateRunnerExecute(r RunnersAPICreateRunnerRequest) (*http.Response, error)
|
||||
|
||||
/*
|
||||
GetRunnerBySandboxId Get runner by sandbox ID
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param sandboxId
|
||||
@return RunnersAPIGetRunnerBySandboxIdRequest
|
||||
*/
|
||||
GetRunnerBySandboxId(ctx context.Context, sandboxId string) RunnersAPIGetRunnerBySandboxIdRequest
|
||||
|
||||
// GetRunnerBySandboxIdExecute executes the request
|
||||
// @return Runner
|
||||
GetRunnerBySandboxIdExecute(r RunnersAPIGetRunnerBySandboxIdRequest) (*Runner, *http.Response, error)
|
||||
|
||||
/*
|
||||
ListRunners List all runners
|
||||
|
||||
@@ -160,6 +173,108 @@ func (a *RunnersAPIService) CreateRunnerExecute(r RunnersAPICreateRunnerRequest)
|
||||
return localVarHTTPResponse, nil
|
||||
}
|
||||
|
||||
type RunnersAPIGetRunnerBySandboxIdRequest struct {
|
||||
ctx context.Context
|
||||
ApiService RunnersAPI
|
||||
sandboxId string
|
||||
}
|
||||
|
||||
func (r RunnersAPIGetRunnerBySandboxIdRequest) Execute() (*Runner, *http.Response, error) {
|
||||
return r.ApiService.GetRunnerBySandboxIdExecute(r)
|
||||
}
|
||||
|
||||
/*
|
||||
GetRunnerBySandboxId Get runner by sandbox ID
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param sandboxId
|
||||
@return RunnersAPIGetRunnerBySandboxIdRequest
|
||||
*/
|
||||
func (a *RunnersAPIService) GetRunnerBySandboxId(ctx context.Context, sandboxId string) RunnersAPIGetRunnerBySandboxIdRequest {
|
||||
return RunnersAPIGetRunnerBySandboxIdRequest{
|
||||
ApiService: a,
|
||||
ctx: ctx,
|
||||
sandboxId: sandboxId,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the request
|
||||
//
|
||||
// @return Runner
|
||||
func (a *RunnersAPIService) GetRunnerBySandboxIdExecute(r RunnersAPIGetRunnerBySandboxIdRequest) (*Runner, *http.Response, error) {
|
||||
var (
|
||||
localVarHTTPMethod = http.MethodGet
|
||||
localVarPostBody interface{}
|
||||
formFiles []formFile
|
||||
localVarReturnValue *Runner
|
||||
)
|
||||
|
||||
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnersAPIService.GetRunnerBySandboxId")
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||
}
|
||||
|
||||
localVarPath := localBasePath + "/runners/by-sandbox/{sandboxId}"
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"sandboxId"+"}", url.PathEscape(parameterValueToString(r.sandboxId, "sandboxId")), -1)
|
||||
|
||||
localVarHeaderParams := make(map[string]string)
|
||||
localVarQueryParams := url.Values{}
|
||||
localVarFormParams := url.Values{}
|
||||
|
||||
// to determine the Content-Type header
|
||||
localVarHTTPContentTypes := []string{}
|
||||
|
||||
// set Content-Type header
|
||||
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||
if localVarHTTPContentType != "" {
|
||||
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||
}
|
||||
|
||||
// to determine the Accept header
|
||||
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||
|
||||
// set Accept header
|
||||
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||
if localVarHTTPHeaderAccept != "" {
|
||||
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||
}
|
||||
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, err
|
||||
}
|
||||
|
||||
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||
if err != nil || localVarHTTPResponse == nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||
localVarHTTPResponse.Body.Close()
|
||||
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||
if err != nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
if localVarHTTPResponse.StatusCode >= 300 {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: localVarHTTPResponse.Status,
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: err.Error(),
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
return localVarReturnValue, localVarHTTPResponse, nil
|
||||
}
|
||||
|
||||
type RunnersAPIListRunnersRequest struct {
|
||||
ctx context.Context
|
||||
ApiService RunnersAPI
|
||||
|
||||
@@ -0,0 +1,662 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
API version: 1.0
|
||||
Contact: support@daytona.com
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package daytonaapiclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// checks if the Runner type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &Runner{}
|
||||
|
||||
// Runner struct for Runner
|
||||
type Runner struct {
|
||||
// The ID of the runner
|
||||
Id string `json:"id"`
|
||||
// The domain of the runner
|
||||
Domain string `json:"domain"`
|
||||
// The API URL of the runner
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// The API key for the runner
|
||||
ApiKey string `json:"apiKey"`
|
||||
// The CPU capacity of the runner
|
||||
Cpu float32 `json:"cpu"`
|
||||
// The memory capacity of the runner in GB
|
||||
Memory float32 `json:"memory"`
|
||||
// The disk capacity of the runner in GB
|
||||
Disk float32 `json:"disk"`
|
||||
// The GPU capacity of the runner
|
||||
Gpu float32 `json:"gpu"`
|
||||
// The type of GPU
|
||||
GpuType string `json:"gpuType"`
|
||||
// The class of the runner
|
||||
Class SandboxClass `json:"class"`
|
||||
// The current usage of the runner
|
||||
Used float32 `json:"used"`
|
||||
// The capacity of the runner
|
||||
Capacity float32 `json:"capacity"`
|
||||
// The region of the runner
|
||||
Region RunnerRegion `json:"region"`
|
||||
// The state of the runner
|
||||
State RunnerState `json:"state"`
|
||||
// The last time the runner was checked
|
||||
LastChecked *string `json:"lastChecked,omitempty"`
|
||||
// Whether the runner is unschedulable
|
||||
Unschedulable bool `json:"unschedulable"`
|
||||
// The creation timestamp of the runner
|
||||
CreatedAt string `json:"createdAt"`
|
||||
// The last update timestamp of the runner
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type _Runner Runner
|
||||
|
||||
// NewRunner instantiates a new Runner object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewRunner(id string, domain string, apiUrl string, apiKey string, cpu float32, memory float32, disk float32, gpu float32, gpuType string, class SandboxClass, used float32, capacity float32, region RunnerRegion, state RunnerState, unschedulable bool, createdAt string, updatedAt string) *Runner {
|
||||
this := Runner{}
|
||||
this.Id = id
|
||||
this.Domain = domain
|
||||
this.ApiUrl = apiUrl
|
||||
this.ApiKey = apiKey
|
||||
this.Cpu = cpu
|
||||
this.Memory = memory
|
||||
this.Disk = disk
|
||||
this.Gpu = gpu
|
||||
this.GpuType = gpuType
|
||||
this.Class = class
|
||||
this.Used = used
|
||||
this.Capacity = capacity
|
||||
this.Region = region
|
||||
this.State = state
|
||||
this.Unschedulable = unschedulable
|
||||
this.CreatedAt = createdAt
|
||||
this.UpdatedAt = updatedAt
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewRunnerWithDefaults instantiates a new Runner object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewRunnerWithDefaults() *Runner {
|
||||
this := Runner{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetId returns the Id field value
|
||||
func (o *Runner) GetId() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Id
|
||||
}
|
||||
|
||||
// GetIdOk returns a tuple with the Id field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetIdOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Id, true
|
||||
}
|
||||
|
||||
// SetId sets field value
|
||||
func (o *Runner) SetId(v string) {
|
||||
o.Id = v
|
||||
}
|
||||
|
||||
// GetDomain returns the Domain field value
|
||||
func (o *Runner) GetDomain() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Domain
|
||||
}
|
||||
|
||||
// GetDomainOk returns a tuple with the Domain field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetDomainOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Domain, true
|
||||
}
|
||||
|
||||
// SetDomain sets field value
|
||||
func (o *Runner) SetDomain(v string) {
|
||||
o.Domain = v
|
||||
}
|
||||
|
||||
// GetApiUrl returns the ApiUrl field value
|
||||
func (o *Runner) GetApiUrl() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.ApiUrl
|
||||
}
|
||||
|
||||
// GetApiUrlOk returns a tuple with the ApiUrl field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetApiUrlOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.ApiUrl, true
|
||||
}
|
||||
|
||||
// SetApiUrl sets field value
|
||||
func (o *Runner) SetApiUrl(v string) {
|
||||
o.ApiUrl = v
|
||||
}
|
||||
|
||||
// GetApiKey returns the ApiKey field value
|
||||
func (o *Runner) GetApiKey() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.ApiKey
|
||||
}
|
||||
|
||||
// GetApiKeyOk returns a tuple with the ApiKey field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetApiKeyOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.ApiKey, true
|
||||
}
|
||||
|
||||
// SetApiKey sets field value
|
||||
func (o *Runner) SetApiKey(v string) {
|
||||
o.ApiKey = v
|
||||
}
|
||||
|
||||
// GetCpu returns the Cpu field value
|
||||
func (o *Runner) GetCpu() float32 {
|
||||
if o == nil {
|
||||
var ret float32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Cpu
|
||||
}
|
||||
|
||||
// GetCpuOk returns a tuple with the Cpu field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetCpuOk() (*float32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Cpu, true
|
||||
}
|
||||
|
||||
// SetCpu sets field value
|
||||
func (o *Runner) SetCpu(v float32) {
|
||||
o.Cpu = v
|
||||
}
|
||||
|
||||
// GetMemory returns the Memory field value
|
||||
func (o *Runner) GetMemory() float32 {
|
||||
if o == nil {
|
||||
var ret float32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Memory
|
||||
}
|
||||
|
||||
// GetMemoryOk returns a tuple with the Memory field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetMemoryOk() (*float32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Memory, true
|
||||
}
|
||||
|
||||
// SetMemory sets field value
|
||||
func (o *Runner) SetMemory(v float32) {
|
||||
o.Memory = v
|
||||
}
|
||||
|
||||
// GetDisk returns the Disk field value
|
||||
func (o *Runner) GetDisk() float32 {
|
||||
if o == nil {
|
||||
var ret float32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Disk
|
||||
}
|
||||
|
||||
// GetDiskOk returns a tuple with the Disk field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetDiskOk() (*float32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Disk, true
|
||||
}
|
||||
|
||||
// SetDisk sets field value
|
||||
func (o *Runner) SetDisk(v float32) {
|
||||
o.Disk = v
|
||||
}
|
||||
|
||||
// GetGpu returns the Gpu field value
|
||||
func (o *Runner) GetGpu() float32 {
|
||||
if o == nil {
|
||||
var ret float32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Gpu
|
||||
}
|
||||
|
||||
// GetGpuOk returns a tuple with the Gpu field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetGpuOk() (*float32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Gpu, true
|
||||
}
|
||||
|
||||
// SetGpu sets field value
|
||||
func (o *Runner) SetGpu(v float32) {
|
||||
o.Gpu = v
|
||||
}
|
||||
|
||||
// GetGpuType returns the GpuType field value
|
||||
func (o *Runner) GetGpuType() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.GpuType
|
||||
}
|
||||
|
||||
// GetGpuTypeOk returns a tuple with the GpuType field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetGpuTypeOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.GpuType, true
|
||||
}
|
||||
|
||||
// SetGpuType sets field value
|
||||
func (o *Runner) SetGpuType(v string) {
|
||||
o.GpuType = v
|
||||
}
|
||||
|
||||
// GetClass returns the Class field value
|
||||
func (o *Runner) GetClass() SandboxClass {
|
||||
if o == nil {
|
||||
var ret SandboxClass
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Class
|
||||
}
|
||||
|
||||
// GetClassOk returns a tuple with the Class field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetClassOk() (*SandboxClass, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Class, true
|
||||
}
|
||||
|
||||
// SetClass sets field value
|
||||
func (o *Runner) SetClass(v SandboxClass) {
|
||||
o.Class = v
|
||||
}
|
||||
|
||||
// GetUsed returns the Used field value
|
||||
func (o *Runner) GetUsed() float32 {
|
||||
if o == nil {
|
||||
var ret float32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Used
|
||||
}
|
||||
|
||||
// GetUsedOk returns a tuple with the Used field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetUsedOk() (*float32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Used, true
|
||||
}
|
||||
|
||||
// SetUsed sets field value
|
||||
func (o *Runner) SetUsed(v float32) {
|
||||
o.Used = v
|
||||
}
|
||||
|
||||
// GetCapacity returns the Capacity field value
|
||||
func (o *Runner) GetCapacity() float32 {
|
||||
if o == nil {
|
||||
var ret float32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Capacity
|
||||
}
|
||||
|
||||
// GetCapacityOk returns a tuple with the Capacity field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetCapacityOk() (*float32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Capacity, true
|
||||
}
|
||||
|
||||
// SetCapacity sets field value
|
||||
func (o *Runner) SetCapacity(v float32) {
|
||||
o.Capacity = v
|
||||
}
|
||||
|
||||
// GetRegion returns the Region field value
|
||||
func (o *Runner) GetRegion() RunnerRegion {
|
||||
if o == nil {
|
||||
var ret RunnerRegion
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Region
|
||||
}
|
||||
|
||||
// GetRegionOk returns a tuple with the Region field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetRegionOk() (*RunnerRegion, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Region, true
|
||||
}
|
||||
|
||||
// SetRegion sets field value
|
||||
func (o *Runner) SetRegion(v RunnerRegion) {
|
||||
o.Region = v
|
||||
}
|
||||
|
||||
// GetState returns the State field value
|
||||
func (o *Runner) GetState() RunnerState {
|
||||
if o == nil {
|
||||
var ret RunnerState
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.State
|
||||
}
|
||||
|
||||
// GetStateOk returns a tuple with the State field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetStateOk() (*RunnerState, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.State, true
|
||||
}
|
||||
|
||||
// SetState sets field value
|
||||
func (o *Runner) SetState(v RunnerState) {
|
||||
o.State = v
|
||||
}
|
||||
|
||||
// GetLastChecked returns the LastChecked field value if set, zero value otherwise.
|
||||
func (o *Runner) GetLastChecked() string {
|
||||
if o == nil || IsNil(o.LastChecked) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.LastChecked
|
||||
}
|
||||
|
||||
// GetLastCheckedOk returns a tuple with the LastChecked field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetLastCheckedOk() (*string, bool) {
|
||||
if o == nil || IsNil(o.LastChecked) {
|
||||
return nil, false
|
||||
}
|
||||
return o.LastChecked, true
|
||||
}
|
||||
|
||||
// HasLastChecked returns a boolean if a field has been set.
|
||||
func (o *Runner) HasLastChecked() bool {
|
||||
if o != nil && !IsNil(o.LastChecked) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetLastChecked gets a reference to the given string and assigns it to the LastChecked field.
|
||||
func (o *Runner) SetLastChecked(v string) {
|
||||
o.LastChecked = &v
|
||||
}
|
||||
|
||||
// GetUnschedulable returns the Unschedulable field value
|
||||
func (o *Runner) GetUnschedulable() bool {
|
||||
if o == nil {
|
||||
var ret bool
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Unschedulable
|
||||
}
|
||||
|
||||
// GetUnschedulableOk returns a tuple with the Unschedulable field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetUnschedulableOk() (*bool, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Unschedulable, true
|
||||
}
|
||||
|
||||
// SetUnschedulable sets field value
|
||||
func (o *Runner) SetUnschedulable(v bool) {
|
||||
o.Unschedulable = v
|
||||
}
|
||||
|
||||
// GetCreatedAt returns the CreatedAt field value
|
||||
func (o *Runner) GetCreatedAt() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.CreatedAt
|
||||
}
|
||||
|
||||
// GetCreatedAtOk returns a tuple with the CreatedAt field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetCreatedAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.CreatedAt, true
|
||||
}
|
||||
|
||||
// SetCreatedAt sets field value
|
||||
func (o *Runner) SetCreatedAt(v string) {
|
||||
o.CreatedAt = v
|
||||
}
|
||||
|
||||
// GetUpdatedAt returns the UpdatedAt field value
|
||||
func (o *Runner) GetUpdatedAt() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.UpdatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAtOk returns a tuple with the UpdatedAt field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *Runner) GetUpdatedAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.UpdatedAt, true
|
||||
}
|
||||
|
||||
// SetUpdatedAt sets field value
|
||||
func (o *Runner) SetUpdatedAt(v string) {
|
||||
o.UpdatedAt = v
|
||||
}
|
||||
|
||||
func (o Runner) MarshalJSON() ([]byte, error) {
|
||||
toSerialize, err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o Runner) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
toSerialize["id"] = o.Id
|
||||
toSerialize["domain"] = o.Domain
|
||||
toSerialize["apiUrl"] = o.ApiUrl
|
||||
toSerialize["apiKey"] = o.ApiKey
|
||||
toSerialize["cpu"] = o.Cpu
|
||||
toSerialize["memory"] = o.Memory
|
||||
toSerialize["disk"] = o.Disk
|
||||
toSerialize["gpu"] = o.Gpu
|
||||
toSerialize["gpuType"] = o.GpuType
|
||||
toSerialize["class"] = o.Class
|
||||
toSerialize["used"] = o.Used
|
||||
toSerialize["capacity"] = o.Capacity
|
||||
toSerialize["region"] = o.Region
|
||||
toSerialize["state"] = o.State
|
||||
if !IsNil(o.LastChecked) {
|
||||
toSerialize["lastChecked"] = o.LastChecked
|
||||
}
|
||||
toSerialize["unschedulable"] = o.Unschedulable
|
||||
toSerialize["createdAt"] = o.CreatedAt
|
||||
toSerialize["updatedAt"] = o.UpdatedAt
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
func (o *Runner) UnmarshalJSON(data []byte) (err error) {
|
||||
// This validates that all required properties are included in the JSON object
|
||||
// by unmarshalling the object into a generic map with string keys and checking
|
||||
// that every required field exists as a key in the generic map.
|
||||
requiredProperties := []string{
|
||||
"id",
|
||||
"domain",
|
||||
"apiUrl",
|
||||
"apiKey",
|
||||
"cpu",
|
||||
"memory",
|
||||
"disk",
|
||||
"gpu",
|
||||
"gpuType",
|
||||
"class",
|
||||
"used",
|
||||
"capacity",
|
||||
"region",
|
||||
"state",
|
||||
"unschedulable",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
}
|
||||
|
||||
allProperties := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(data, &allProperties)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, requiredProperty := range requiredProperties {
|
||||
if _, exists := allProperties[requiredProperty]; !exists {
|
||||
return fmt.Errorf("no value given for required property %v", requiredProperty)
|
||||
}
|
||||
}
|
||||
|
||||
varRunner := _Runner{}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&varRunner)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*o = Runner(varRunner)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type NullableRunner struct {
|
||||
value *Runner
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableRunner) Get() *Runner {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableRunner) Set(val *Runner) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableRunner) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableRunner) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableRunner(val *Runner) *NullableRunner {
|
||||
return &NullableRunner{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableRunner) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableRunner) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
API version: 1.0
|
||||
Contact: support@daytona.com
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package daytonaapiclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RunnerRegion The region of the runner
|
||||
type RunnerRegion string
|
||||
|
||||
// List of RunnerRegion
|
||||
const (
|
||||
RUNNERREGION_EU RunnerRegion = "eu"
|
||||
RUNNERREGION_US RunnerRegion = "us"
|
||||
RUNNERREGION_ASIA RunnerRegion = "asia"
|
||||
)
|
||||
|
||||
// All allowed values of RunnerRegion enum
|
||||
var AllowedRunnerRegionEnumValues = []RunnerRegion{
|
||||
"eu",
|
||||
"us",
|
||||
"asia",
|
||||
}
|
||||
|
||||
func (v *RunnerRegion) UnmarshalJSON(src []byte) error {
|
||||
var value string
|
||||
err := json.Unmarshal(src, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enumTypeValue := RunnerRegion(value)
|
||||
for _, existing := range AllowedRunnerRegionEnumValues {
|
||||
if existing == enumTypeValue {
|
||||
*v = enumTypeValue
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%+v is not a valid RunnerRegion", value)
|
||||
}
|
||||
|
||||
// NewRunnerRegionFromValue returns a pointer to a valid RunnerRegion
|
||||
// for the value passed as argument, or an error if the value passed is not allowed by the enum
|
||||
func NewRunnerRegionFromValue(v string) (*RunnerRegion, error) {
|
||||
ev := RunnerRegion(v)
|
||||
if ev.IsValid() {
|
||||
return &ev, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid value '%v' for RunnerRegion: valid values are %v", v, AllowedRunnerRegionEnumValues)
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid return true if the value is valid for the enum, false otherwise
|
||||
func (v RunnerRegion) IsValid() bool {
|
||||
for _, existing := range AllowedRunnerRegionEnumValues {
|
||||
if existing == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Ptr returns reference to RunnerRegion value
|
||||
func (v RunnerRegion) Ptr() *RunnerRegion {
|
||||
return &v
|
||||
}
|
||||
|
||||
type NullableRunnerRegion struct {
|
||||
value *RunnerRegion
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableRunnerRegion) Get() *RunnerRegion {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableRunnerRegion) Set(val *RunnerRegion) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableRunnerRegion) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableRunnerRegion) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableRunnerRegion(val *RunnerRegion) *NullableRunnerRegion {
|
||||
return &NullableRunnerRegion{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableRunnerRegion) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableRunnerRegion) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
API version: 1.0
|
||||
Contact: support@daytona.com
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package daytonaapiclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RunnerState The state of the runner
|
||||
type RunnerState string
|
||||
|
||||
// List of RunnerState
|
||||
const (
|
||||
RUNNERSTATE_INITIALIZING RunnerState = "initializing"
|
||||
RUNNERSTATE_READY RunnerState = "ready"
|
||||
RUNNERSTATE_DISABLED RunnerState = "disabled"
|
||||
RUNNERSTATE_DECOMMISSIONED RunnerState = "decommissioned"
|
||||
RUNNERSTATE_UNRESPONSIVE RunnerState = "unresponsive"
|
||||
)
|
||||
|
||||
// All allowed values of RunnerState enum
|
||||
var AllowedRunnerStateEnumValues = []RunnerState{
|
||||
"initializing",
|
||||
"ready",
|
||||
"disabled",
|
||||
"decommissioned",
|
||||
"unresponsive",
|
||||
}
|
||||
|
||||
func (v *RunnerState) UnmarshalJSON(src []byte) error {
|
||||
var value string
|
||||
err := json.Unmarshal(src, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enumTypeValue := RunnerState(value)
|
||||
for _, existing := range AllowedRunnerStateEnumValues {
|
||||
if existing == enumTypeValue {
|
||||
*v = enumTypeValue
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%+v is not a valid RunnerState", value)
|
||||
}
|
||||
|
||||
// NewRunnerStateFromValue returns a pointer to a valid RunnerState
|
||||
// for the value passed as argument, or an error if the value passed is not allowed by the enum
|
||||
func NewRunnerStateFromValue(v string) (*RunnerState, error) {
|
||||
ev := RunnerState(v)
|
||||
if ev.IsValid() {
|
||||
return &ev, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid value '%v' for RunnerState: valid values are %v", v, AllowedRunnerStateEnumValues)
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid return true if the value is valid for the enum, false otherwise
|
||||
func (v RunnerState) IsValid() bool {
|
||||
for _, existing := range AllowedRunnerStateEnumValues {
|
||||
if existing == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Ptr returns reference to RunnerState value
|
||||
func (v RunnerState) Ptr() *RunnerState {
|
||||
return &v
|
||||
}
|
||||
|
||||
type NullableRunnerState struct {
|
||||
value *RunnerState
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableRunnerState) Get() *RunnerState {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableRunnerState) Set(val *RunnerState) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableRunnerState) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableRunnerState) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableRunnerState(val *RunnerState) *NullableRunnerState {
|
||||
return &NullableRunnerState{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableRunnerState) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableRunnerState) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
API version: 1.0
|
||||
Contact: support@daytona.com
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package daytonaapiclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// SandboxClass The class of the runner
|
||||
type SandboxClass string
|
||||
|
||||
// List of SandboxClass
|
||||
const (
|
||||
SANDBOXCLASS_SMALL SandboxClass = "small"
|
||||
SANDBOXCLASS_MEDIUM SandboxClass = "medium"
|
||||
SANDBOXCLASS_LARGE SandboxClass = "large"
|
||||
)
|
||||
|
||||
// All allowed values of SandboxClass enum
|
||||
var AllowedSandboxClassEnumValues = []SandboxClass{
|
||||
"small",
|
||||
"medium",
|
||||
"large",
|
||||
}
|
||||
|
||||
func (v *SandboxClass) UnmarshalJSON(src []byte) error {
|
||||
var value string
|
||||
err := json.Unmarshal(src, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enumTypeValue := SandboxClass(value)
|
||||
for _, existing := range AllowedSandboxClassEnumValues {
|
||||
if existing == enumTypeValue {
|
||||
*v = enumTypeValue
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%+v is not a valid SandboxClass", value)
|
||||
}
|
||||
|
||||
// NewSandboxClassFromValue returns a pointer to a valid SandboxClass
|
||||
// for the value passed as argument, or an error if the value passed is not allowed by the enum
|
||||
func NewSandboxClassFromValue(v string) (*SandboxClass, error) {
|
||||
ev := SandboxClass(v)
|
||||
if ev.IsValid() {
|
||||
return &ev, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid value '%v' for SandboxClass: valid values are %v", v, AllowedSandboxClassEnumValues)
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid return true if the value is valid for the enum, false otherwise
|
||||
func (v SandboxClass) IsValid() bool {
|
||||
for _, existing := range AllowedSandboxClassEnumValues {
|
||||
if existing == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Ptr returns reference to SandboxClass value
|
||||
func (v SandboxClass) Ptr() *SandboxClass {
|
||||
return &v
|
||||
}
|
||||
|
||||
type NullableSandboxClass struct {
|
||||
value *SandboxClass
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableSandboxClass) Get() *SandboxClass {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableSandboxClass) Set(val *SandboxClass) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableSandboxClass) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableSandboxClass) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableSandboxClass(val *SandboxClass) *NullableSandboxClass {
|
||||
return &NullableSandboxClass{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableSandboxClass) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableSandboxClass) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
@@ -76,7 +76,11 @@ daytona_api_client_async/models/range.py
|
||||
daytona_api_client_async/models/registry_push_access_dto.py
|
||||
daytona_api_client_async/models/replace_request.py
|
||||
daytona_api_client_async/models/replace_result.py
|
||||
daytona_api_client_async/models/runner.py
|
||||
daytona_api_client_async/models/runner_region.py
|
||||
daytona_api_client_async/models/runner_state.py
|
||||
daytona_api_client_async/models/sandbox.py
|
||||
daytona_api_client_async/models/sandbox_class.py
|
||||
daytona_api_client_async/models/sandbox_info.py
|
||||
daytona_api_client_async/models/sandbox_labels.py
|
||||
daytona_api_client_async/models/sandbox_state.py
|
||||
|
||||
@@ -104,7 +104,11 @@ from daytona_api_client_async.models.range import Range
|
||||
from daytona_api_client_async.models.registry_push_access_dto import RegistryPushAccessDto
|
||||
from daytona_api_client_async.models.replace_request import ReplaceRequest
|
||||
from daytona_api_client_async.models.replace_result import ReplaceResult
|
||||
from daytona_api_client_async.models.runner import Runner
|
||||
from daytona_api_client_async.models.runner_region import RunnerRegion
|
||||
from daytona_api_client_async.models.runner_state import RunnerState
|
||||
from daytona_api_client_async.models.sandbox import Sandbox
|
||||
from daytona_api_client_async.models.sandbox_class import SandboxClass
|
||||
from daytona_api_client_async.models.sandbox_info import SandboxInfo
|
||||
from daytona_api_client_async.models.sandbox_labels import SandboxLabels
|
||||
from daytona_api_client_async.models.sandbox_state import SandboxState
|
||||
|
||||
@@ -22,6 +22,7 @@ from typing_extensions import Annotated
|
||||
|
||||
from pydantic import StrictStr
|
||||
from daytona_api_client_async.models.create_runner import CreateRunner
|
||||
from daytona_api_client_async.models.runner import Runner
|
||||
|
||||
from daytona_api_client_async.api_client import ApiClient, RequestSerialized
|
||||
from daytona_api_client_async.api_response import ApiResponse
|
||||
@@ -306,6 +307,265 @@ class RunnersApi:
|
||||
|
||||
|
||||
|
||||
@validate_call
|
||||
async def get_runner_by_sandbox_id(
|
||||
self,
|
||||
sandbox_id: StrictStr,
|
||||
_request_timeout: Union[
|
||||
None,
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Tuple[
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Annotated[StrictFloat, Field(gt=0)]
|
||||
]
|
||||
] = None,
|
||||
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
||||
_content_type: Optional[StrictStr] = None,
|
||||
_headers: Optional[Dict[StrictStr, Any]] = None,
|
||||
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
||||
) -> Runner:
|
||||
"""Get runner by sandbox ID
|
||||
|
||||
|
||||
:param sandbox_id: (required)
|
||||
:type sandbox_id: str
|
||||
:param _request_timeout: timeout setting for this request. If one
|
||||
number provided, it will be total request
|
||||
timeout. It can also be a pair (tuple) of
|
||||
(connection, read) timeouts.
|
||||
:type _request_timeout: int, tuple(int, int), optional
|
||||
:param _request_auth: set to override the auth_settings for an a single
|
||||
request; this effectively ignores the
|
||||
authentication in the spec for a single request.
|
||||
:type _request_auth: dict, optional
|
||||
:param _content_type: force content-type for the request.
|
||||
:type _content_type: str, Optional
|
||||
:param _headers: set to override the headers for a single
|
||||
request; this effectively ignores the headers
|
||||
in the spec for a single request.
|
||||
:type _headers: dict, optional
|
||||
:param _host_index: set to override the host_index for a single
|
||||
request; this effectively ignores the host_index
|
||||
in the spec for a single request.
|
||||
:type _host_index: int, optional
|
||||
:return: Returns the result object.
|
||||
""" # noqa: E501
|
||||
|
||||
_param = self._get_runner_by_sandbox_id_serialize(
|
||||
sandbox_id=sandbox_id,
|
||||
_request_auth=_request_auth,
|
||||
_content_type=_content_type,
|
||||
_headers=_headers,
|
||||
_host_index=_host_index
|
||||
)
|
||||
|
||||
_response_types_map: Dict[str, Optional[str]] = {
|
||||
'200': "Runner",
|
||||
}
|
||||
response_data = await self.api_client.call_api(
|
||||
*_param,
|
||||
_request_timeout=_request_timeout
|
||||
)
|
||||
await response_data.read()
|
||||
return self.api_client.response_deserialize(
|
||||
response_data=response_data,
|
||||
response_types_map=_response_types_map,
|
||||
).data
|
||||
|
||||
|
||||
@validate_call
|
||||
async def get_runner_by_sandbox_id_with_http_info(
|
||||
self,
|
||||
sandbox_id: StrictStr,
|
||||
_request_timeout: Union[
|
||||
None,
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Tuple[
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Annotated[StrictFloat, Field(gt=0)]
|
||||
]
|
||||
] = None,
|
||||
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
||||
_content_type: Optional[StrictStr] = None,
|
||||
_headers: Optional[Dict[StrictStr, Any]] = None,
|
||||
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
||||
) -> ApiResponse[Runner]:
|
||||
"""Get runner by sandbox ID
|
||||
|
||||
|
||||
:param sandbox_id: (required)
|
||||
:type sandbox_id: str
|
||||
:param _request_timeout: timeout setting for this request. If one
|
||||
number provided, it will be total request
|
||||
timeout. It can also be a pair (tuple) of
|
||||
(connection, read) timeouts.
|
||||
:type _request_timeout: int, tuple(int, int), optional
|
||||
:param _request_auth: set to override the auth_settings for an a single
|
||||
request; this effectively ignores the
|
||||
authentication in the spec for a single request.
|
||||
:type _request_auth: dict, optional
|
||||
:param _content_type: force content-type for the request.
|
||||
:type _content_type: str, Optional
|
||||
:param _headers: set to override the headers for a single
|
||||
request; this effectively ignores the headers
|
||||
in the spec for a single request.
|
||||
:type _headers: dict, optional
|
||||
:param _host_index: set to override the host_index for a single
|
||||
request; this effectively ignores the host_index
|
||||
in the spec for a single request.
|
||||
:type _host_index: int, optional
|
||||
:return: Returns the result object.
|
||||
""" # noqa: E501
|
||||
|
||||
_param = self._get_runner_by_sandbox_id_serialize(
|
||||
sandbox_id=sandbox_id,
|
||||
_request_auth=_request_auth,
|
||||
_content_type=_content_type,
|
||||
_headers=_headers,
|
||||
_host_index=_host_index
|
||||
)
|
||||
|
||||
_response_types_map: Dict[str, Optional[str]] = {
|
||||
'200': "Runner",
|
||||
}
|
||||
response_data = await self.api_client.call_api(
|
||||
*_param,
|
||||
_request_timeout=_request_timeout
|
||||
)
|
||||
await response_data.read()
|
||||
return self.api_client.response_deserialize(
|
||||
response_data=response_data,
|
||||
response_types_map=_response_types_map,
|
||||
)
|
||||
|
||||
|
||||
@validate_call
|
||||
async def get_runner_by_sandbox_id_without_preload_content(
|
||||
self,
|
||||
sandbox_id: StrictStr,
|
||||
_request_timeout: Union[
|
||||
None,
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Tuple[
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Annotated[StrictFloat, Field(gt=0)]
|
||||
]
|
||||
] = None,
|
||||
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
||||
_content_type: Optional[StrictStr] = None,
|
||||
_headers: Optional[Dict[StrictStr, Any]] = None,
|
||||
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
||||
) -> RESTResponseType:
|
||||
"""Get runner by sandbox ID
|
||||
|
||||
|
||||
:param sandbox_id: (required)
|
||||
:type sandbox_id: str
|
||||
:param _request_timeout: timeout setting for this request. If one
|
||||
number provided, it will be total request
|
||||
timeout. It can also be a pair (tuple) of
|
||||
(connection, read) timeouts.
|
||||
:type _request_timeout: int, tuple(int, int), optional
|
||||
:param _request_auth: set to override the auth_settings for an a single
|
||||
request; this effectively ignores the
|
||||
authentication in the spec for a single request.
|
||||
:type _request_auth: dict, optional
|
||||
:param _content_type: force content-type for the request.
|
||||
:type _content_type: str, Optional
|
||||
:param _headers: set to override the headers for a single
|
||||
request; this effectively ignores the headers
|
||||
in the spec for a single request.
|
||||
:type _headers: dict, optional
|
||||
:param _host_index: set to override the host_index for a single
|
||||
request; this effectively ignores the host_index
|
||||
in the spec for a single request.
|
||||
:type _host_index: int, optional
|
||||
:return: Returns the result object.
|
||||
""" # noqa: E501
|
||||
|
||||
_param = self._get_runner_by_sandbox_id_serialize(
|
||||
sandbox_id=sandbox_id,
|
||||
_request_auth=_request_auth,
|
||||
_content_type=_content_type,
|
||||
_headers=_headers,
|
||||
_host_index=_host_index
|
||||
)
|
||||
|
||||
_response_types_map: Dict[str, Optional[str]] = {
|
||||
'200': "Runner",
|
||||
}
|
||||
response_data = await self.api_client.call_api(
|
||||
*_param,
|
||||
_request_timeout=_request_timeout
|
||||
)
|
||||
return response_data.response
|
||||
|
||||
|
||||
def _get_runner_by_sandbox_id_serialize(
|
||||
self,
|
||||
sandbox_id,
|
||||
_request_auth,
|
||||
_content_type,
|
||||
_headers,
|
||||
_host_index,
|
||||
) -> RequestSerialized:
|
||||
|
||||
_host = None
|
||||
|
||||
_collection_formats: Dict[str, str] = {
|
||||
}
|
||||
|
||||
_path_params: Dict[str, str] = {}
|
||||
_query_params: List[Tuple[str, str]] = []
|
||||
_header_params: Dict[str, Optional[str]] = _headers or {}
|
||||
_form_params: List[Tuple[str, str]] = []
|
||||
_files: Dict[
|
||||
str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]
|
||||
] = {}
|
||||
_body_params: Optional[bytes] = None
|
||||
|
||||
# process the path parameters
|
||||
if sandbox_id is not None:
|
||||
_path_params['sandboxId'] = sandbox_id
|
||||
# process the query parameters
|
||||
# process the header parameters
|
||||
# process the form parameters
|
||||
# process the body parameter
|
||||
|
||||
|
||||
# set the HTTP header `Accept`
|
||||
if 'Accept' not in _header_params:
|
||||
_header_params['Accept'] = self.api_client.select_header_accept(
|
||||
[
|
||||
'application/json'
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# authentication setting
|
||||
_auth_settings: List[str] = [
|
||||
'bearer',
|
||||
'oauth2'
|
||||
]
|
||||
|
||||
return self.api_client.param_serialize(
|
||||
method='GET',
|
||||
resource_path='/runners/by-sandbox/{sandboxId}',
|
||||
path_params=_path_params,
|
||||
query_params=_query_params,
|
||||
header_params=_header_params,
|
||||
body=_body_params,
|
||||
post_params=_form_params,
|
||||
files=_files,
|
||||
auth_settings=_auth_settings,
|
||||
collection_formats=_collection_formats,
|
||||
_host=_host,
|
||||
_request_auth=_request_auth
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@validate_call
|
||||
async def list_runners(
|
||||
self,
|
||||
|
||||
@@ -76,7 +76,11 @@ from daytona_api_client_async.models.range import Range
|
||||
from daytona_api_client_async.models.registry_push_access_dto import RegistryPushAccessDto
|
||||
from daytona_api_client_async.models.replace_request import ReplaceRequest
|
||||
from daytona_api_client_async.models.replace_result import ReplaceResult
|
||||
from daytona_api_client_async.models.runner import Runner
|
||||
from daytona_api_client_async.models.runner_region import RunnerRegion
|
||||
from daytona_api_client_async.models.runner_state import RunnerState
|
||||
from daytona_api_client_async.models.sandbox import Sandbox
|
||||
from daytona_api_client_async.models.sandbox_class import SandboxClass
|
||||
from daytona_api_client_async.models.sandbox_info import SandboxInfo
|
||||
from daytona_api_client_async.models.sandbox_labels import SandboxLabels
|
||||
from daytona_api_client_async.models.sandbox_state import SandboxState
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional, Union
|
||||
from daytona_api_client_async.models.runner_region import RunnerRegion
|
||||
from daytona_api_client_async.models.runner_state import RunnerState
|
||||
from daytona_api_client_async.models.sandbox_class import SandboxClass
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class Runner(BaseModel):
|
||||
"""
|
||||
Runner
|
||||
""" # noqa: E501
|
||||
id: StrictStr = Field(description="The ID of the runner")
|
||||
domain: StrictStr = Field(description="The domain of the runner")
|
||||
api_url: StrictStr = Field(
|
||||
description="The API URL of the runner", alias="apiUrl")
|
||||
api_key: StrictStr = Field(
|
||||
description="The API key for the runner", alias="apiKey")
|
||||
cpu: Union[StrictFloat, StrictInt] = Field(
|
||||
description="The CPU capacity of the runner")
|
||||
memory: Union[StrictFloat, StrictInt] = Field(
|
||||
description="The memory capacity of the runner in GB")
|
||||
disk: Union[StrictFloat, StrictInt] = Field(
|
||||
description="The disk capacity of the runner in GB")
|
||||
gpu: Union[StrictFloat, StrictInt] = Field(
|
||||
description="The GPU capacity of the runner")
|
||||
gpu_type: StrictStr = Field(description="The type of GPU", alias="gpuType")
|
||||
var_class: SandboxClass = Field(
|
||||
description="The class of the runner", alias="class")
|
||||
used: Union[StrictFloat, StrictInt] = Field(
|
||||
description="The current usage of the runner")
|
||||
capacity: Union[StrictFloat, StrictInt] = Field(
|
||||
description="The capacity of the runner")
|
||||
region: RunnerRegion = Field(description="The region of the runner")
|
||||
state: RunnerState = Field(description="The state of the runner")
|
||||
last_checked: Optional[StrictStr] = Field(
|
||||
default=None, description="The last time the runner was checked", alias="lastChecked")
|
||||
unschedulable: StrictBool = Field(
|
||||
description="Whether the runner is unschedulable")
|
||||
created_at: StrictStr = Field(
|
||||
description="The creation timestamp of the runner", alias="createdAt")
|
||||
updated_at: StrictStr = Field(
|
||||
description="The last update timestamp of the runner", alias="updatedAt")
|
||||
additional_properties: Dict[str, Any] = {}
|
||||
__properties: ClassVar[List[str]] = ["id", "domain", "apiUrl", "apiKey", "cpu", "memory", "disk", "gpu", "gpuType",
|
||||
"class", "used", "capacity", "region", "state", "lastChecked", "unschedulable", "createdAt", "updatedAt"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of Runner from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
* Fields in `self.additional_properties` are added to the output dict.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
"additional_properties",
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# puts key-value pairs in additional_properties in the top level
|
||||
if self.additional_properties is not None:
|
||||
for _key, _value in self.additional_properties.items():
|
||||
_dict[_key] = _value
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of Runner from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"id": obj.get("id"),
|
||||
"domain": obj.get("domain"),
|
||||
"apiUrl": obj.get("apiUrl"),
|
||||
"apiKey": obj.get("apiKey"),
|
||||
"cpu": obj.get("cpu"),
|
||||
"memory": obj.get("memory"),
|
||||
"disk": obj.get("disk"),
|
||||
"gpu": obj.get("gpu"),
|
||||
"gpuType": obj.get("gpuType"),
|
||||
"class": obj.get("class"),
|
||||
"used": obj.get("used"),
|
||||
"capacity": obj.get("capacity"),
|
||||
"region": obj.get("region"),
|
||||
"state": obj.get("state"),
|
||||
"lastChecked": obj.get("lastChecked"),
|
||||
"unschedulable": obj.get("unschedulable"),
|
||||
"createdAt": obj.get("createdAt"),
|
||||
"updatedAt": obj.get("updatedAt")
|
||||
})
|
||||
# store additional fields in additional_properties
|
||||
for _key in obj.keys():
|
||||
if _key not in cls.__properties:
|
||||
_obj.additional_properties[_key] = obj.get(_key)
|
||||
|
||||
return _obj
|
||||
@@ -0,0 +1,40 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class RunnerRegion(str, Enum):
|
||||
"""
|
||||
The region of the runner
|
||||
"""
|
||||
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
EU = 'eu'
|
||||
US = 'us'
|
||||
ASIA = 'asia'
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
"""Create an instance of RunnerRegion from a JSON string"""
|
||||
return cls(json.loads(json_str))
|
||||
@@ -0,0 +1,41 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class RunnerState(str, Enum):
|
||||
"""
|
||||
The state of the runner
|
||||
"""
|
||||
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
INITIALIZING = 'initializing'
|
||||
READY = 'ready'
|
||||
DISABLED = 'disabled'
|
||||
DECOMMISSIONED = 'decommissioned'
|
||||
UNRESPONSIVE = 'unresponsive'
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
"""Create an instance of RunnerState from a JSON string"""
|
||||
return cls(json.loads(json_str))
|
||||
@@ -0,0 +1,39 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class SandboxClass(str, Enum):
|
||||
"""
|
||||
The class of the runner
|
||||
"""
|
||||
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
SMALL = 'small'
|
||||
MEDIUM = 'medium'
|
||||
LARGE = 'large'
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
"""Create an instance of SandboxClass from a JSON string"""
|
||||
return cls(json.loads(json_str))
|
||||
@@ -76,7 +76,11 @@ daytona_api_client/models/range.py
|
||||
daytona_api_client/models/registry_push_access_dto.py
|
||||
daytona_api_client/models/replace_request.py
|
||||
daytona_api_client/models/replace_result.py
|
||||
daytona_api_client/models/runner.py
|
||||
daytona_api_client/models/runner_region.py
|
||||
daytona_api_client/models/runner_state.py
|
||||
daytona_api_client/models/sandbox.py
|
||||
daytona_api_client/models/sandbox_class.py
|
||||
daytona_api_client/models/sandbox_info.py
|
||||
daytona_api_client/models/sandbox_labels.py
|
||||
daytona_api_client/models/sandbox_state.py
|
||||
|
||||
@@ -104,7 +104,11 @@ from daytona_api_client.models.range import Range
|
||||
from daytona_api_client.models.registry_push_access_dto import RegistryPushAccessDto
|
||||
from daytona_api_client.models.replace_request import ReplaceRequest
|
||||
from daytona_api_client.models.replace_result import ReplaceResult
|
||||
from daytona_api_client.models.runner import Runner
|
||||
from daytona_api_client.models.runner_region import RunnerRegion
|
||||
from daytona_api_client.models.runner_state import RunnerState
|
||||
from daytona_api_client.models.sandbox import Sandbox
|
||||
from daytona_api_client.models.sandbox_class import SandboxClass
|
||||
from daytona_api_client.models.sandbox_info import SandboxInfo
|
||||
from daytona_api_client.models.sandbox_labels import SandboxLabels
|
||||
from daytona_api_client.models.sandbox_state import SandboxState
|
||||
|
||||
@@ -22,6 +22,7 @@ from typing_extensions import Annotated
|
||||
|
||||
from pydantic import StrictStr
|
||||
from daytona_api_client.models.create_runner import CreateRunner
|
||||
from daytona_api_client.models.runner import Runner
|
||||
|
||||
from daytona_api_client.api_client import ApiClient, RequestSerialized
|
||||
from daytona_api_client.api_response import ApiResponse
|
||||
@@ -266,6 +267,228 @@ class RunnersApi:
|
||||
_request_auth=_request_auth,
|
||||
)
|
||||
|
||||
@validate_call
|
||||
def get_runner_by_sandbox_id(
|
||||
self,
|
||||
sandbox_id: StrictStr,
|
||||
_request_timeout: Union[
|
||||
None,
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
|
||||
] = None,
|
||||
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
||||
_content_type: Optional[StrictStr] = None,
|
||||
_headers: Optional[Dict[StrictStr, Any]] = None,
|
||||
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
||||
) -> Runner:
|
||||
"""Get runner by sandbox ID
|
||||
|
||||
|
||||
:param sandbox_id: (required)
|
||||
:type sandbox_id: str
|
||||
:param _request_timeout: timeout setting for this request. If one
|
||||
number provided, it will be total request
|
||||
timeout. It can also be a pair (tuple) of
|
||||
(connection, read) timeouts.
|
||||
:type _request_timeout: int, tuple(int, int), optional
|
||||
:param _request_auth: set to override the auth_settings for an a single
|
||||
request; this effectively ignores the
|
||||
authentication in the spec for a single request.
|
||||
:type _request_auth: dict, optional
|
||||
:param _content_type: force content-type for the request.
|
||||
:type _content_type: str, Optional
|
||||
:param _headers: set to override the headers for a single
|
||||
request; this effectively ignores the headers
|
||||
in the spec for a single request.
|
||||
:type _headers: dict, optional
|
||||
:param _host_index: set to override the host_index for a single
|
||||
request; this effectively ignores the host_index
|
||||
in the spec for a single request.
|
||||
:type _host_index: int, optional
|
||||
:return: Returns the result object.
|
||||
""" # noqa: E501
|
||||
|
||||
_param = self._get_runner_by_sandbox_id_serialize(
|
||||
sandbox_id=sandbox_id,
|
||||
_request_auth=_request_auth,
|
||||
_content_type=_content_type,
|
||||
_headers=_headers,
|
||||
_host_index=_host_index,
|
||||
)
|
||||
|
||||
_response_types_map: Dict[str, Optional[str]] = {
|
||||
"200": "Runner",
|
||||
}
|
||||
response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout)
|
||||
response_data.read()
|
||||
return self.api_client.response_deserialize(
|
||||
response_data=response_data,
|
||||
response_types_map=_response_types_map,
|
||||
).data
|
||||
|
||||
@validate_call
|
||||
def get_runner_by_sandbox_id_with_http_info(
|
||||
self,
|
||||
sandbox_id: StrictStr,
|
||||
_request_timeout: Union[
|
||||
None,
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
|
||||
] = None,
|
||||
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
||||
_content_type: Optional[StrictStr] = None,
|
||||
_headers: Optional[Dict[StrictStr, Any]] = None,
|
||||
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
||||
) -> ApiResponse[Runner]:
|
||||
"""Get runner by sandbox ID
|
||||
|
||||
|
||||
:param sandbox_id: (required)
|
||||
:type sandbox_id: str
|
||||
:param _request_timeout: timeout setting for this request. If one
|
||||
number provided, it will be total request
|
||||
timeout. It can also be a pair (tuple) of
|
||||
(connection, read) timeouts.
|
||||
:type _request_timeout: int, tuple(int, int), optional
|
||||
:param _request_auth: set to override the auth_settings for an a single
|
||||
request; this effectively ignores the
|
||||
authentication in the spec for a single request.
|
||||
:type _request_auth: dict, optional
|
||||
:param _content_type: force content-type for the request.
|
||||
:type _content_type: str, Optional
|
||||
:param _headers: set to override the headers for a single
|
||||
request; this effectively ignores the headers
|
||||
in the spec for a single request.
|
||||
:type _headers: dict, optional
|
||||
:param _host_index: set to override the host_index for a single
|
||||
request; this effectively ignores the host_index
|
||||
in the spec for a single request.
|
||||
:type _host_index: int, optional
|
||||
:return: Returns the result object.
|
||||
""" # noqa: E501
|
||||
|
||||
_param = self._get_runner_by_sandbox_id_serialize(
|
||||
sandbox_id=sandbox_id,
|
||||
_request_auth=_request_auth,
|
||||
_content_type=_content_type,
|
||||
_headers=_headers,
|
||||
_host_index=_host_index,
|
||||
)
|
||||
|
||||
_response_types_map: Dict[str, Optional[str]] = {
|
||||
"200": "Runner",
|
||||
}
|
||||
response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout)
|
||||
response_data.read()
|
||||
return self.api_client.response_deserialize(
|
||||
response_data=response_data,
|
||||
response_types_map=_response_types_map,
|
||||
)
|
||||
|
||||
@validate_call
|
||||
def get_runner_by_sandbox_id_without_preload_content(
|
||||
self,
|
||||
sandbox_id: StrictStr,
|
||||
_request_timeout: Union[
|
||||
None,
|
||||
Annotated[StrictFloat, Field(gt=0)],
|
||||
Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
|
||||
] = None,
|
||||
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
||||
_content_type: Optional[StrictStr] = None,
|
||||
_headers: Optional[Dict[StrictStr, Any]] = None,
|
||||
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
||||
) -> RESTResponseType:
|
||||
"""Get runner by sandbox ID
|
||||
|
||||
|
||||
:param sandbox_id: (required)
|
||||
:type sandbox_id: str
|
||||
:param _request_timeout: timeout setting for this request. If one
|
||||
number provided, it will be total request
|
||||
timeout. It can also be a pair (tuple) of
|
||||
(connection, read) timeouts.
|
||||
:type _request_timeout: int, tuple(int, int), optional
|
||||
:param _request_auth: set to override the auth_settings for an a single
|
||||
request; this effectively ignores the
|
||||
authentication in the spec for a single request.
|
||||
:type _request_auth: dict, optional
|
||||
:param _content_type: force content-type for the request.
|
||||
:type _content_type: str, Optional
|
||||
:param _headers: set to override the headers for a single
|
||||
request; this effectively ignores the headers
|
||||
in the spec for a single request.
|
||||
:type _headers: dict, optional
|
||||
:param _host_index: set to override the host_index for a single
|
||||
request; this effectively ignores the host_index
|
||||
in the spec for a single request.
|
||||
:type _host_index: int, optional
|
||||
:return: Returns the result object.
|
||||
""" # noqa: E501
|
||||
|
||||
_param = self._get_runner_by_sandbox_id_serialize(
|
||||
sandbox_id=sandbox_id,
|
||||
_request_auth=_request_auth,
|
||||
_content_type=_content_type,
|
||||
_headers=_headers,
|
||||
_host_index=_host_index,
|
||||
)
|
||||
|
||||
_response_types_map: Dict[str, Optional[str]] = {
|
||||
"200": "Runner",
|
||||
}
|
||||
response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout)
|
||||
return response_data.response
|
||||
|
||||
def _get_runner_by_sandbox_id_serialize(
|
||||
self,
|
||||
sandbox_id,
|
||||
_request_auth,
|
||||
_content_type,
|
||||
_headers,
|
||||
_host_index,
|
||||
) -> RequestSerialized:
|
||||
_host = None
|
||||
|
||||
_collection_formats: Dict[str, str] = {}
|
||||
|
||||
_path_params: Dict[str, str] = {}
|
||||
_query_params: List[Tuple[str, str]] = []
|
||||
_header_params: Dict[str, Optional[str]] = _headers or {}
|
||||
_form_params: List[Tuple[str, str]] = []
|
||||
_files: Dict[str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]] = {}
|
||||
_body_params: Optional[bytes] = None
|
||||
|
||||
# process the path parameters
|
||||
if sandbox_id is not None:
|
||||
_path_params["sandboxId"] = sandbox_id
|
||||
# process the query parameters
|
||||
# process the header parameters
|
||||
# process the form parameters
|
||||
# process the body parameter
|
||||
|
||||
# set the HTTP header `Accept`
|
||||
if "Accept" not in _header_params:
|
||||
_header_params["Accept"] = self.api_client.select_header_accept(["application/json"])
|
||||
|
||||
# authentication setting
|
||||
_auth_settings: List[str] = ["bearer", "oauth2"]
|
||||
|
||||
return self.api_client.param_serialize(
|
||||
method="GET",
|
||||
resource_path="/runners/by-sandbox/{sandboxId}",
|
||||
path_params=_path_params,
|
||||
query_params=_query_params,
|
||||
header_params=_header_params,
|
||||
body=_body_params,
|
||||
post_params=_form_params,
|
||||
files=_files,
|
||||
auth_settings=_auth_settings,
|
||||
collection_formats=_collection_formats,
|
||||
_host=_host,
|
||||
_request_auth=_request_auth,
|
||||
)
|
||||
|
||||
@validate_call
|
||||
def list_runners(
|
||||
self,
|
||||
|
||||
@@ -76,7 +76,11 @@ from daytona_api_client.models.range import Range
|
||||
from daytona_api_client.models.registry_push_access_dto import RegistryPushAccessDto
|
||||
from daytona_api_client.models.replace_request import ReplaceRequest
|
||||
from daytona_api_client.models.replace_result import ReplaceResult
|
||||
from daytona_api_client.models.runner import Runner
|
||||
from daytona_api_client.models.runner_region import RunnerRegion
|
||||
from daytona_api_client.models.runner_state import RunnerState
|
||||
from daytona_api_client.models.sandbox import Sandbox
|
||||
from daytona_api_client.models.sandbox_class import SandboxClass
|
||||
from daytona_api_client.models.sandbox_info import SandboxInfo
|
||||
from daytona_api_client.models.sandbox_labels import SandboxLabels
|
||||
from daytona_api_client.models.sandbox_state import SandboxState
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional, Union
|
||||
from daytona_api_client.models.runner_region import RunnerRegion
|
||||
from daytona_api_client.models.runner_state import RunnerState
|
||||
from daytona_api_client.models.sandbox_class import SandboxClass
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class Runner(BaseModel):
|
||||
"""
|
||||
Runner
|
||||
""" # noqa: E501
|
||||
|
||||
id: StrictStr = Field(description="The ID of the runner")
|
||||
domain: StrictStr = Field(description="The domain of the runner")
|
||||
api_url: StrictStr = Field(description="The API URL of the runner", alias="apiUrl")
|
||||
api_key: StrictStr = Field(description="The API key for the runner", alias="apiKey")
|
||||
cpu: Union[StrictFloat, StrictInt] = Field(description="The CPU capacity of the runner")
|
||||
memory: Union[StrictFloat, StrictInt] = Field(description="The memory capacity of the runner in GB")
|
||||
disk: Union[StrictFloat, StrictInt] = Field(description="The disk capacity of the runner in GB")
|
||||
gpu: Union[StrictFloat, StrictInt] = Field(description="The GPU capacity of the runner")
|
||||
gpu_type: StrictStr = Field(description="The type of GPU", alias="gpuType")
|
||||
var_class: SandboxClass = Field(description="The class of the runner", alias="class")
|
||||
used: Union[StrictFloat, StrictInt] = Field(description="The current usage of the runner")
|
||||
capacity: Union[StrictFloat, StrictInt] = Field(description="The capacity of the runner")
|
||||
region: RunnerRegion = Field(description="The region of the runner")
|
||||
state: RunnerState = Field(description="The state of the runner")
|
||||
last_checked: Optional[StrictStr] = Field(
|
||||
default=None, description="The last time the runner was checked", alias="lastChecked"
|
||||
)
|
||||
unschedulable: StrictBool = Field(description="Whether the runner is unschedulable")
|
||||
created_at: StrictStr = Field(description="The creation timestamp of the runner", alias="createdAt")
|
||||
updated_at: StrictStr = Field(description="The last update timestamp of the runner", alias="updatedAt")
|
||||
additional_properties: Dict[str, Any] = {}
|
||||
__properties: ClassVar[List[str]] = [
|
||||
"id",
|
||||
"domain",
|
||||
"apiUrl",
|
||||
"apiKey",
|
||||
"cpu",
|
||||
"memory",
|
||||
"disk",
|
||||
"gpu",
|
||||
"gpuType",
|
||||
"class",
|
||||
"used",
|
||||
"capacity",
|
||||
"region",
|
||||
"state",
|
||||
"lastChecked",
|
||||
"unschedulable",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of Runner from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
* Fields in `self.additional_properties` are added to the output dict.
|
||||
"""
|
||||
excluded_fields: Set[str] = set(
|
||||
[
|
||||
"additional_properties",
|
||||
]
|
||||
)
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# puts key-value pairs in additional_properties in the top level
|
||||
if self.additional_properties is not None:
|
||||
for _key, _value in self.additional_properties.items():
|
||||
_dict[_key] = _value
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of Runner from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate(
|
||||
{
|
||||
"id": obj.get("id"),
|
||||
"domain": obj.get("domain"),
|
||||
"apiUrl": obj.get("apiUrl"),
|
||||
"apiKey": obj.get("apiKey"),
|
||||
"cpu": obj.get("cpu"),
|
||||
"memory": obj.get("memory"),
|
||||
"disk": obj.get("disk"),
|
||||
"gpu": obj.get("gpu"),
|
||||
"gpuType": obj.get("gpuType"),
|
||||
"class": obj.get("class"),
|
||||
"used": obj.get("used"),
|
||||
"capacity": obj.get("capacity"),
|
||||
"region": obj.get("region"),
|
||||
"state": obj.get("state"),
|
||||
"lastChecked": obj.get("lastChecked"),
|
||||
"unschedulable": obj.get("unschedulable"),
|
||||
"createdAt": obj.get("createdAt"),
|
||||
"updatedAt": obj.get("updatedAt"),
|
||||
}
|
||||
)
|
||||
# store additional fields in additional_properties
|
||||
for _key in obj.keys():
|
||||
if _key not in cls.__properties:
|
||||
_obj.additional_properties[_key] = obj.get(_key)
|
||||
|
||||
return _obj
|
||||
@@ -0,0 +1,39 @@
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class RunnerRegion(str, Enum):
|
||||
"""
|
||||
The region of the runner
|
||||
"""
|
||||
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
EU = "eu"
|
||||
US = "us"
|
||||
ASIA = "asia"
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
"""Create an instance of RunnerRegion from a JSON string"""
|
||||
return cls(json.loads(json_str))
|
||||
@@ -0,0 +1,41 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class RunnerState(str, Enum):
|
||||
"""
|
||||
The state of the runner
|
||||
"""
|
||||
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
INITIALIZING = "initializing"
|
||||
READY = "ready"
|
||||
DISABLED = "disabled"
|
||||
DECOMMISSIONED = "decommissioned"
|
||||
UNRESPONSIVE = "unresponsive"
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
"""Create an instance of RunnerState from a JSON string"""
|
||||
return cls(json.loads(json_str))
|
||||
@@ -0,0 +1,39 @@
|
||||
# coding: utf-8
|
||||
# Copyright 2025 Daytona Platforms Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Daytona
|
||||
|
||||
Daytona AI platform API Docs
|
||||
|
||||
The version of the OpenAPI document: 1.0
|
||||
Contact: support@daytona.com
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class SandboxClass(str, Enum):
|
||||
"""
|
||||
The class of the runner
|
||||
"""
|
||||
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
SMALL = "small"
|
||||
MEDIUM = "medium"
|
||||
LARGE = "large"
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
"""Create an instance of SandboxClass from a JSON string"""
|
||||
return cls(json.loads(json_str))
|
||||
@@ -77,6 +77,10 @@ models/range.ts
|
||||
models/registry-push-access-dto.ts
|
||||
models/replace-request.ts
|
||||
models/replace-result.ts
|
||||
models/runner-region.ts
|
||||
models/runner-state.ts
|
||||
models/runner.ts
|
||||
models/sandbox-class.ts
|
||||
models/sandbox-info.ts
|
||||
models/sandbox-labels.ts
|
||||
models/sandbox-state.ts
|
||||
|
||||
@@ -38,6 +38,8 @@ import {
|
||||
import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'
|
||||
// @ts-ignore
|
||||
import type { CreateRunner } from '../models'
|
||||
// @ts-ignore
|
||||
import type { Runner } from '../models'
|
||||
/**
|
||||
* RunnersApi - axios parameter creator
|
||||
* @export
|
||||
@@ -84,6 +86,46 @@ export const RunnersApiAxiosParamCreator = function (configuration?: Configurati
|
||||
options: localVarRequestOptions,
|
||||
}
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Get runner by sandbox ID
|
||||
* @param {string} sandboxId
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getRunnerBySandboxId: async (sandboxId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'sandboxId' is not null or undefined
|
||||
assertParamExists('getRunnerBySandboxId', 'sandboxId', sandboxId)
|
||||
const localVarPath = `/runners/by-sandbox/{sandboxId}`.replace(
|
||||
`{${'sandboxId'}}`,
|
||||
encodeURIComponent(String(sandboxId)),
|
||||
)
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL)
|
||||
let baseOptions
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options }
|
||||
const localVarHeaderParameter = {} as any
|
||||
const localVarQueryParameter = {} as any
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
// authentication oauth2 required
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter)
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}
|
||||
localVarRequestOptions.headers = { ...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers }
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
}
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary List all runners
|
||||
@@ -188,6 +230,29 @@ export const RunnersApiFp = function (configuration?: Configuration) {
|
||||
configuration,
|
||||
)(axios, localVarOperationServerBasePath || basePath)
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Get runner by sandbox ID
|
||||
* @param {string} sandboxId
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getRunnerBySandboxId(
|
||||
sandboxId: string,
|
||||
options?: RawAxiosRequestConfig,
|
||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Runner>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getRunnerBySandboxId(sandboxId, options)
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0
|
||||
const localVarOperationServerBasePath =
|
||||
operationServerMap['RunnersApi.getRunnerBySandboxId']?.[localVarOperationServerIndex]?.url
|
||||
return (axios, basePath) =>
|
||||
createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration,
|
||||
)(axios, localVarOperationServerBasePath || basePath)
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary List all runners
|
||||
@@ -252,6 +317,16 @@ export const RunnersApiFactory = function (configuration?: Configuration, basePa
|
||||
createRunner(createRunner: CreateRunner, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||
return localVarFp.createRunner(createRunner, options).then((request) => request(axios, basePath))
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Get runner by sandbox ID
|
||||
* @param {string} sandboxId
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getRunnerBySandboxId(sandboxId: string, options?: RawAxiosRequestConfig): AxiosPromise<Runner> {
|
||||
return localVarFp.getRunnerBySandboxId(sandboxId, options).then((request) => request(axios, basePath))
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary List all runners
|
||||
@@ -295,6 +370,20 @@ export class RunnersApi extends BaseAPI {
|
||||
.then((request) => request(this.axios, this.basePath))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Get runner by sandbox ID
|
||||
* @param {string} sandboxId
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof RunnersApi
|
||||
*/
|
||||
public getRunnerBySandboxId(sandboxId: string, options?: RawAxiosRequestConfig) {
|
||||
return RunnersApiFp(this.configuration)
|
||||
.getRunnerBySandboxId(sandboxId, options)
|
||||
.then((request) => request(this.axios, this.basePath))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary List all runners
|
||||
|
||||
@@ -61,7 +61,11 @@ export * from './range'
|
||||
export * from './registry-push-access-dto'
|
||||
export * from './replace-request'
|
||||
export * from './replace-result'
|
||||
export * from './runner'
|
||||
export * from './runner-region'
|
||||
export * from './runner-state'
|
||||
export * from './sandbox'
|
||||
export * from './sandbox-class'
|
||||
export * from './sandbox-info'
|
||||
export * from './sandbox-labels'
|
||||
export * from './sandbox-state'
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
|
||||
/**
|
||||
* Daytona
|
||||
* Daytona AI platform API Docs
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
* Contact: support@daytona.com
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The region of the runner
|
||||
* @export
|
||||
* @enum {string}
|
||||
*/
|
||||
|
||||
export const RunnerRegion = {
|
||||
EU: 'eu',
|
||||
US: 'us',
|
||||
ASIA: 'asia',
|
||||
} as const
|
||||
|
||||
export type RunnerRegion = (typeof RunnerRegion)[keyof typeof RunnerRegion]
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
|
||||
/**
|
||||
* Daytona
|
||||
* Daytona AI platform API Docs
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
* Contact: support@daytona.com
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The state of the runner
|
||||
* @export
|
||||
* @enum {string}
|
||||
*/
|
||||
|
||||
export const RunnerState = {
|
||||
INITIALIZING: 'initializing',
|
||||
READY: 'ready',
|
||||
DISABLED: 'disabled',
|
||||
DECOMMISSIONED: 'decommissioned',
|
||||
UNRESPONSIVE: 'unresponsive',
|
||||
} as const
|
||||
|
||||
export type RunnerState = (typeof RunnerState)[keyof typeof RunnerState]
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Daytona
|
||||
* Daytona AI platform API Docs
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
* Contact: support@daytona.com
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { RunnerRegion } from './runner-region'
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { RunnerState } from './runner-state'
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { SandboxClass } from './sandbox-class'
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface Runner
|
||||
*/
|
||||
export interface Runner {
|
||||
/**
|
||||
* The ID of the runner
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* The domain of the runner
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
domain: string
|
||||
/**
|
||||
* The API URL of the runner
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
apiUrl: string
|
||||
/**
|
||||
* The API key for the runner
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
apiKey: string
|
||||
/**
|
||||
* The CPU capacity of the runner
|
||||
* @type {number}
|
||||
* @memberof Runner
|
||||
*/
|
||||
cpu: number
|
||||
/**
|
||||
* The memory capacity of the runner in GB
|
||||
* @type {number}
|
||||
* @memberof Runner
|
||||
*/
|
||||
memory: number
|
||||
/**
|
||||
* The disk capacity of the runner in GB
|
||||
* @type {number}
|
||||
* @memberof Runner
|
||||
*/
|
||||
disk: number
|
||||
/**
|
||||
* The GPU capacity of the runner
|
||||
* @type {number}
|
||||
* @memberof Runner
|
||||
*/
|
||||
gpu: number
|
||||
/**
|
||||
* The type of GPU
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
gpuType: string
|
||||
/**
|
||||
* The class of the runner
|
||||
* @type {SandboxClass}
|
||||
* @memberof Runner
|
||||
*/
|
||||
class: SandboxClass
|
||||
/**
|
||||
* The current usage of the runner
|
||||
* @type {number}
|
||||
* @memberof Runner
|
||||
*/
|
||||
used: number
|
||||
/**
|
||||
* The capacity of the runner
|
||||
* @type {number}
|
||||
* @memberof Runner
|
||||
*/
|
||||
capacity: number
|
||||
/**
|
||||
* The region of the runner
|
||||
* @type {RunnerRegion}
|
||||
* @memberof Runner
|
||||
*/
|
||||
region: RunnerRegion
|
||||
/**
|
||||
* The state of the runner
|
||||
* @type {RunnerState}
|
||||
* @memberof Runner
|
||||
*/
|
||||
state: RunnerState
|
||||
/**
|
||||
* The last time the runner was checked
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
lastChecked?: string
|
||||
/**
|
||||
* Whether the runner is unschedulable
|
||||
* @type {boolean}
|
||||
* @memberof Runner
|
||||
*/
|
||||
unschedulable: boolean
|
||||
/**
|
||||
* The creation timestamp of the runner
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
createdAt: string
|
||||
/**
|
||||
* The last update timestamp of the runner
|
||||
* @type {string}
|
||||
* @memberof Runner
|
||||
*/
|
||||
updatedAt: string
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 Daytona Platforms Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
|
||||
/**
|
||||
* Daytona
|
||||
* Daytona AI platform API Docs
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0
|
||||
* Contact: support@daytona.com
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The class of the runner
|
||||
* @export
|
||||
* @enum {string}
|
||||
*/
|
||||
|
||||
export const SandboxClass = {
|
||||
SMALL: 'small',
|
||||
MEDIUM: 'medium',
|
||||
LARGE: 'large',
|
||||
} as const
|
||||
|
||||
export type SandboxClass = (typeof SandboxClass)[keyof typeof SandboxClass]
|
||||
@@ -0,0 +1,45 @@
|
||||
module github.com/daytonaio/common-go
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.12.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.24.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.12.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/protobuf v1.36.3 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,103 @@
|
||||
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
|
||||
github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
|
||||
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
|
||||
github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
|
||||
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrorResponse represents the error response structure
|
||||
//
|
||||
// @Description Error response
|
||||
// @Schema ErrorResponse
|
||||
type ErrorResponse struct {
|
||||
StatusCode int `json:"statusCode" example:"400" binding:"required"`
|
||||
Message string `json:"message" example:"Bad request" binding:"required"`
|
||||
Code string `json:"code" example:"BAD_REQUEST" binding:"required"`
|
||||
Timestamp time.Time `json:"timestamp" example:"2023-01-01T12:00:00Z" binding:"required"`
|
||||
Path string `json:"path" example:"/api/resource" binding:"required"`
|
||||
Method string `json:"method" example:"GET" binding:"required"`
|
||||
} // @name ErrorResponse
|
||||
|
||||
type CustomError struct {
|
||||
StatusCode int
|
||||
Message string
|
||||
Code string
|
||||
}
|
||||
|
||||
func (e *CustomError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewCustomError(statusCode int, message, code string) error {
|
||||
return &CustomError{
|
||||
StatusCode: statusCode,
|
||||
Message: message,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
type NotFoundError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func NewNotFoundError(err error) error {
|
||||
return &NotFoundError{
|
||||
Message: fmt.Sprintf("not found: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *NotFoundError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func IsNotFoundError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "not found")
|
||||
}
|
||||
|
||||
type InvalidBodyRequestError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *InvalidBodyRequestError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewInvalidBodyRequestError(err error) error {
|
||||
return &InvalidBodyRequestError{
|
||||
Message: fmt.Sprintf("invalid body request: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
func IsInvalidBodyRequestError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "invalid body request")
|
||||
}
|
||||
|
||||
type UnauthorizedError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *UnauthorizedError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewUnauthorizedError(err error) error {
|
||||
return &UnauthorizedError{
|
||||
Message: fmt.Sprintf("unauthorized: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
func IsUnauthorizedError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "unauthorized")
|
||||
}
|
||||
|
||||
type ConflictError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ConflictError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewConflictError(err error) error {
|
||||
return &ConflictError{
|
||||
Message: fmt.Sprintf("conflict: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
func IsConflictError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "conflict")
|
||||
}
|
||||
|
||||
type BadRequestError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *BadRequestError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewBadRequestError(err error) error {
|
||||
return &BadRequestError{
|
||||
Message: fmt.Sprintf("bad request: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
func IsBadRequestError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "bad request")
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func NewErrorMiddleware(defaultErrorHandler func(ctx *gin.Context, err error) ErrorResponse) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
ctx.Next()
|
||||
|
||||
errs := ctx.Errors
|
||||
if len(errs) > 0 {
|
||||
var errorResponse ErrorResponse
|
||||
err := errs.Last()
|
||||
|
||||
switch e := err.Err.(type) {
|
||||
case *CustomError:
|
||||
errorResponse = ErrorResponse{
|
||||
StatusCode: e.StatusCode,
|
||||
Message: e.Message,
|
||||
Code: e.Code,
|
||||
Timestamp: time.Now(),
|
||||
Path: ctx.Request.URL.Path,
|
||||
Method: ctx.Request.Method,
|
||||
}
|
||||
case *NotFoundError:
|
||||
errorResponse = ErrorResponse{
|
||||
StatusCode: http.StatusNotFound,
|
||||
Message: err.Err.Error(),
|
||||
Code: "NOT_FOUND",
|
||||
Timestamp: time.Now(),
|
||||
Path: ctx.Request.URL.Path,
|
||||
Method: ctx.Request.Method,
|
||||
}
|
||||
case *UnauthorizedError:
|
||||
errorResponse = ErrorResponse{
|
||||
StatusCode: http.StatusUnauthorized,
|
||||
Message: err.Err.Error(),
|
||||
Code: "UNAUTHORIZED",
|
||||
Timestamp: time.Now(),
|
||||
Path: ctx.Request.URL.Path,
|
||||
Method: ctx.Request.Method,
|
||||
}
|
||||
case *InvalidBodyRequestError:
|
||||
errorResponse = ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: err.Err.Error(),
|
||||
Code: "INVALID_REQUEST_BODY",
|
||||
Timestamp: time.Now(),
|
||||
Path: ctx.Request.URL.Path,
|
||||
Method: ctx.Request.Method,
|
||||
}
|
||||
case *ConflictError:
|
||||
errorResponse = ErrorResponse{
|
||||
StatusCode: http.StatusConflict,
|
||||
Message: err.Err.Error(),
|
||||
Code: "CONFLICT",
|
||||
Timestamp: time.Now(),
|
||||
Path: ctx.Request.URL.Path,
|
||||
Method: ctx.Request.Method,
|
||||
}
|
||||
case *BadRequestError:
|
||||
errorResponse = ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: ExtractErrorPart(err.Err.Error()),
|
||||
Code: "BAD_REQUEST",
|
||||
Timestamp: time.Now(),
|
||||
Path: ctx.Request.URL.Path,
|
||||
Method: ctx.Request.Method,
|
||||
}
|
||||
default:
|
||||
errorResponse = defaultErrorHandler(ctx, err)
|
||||
}
|
||||
|
||||
if errorResponse.StatusCode == http.StatusInternalServerError {
|
||||
log.WithError(err).WithFields(log.Fields{
|
||||
"path": ctx.Request.URL.Path,
|
||||
"method": ctx.Request.Method,
|
||||
}).Error("Internal Server Error")
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"method": ctx.Request.Method,
|
||||
"URI": ctx.Request.URL.Path,
|
||||
"status": errorResponse.StatusCode,
|
||||
"error": errorResponse.Message,
|
||||
}).Error("API ERROR")
|
||||
}
|
||||
|
||||
// Set explicit content type header
|
||||
ctx.Header("Content-Type", "application/json")
|
||||
ctx.JSON(errorResponse.StatusCode, errorResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExtractErrorPart(errorMsg string) string {
|
||||
r := regexp.MustCompile(`(unable to find user [^:]+)`)
|
||||
|
||||
matches := r.FindStringSubmatch(errorMsg)
|
||||
|
||||
if len(matches) < 2 {
|
||||
return errorMsg
|
||||
}
|
||||
|
||||
return fmt.Sprintf("bad request: %s", matches[1])
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2025 Daytona Platforms Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
common_errors "github.com/daytonaio/common-go/pkg/errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var proxyTransport = &http.Transport{
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
DialContext: (&net.Dialer{
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext,
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
// Custom HTTP client that follows redirects while maintaining original headers
|
||||
var proxyClient = &http.Client{
|
||||
Transport: proxyTransport,
|
||||
// Create a custom redirect policy
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
// Copy headers from original request
|
||||
if len(via) > 0 {
|
||||
// Copy the headers from the original request
|
||||
for key, values := range via[0].Header {
|
||||
// Skip certain headers that shouldn't be copied
|
||||
if key != "Cookie" {
|
||||
for _, value := range values {
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limit the number of redirects to prevent infinite loops
|
||||
if len(via) >= 10 {
|
||||
return errors.New("stopped after 10 redirects")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// ProxyRequest handles proxying requests to a sandbox's container
|
||||
//
|
||||
// @Tags toolbox
|
||||
// @Summary Proxy requests to the sandbox toolbox
|
||||
// @Description Forwards the request to the specified sandbox's container
|
||||
// @Param workspaceId path string true "Sandbox ID"
|
||||
// @Param projectId path string true "Project ID"
|
||||
// @Param path path string true "Path to forward"
|
||||
// @Success 200 {object} string "Proxied response"
|
||||
// @Failure 400 {object} string "Bad request"
|
||||
// @Failure 401 {object} string "Unauthorized"
|
||||
// @Failure 404 {object} string "Sandbox container not found"
|
||||
// @Failure 409 {object} string "Sandbox container conflict"
|
||||
// @Failure 500 {object} string "Internal server error"
|
||||
// @Router /workspaces/{workspaceId}/{projectId}/toolbox/{path} [get]
|
||||
func NewProxyRequestHandler(getProxyTarget func(*gin.Context) (*url.URL, string, map[string]string, error)) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
target, fullTargetURL, extraHeaders, err := getProxyTarget(ctx)
|
||||
if err != nil {
|
||||
// Error already sent to the context
|
||||
return
|
||||
}
|
||||
|
||||
// Create a new outgoing request
|
||||
outReq, err := http.NewRequestWithContext(
|
||||
ctx.Request.Context(),
|
||||
ctx.Request.Method,
|
||||
fullTargetURL,
|
||||
ctx.Request.Body,
|
||||
)
|
||||
if err != nil {
|
||||
ctx.Error(common_errors.NewBadRequestError(fmt.Errorf("failed to create outgoing request: %w", err)))
|
||||
return
|
||||
}
|
||||
|
||||
// Copy headers from original request
|
||||
for key, values := range ctx.Request.Header {
|
||||
// Skip the Connection header
|
||||
if key != "Connection" {
|
||||
for _, value := range values {
|
||||
outReq.Header.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Host header to the target
|
||||
outReq.Host = target.Host
|
||||
outReq.Header.Set("Connection", "keep-alive")
|
||||
|
||||
for key, value := range extraHeaders {
|
||||
outReq.Header.Add(key, value)
|
||||
}
|
||||
|
||||
if ctx.Request.Header.Get("Upgrade") == "websocket" {
|
||||
ws, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
reqExtraHeaders := http.Header{}
|
||||
for key, value := range extraHeaders {
|
||||
reqExtraHeaders.Add(key, value)
|
||||
}
|
||||
|
||||
conn, _, err := websocket.DefaultDialer.DialContext(ctx.Request.Context(), strings.Replace(fullTargetURL, "http", "ws", 1), reqExtraHeaders)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
go func() {
|
||||
io.Copy(ws.NetConn(), conn.NetConn())
|
||||
}()
|
||||
|
||||
io.Copy(conn.NetConn(), ws.NetConn())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Execute the request with our custom client that handles redirects
|
||||
resp, err := proxyClient.Do(outReq)
|
||||
if err != nil {
|
||||
ctx.Error(fmt.Errorf("proxy request failed: %w", err))
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Copy response headers
|
||||
for key, values := range resp.Header {
|
||||
for _, value := range values {
|
||||
ctx.Writer.Header().Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Set the status code
|
||||
ctx.Writer.WriteHeader(resp.StatusCode)
|
||||
|
||||
// Copy the response body
|
||||
if _, err := io.Copy(ctx.Writer, resp.Body); err != nil {
|
||||
log.Errorf("Error copying response body: %v", err)
|
||||
// Error already sent to client, just log here
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
"build:production": "nx run-many --target=build --all --parallel=$(getconf _NPROCESSORS_ONLN) --configuration=production",
|
||||
"serve": "nx run-many --target=serve --all --exclude=daemon --parallel=$(getconf _NPROCESSORS_ONLN) --configuration=development",
|
||||
"serve:skip-runner": "nx run-many --target=serve --all --exclude=runner,daemon --parallel=$(getconf _NPROCESSORS_ONLN) --configuration=development",
|
||||
"serve:skip-proxy": "nx run-many --target=serve --all --exclude=proxy,daemon --parallel=$(getconf _NPROCESSORS_ONLN) --configuration=development",
|
||||
"serve:production": "nx run-many --target=serve --all --exclude=daemon --parallel=$(getconf _NPROCESSORS_ONLN) --configuration=production",
|
||||
"generate:openapi": "nx run-many --target=openapi --all",
|
||||
"generate:api-client": "yarn generate:openapi && nx run-many --target=generate:api-client --all",
|
||||
|
||||
Reference in New Issue
Block a user