Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
6cd6e94170 | |||
ca10608d64 | |||
71724fd1bf | |||
8a22bb3cb5 | |||
72c89f2e43 |
@ -4,7 +4,8 @@
|
||||
# resource
|
||||
resource/deploy
|
||||
resource/frontend
|
||||
resource/runner/.mark.image
|
||||
resource/runner/problem/*
|
||||
resource/runner/tmp/*
|
||||
resource/runner/user/*
|
||||
resource/runner/framework/rootfs/*
|
||||
|
||||
|
48
.github/workflows/container.yml
vendored
48
.github/workflows/container.yml
vendored
@ -1,48 +0,0 @@
|
||||
name: Build Container Image
|
||||
on: [ push ]
|
||||
jobs:
|
||||
image:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER: podman
|
||||
IMAGE_PREFIX: quay.io/ldcraft
|
||||
steps:
|
||||
- name: Maximize Build Space
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /opt/hostedtoolcache/CodeQL
|
||||
sudo df -h
|
||||
- uses: actions/checkout@v4
|
||||
# reference: https://github.com/containers/podman/discussions/17868
|
||||
- name: Tar as root
|
||||
run: |
|
||||
sudo mv -fv /usr/bin/tar /usr/bin/tar.orig
|
||||
echo -e '#!/bin/sh\n\nsudo /usr/bin/tar.orig "$@"' | sudo tee -a /usr/bin/tar
|
||||
sudo chmod +x /usr/bin/tar
|
||||
- name: Cache Podman
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.local/share/containers
|
||||
~/.config/containers
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/*.Dockerfile', 'build_image.sh', 'docker-entrypoint.sh', 'VERSION') }}
|
||||
- name: Login to Container Registry
|
||||
uses: redhat-actions/podman-login@v1
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.CONTAINER_USERNAME }}
|
||||
password: ${{ secrets.CONTAINER_PASSWORD }}
|
||||
- name: Write Sentry DSN
|
||||
run: echo -n "$SENTRY_DSN" > dsn.txt
|
||||
env:
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
- name: Build Rootfs Image
|
||||
run: ./build_image.sh rootfs
|
||||
- name: Build Base Image
|
||||
run: ./build_image.sh base
|
||||
- name: Build Server Image
|
||||
run: ./build_image.sh server
|
||||
- name: Build Runner Image
|
||||
run: ./build_image.sh runner
|
2
.idea/.gitignore
vendored
2
.idea/.gitignore
vendored
@ -6,5 +6,3 @@
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# GitHub Copilot persisted chat sessions
|
||||
/copilot/chatSessions
|
||||
|
@ -6,8 +6,6 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/resource/frontend" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/resource/runner/tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/resource/runner/user" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/resource/runner/framework/rootfs/full" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/resource/runner/framework/rootfs/run" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
@ -1,16 +0,0 @@
|
||||
# builder
|
||||
FROM docker.io/library/golang:alpine
|
||||
|
||||
#ENV GOPROXY=https://goproxy.cn
|
||||
ENV CGO_ENABLED=0
|
||||
WORKDIR /builder
|
||||
|
||||
RUN apk add --no-cache git make
|
||||
RUN go install github.com/swaggo/swag/cmd/swag@latest
|
||||
|
||||
COPY go.mod /builder/go.mod
|
||||
COPY go.sum /builder/go.sum
|
||||
RUN go mod download
|
||||
|
||||
COPY . /builder
|
||||
RUN make build
|
7
Makefile
7
Makefile
@ -11,8 +11,7 @@ LDFLAGS += -X $(PKG_BASE)/cmd.GitCommit=$(GIT_COMMIT)
|
||||
LDFLAGS += -X $(PKG_BASE)/cmd.SentryDSN=$(shell cat dsn.txt)
|
||||
LDFLAGS += -s -w
|
||||
|
||||
GOBUILD := $(GO) build
|
||||
GOFLAGS := -ldflags '$(LDFLAGS)'
|
||||
GOBUILD := $(GO) build -ldflags '$(LDFLAGS)'
|
||||
GOBIN := $(shell go env GOPATH)/bin
|
||||
|
||||
.PHONY: all build clean dep swagger fmt coverage test
|
||||
@ -22,10 +21,10 @@ default: all
|
||||
all: clean build
|
||||
|
||||
build: swagger dep
|
||||
$(GOBUILD) $(GOFLAGS) -o woj ./cmd/woj
|
||||
$(GOBUILD) -o woj ./cmd/woj
|
||||
|
||||
clean:
|
||||
rm -f woj coverage.out coverage.html
|
||||
rm -f woj
|
||||
|
||||
dep:
|
||||
go mod download
|
||||
|
@ -1,38 +1,33 @@
|
||||
ARG IMAGE_PREFIX=git.0x7f.app/woj
|
||||
ARG VERSION=latest
|
||||
# builder
|
||||
FROM docker.io/library/golang:alpine AS builder
|
||||
|
||||
# Base image
|
||||
FROM ${IMAGE_PREFIX}/woj-server-base:${VERSION} AS base
|
||||
#ENV GOPROXY=https://goproxy.cn
|
||||
ENV CGO_ENABLED=0
|
||||
WORKDIR /builder
|
||||
|
||||
# Rootfs: debian-full
|
||||
FROM ${IMAGE_PREFIX}/debian-full:${VERSION} AS rootfs-full
|
||||
RUN apk add --no-cache git make
|
||||
RUN --mount=type=cache,id=golang,target=/go/pkg go install github.com/swaggo/swag/cmd/swag@latest
|
||||
|
||||
# Rootfs: debian-full
|
||||
FROM ${IMAGE_PREFIX}/debian-run:${VERSION} AS rootfs-run
|
||||
COPY go.mod /builder/go.mod
|
||||
COPY go.sum /builder/go.sum
|
||||
RUN --mount=type=cache,id=golang,target=/go/pkg go mod download
|
||||
|
||||
# Main image
|
||||
FROM docker.io/library/debian:bookworm-slim
|
||||
COPY . /builder
|
||||
RUN --mount=type=cache,id=golang,target=/go/pkg make build
|
||||
|
||||
|
||||
# main image
|
||||
FROM docker.io/library/alpine
|
||||
|
||||
WORKDIR /app
|
||||
RUN apt-get update && apt-get upgrade -y \
|
||||
&& apt-get install -y ca-certificates gosu libnl-route-3-200 libprotobuf32 tini \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# rootfs
|
||||
COPY --from=rootfs-full / /app/resource/runner/framework/rootfs/full
|
||||
COPY --from=rootfs-run / /app/resource/runner/framework/rootfs/run
|
||||
|
||||
# nsjail
|
||||
COPY --from=rootfs-full /woj/framework/scripts/nsjail /app/resource/runner/framework/scripts/nsjail
|
||||
RUN apk --no-cache add tzdata ca-certificates bash tini \
|
||||
containerd nerdctl
|
||||
|
||||
# sources
|
||||
COPY --from=base /builder/resource/runner /app/resource/runner
|
||||
COPY --from=base /builder/config.docker.yaml /app
|
||||
COPY --from=base /builder/docker-entrypoint.sh /app
|
||||
COPY --from=base /builder/woj /app
|
||||
COPY --from=builder /builder/resource/runner /app/resource/runner
|
||||
COPY --from=builder /builder/config.docker.yaml /app
|
||||
COPY --from=builder /builder/docker-entrypoint.sh /app
|
||||
COPY --from=builder /builder/woj /app
|
||||
|
||||
# tell entrypoint to setup runner env
|
||||
ENV RUNNER_IMAGE=1
|
||||
|
||||
# reap zombies
|
||||
ENTRYPOINT ["/usr/bin/tini", "/app/docker-entrypoint.sh"]
|
||||
# reap zombies from containerd-shim
|
||||
ENTRYPOINT ["/sbin/tini", "/app/docker-entrypoint.sh"]
|
||||
|
@ -1,23 +1,34 @@
|
||||
ARG IMAGE_PREFIX=git.0x7f.app/woj
|
||||
ARG VERSION=latest
|
||||
# Go builder
|
||||
FROM docker.io/library/golang:alpine AS go-builder
|
||||
|
||||
# Base image
|
||||
FROM ${IMAGE_PREFIX}/woj-server-base:${VERSION} AS base
|
||||
#ENV GOPROXY=https://goproxy.cn
|
||||
ENV CGO_ENABLED=0
|
||||
WORKDIR /builder
|
||||
|
||||
RUN apk add --no-cache git make
|
||||
RUN --mount=type=cache,id=golang,target=/go/pkg go install github.com/swaggo/swag/cmd/swag@latest
|
||||
|
||||
COPY go.mod /builder/go.mod
|
||||
COPY go.sum /builder/go.sum
|
||||
RUN --mount=type=cache,id=golang,target=/go/pkg go mod download
|
||||
|
||||
COPY . /builder
|
||||
RUN --mount=type=cache,id=golang,target=/go/pkg make build
|
||||
|
||||
# UI Builder
|
||||
FROM ${IMAGE_PREFIX}/woj-ui:${VERSION} AS ui
|
||||
FROM git.0x7f.app/woj/woj-ui:1.1.0 AS ui-builder
|
||||
RUN find /app -type f -name "*.map" -delete
|
||||
|
||||
# Main image
|
||||
# main image
|
||||
FROM docker.io/library/alpine
|
||||
|
||||
WORKDIR /app
|
||||
RUN apk --no-cache add tzdata ca-certificates bash su-exec
|
||||
RUN apk --no-cache add tzdata ca-certificates bash
|
||||
|
||||
COPY --from=base /builder/config.docker.yaml /app
|
||||
COPY --from=base /builder/docker-entrypoint.sh /app
|
||||
COPY --from=base /builder/woj /app
|
||||
COPY --from=go-builder /builder/config.docker.yaml /app
|
||||
COPY --from=go-builder /builder/docker-entrypoint.sh /app
|
||||
COPY --from=go-builder /builder/woj /app
|
||||
|
||||
COPY --from=ui /app /app/resource/frontend
|
||||
COPY --from=ui-builder /app /app/resource/frontend
|
||||
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
|
103
build_image.sh
103
build_image.sh
@ -2,90 +2,57 @@
|
||||
|
||||
. resource/runner/scripts/common.sh
|
||||
|
||||
# Version
|
||||
# version
|
||||
VERSION="$(cat VERSION)"
|
||||
log_info "VERSION: $VERSION"
|
||||
|
||||
# Image Prefix
|
||||
IMAGE_PREFIX=${IMAGE_PREFIX:-"git.0x7f.app/woj"}
|
||||
|
||||
function docker_pull() {
|
||||
tag_name="$IMAGE_PREFIX/$1:$VERSION"
|
||||
shift 1
|
||||
$DOCKER pull "$tag_name" "$@" || log_warn "[!] Failed to pull $tag_name"
|
||||
}
|
||||
|
||||
function docker_build() {
|
||||
tag_name="$IMAGE_PREFIX/$1:$VERSION"
|
||||
docker_file="$2"
|
||||
shift 2
|
||||
$DOCKER build -t "$tag_name" -f "$docker_file" --build-arg "IMAGE_PREFIX=$IMAGE_PREFIX" --build-arg "VERSION=$VERSION" "$@" . ||
|
||||
{ log_error "[!] Failed to build $tag_name"; exit 1; }
|
||||
}
|
||||
|
||||
function docker_push() {
|
||||
tag_name="$IMAGE_PREFIX/$1"
|
||||
$DOCKER push "$tag_name" ||
|
||||
{ log_error "[!] Failed to push $tag_name"; exit 1; }
|
||||
}
|
||||
|
||||
function build_rootfs() {
|
||||
log_info "[+] Building Rootfs Images"
|
||||
pushd resource/runner || exit 1
|
||||
docker_build "debian-full" "scripts/debian-full.Dockerfile"
|
||||
docker_build "debian-run" "scripts/debian-run.Dockerfile"
|
||||
popd || exit 1
|
||||
}
|
||||
|
||||
function push_rootfs() {
|
||||
log_info "[+] Pushing Rootfs Images"
|
||||
docker_push "debian-full:$VERSION"
|
||||
docker_push "debian-run:$VERSION"
|
||||
}
|
||||
|
||||
function build_base() {
|
||||
log_info "[+] Building Base"
|
||||
docker_build "woj-server-base" "Base.Dockerfile"
|
||||
}
|
||||
|
||||
function build_server() {
|
||||
log_info "[+] Pulling woj-ui"
|
||||
docker_pull "woj-ui"
|
||||
log_info "[+] Building Server"
|
||||
docker_build "woj-server" "Server.Dockerfile"
|
||||
}
|
||||
|
||||
function build_runner() {
|
||||
log_info "[+] Building Runner"
|
||||
docker_build "woj-runner" "Runner.Dockerfile"
|
||||
log_info "[+] Building Base Images"
|
||||
pushd resource/runner || exit 1
|
||||
$DOCKER build -t git.0x7f.app/woj/ubuntu-full:latest -f scripts/ubuntu-full.Dockerfile . ||
|
||||
(log_error "Build Full Image failed" && exit 1)
|
||||
$DOCKER build -t git.0x7f.app/woj/ubuntu-run:latest -f scripts/ubuntu-run.Dockerfile . ||
|
||||
(log_error "Build Tiny Image failed" && exit 1)
|
||||
popd || exit 1
|
||||
}
|
||||
|
||||
function push_base() {
|
||||
log_info "[+] Pushing Base Images"
|
||||
docker_push "woj-server-base:$VERSION"
|
||||
$DOCKER tag "$IMAGE_PREFIX/woj-server-base:$VERSION" "$IMAGE_PREFIX/woj-server-base:latest"
|
||||
docker_push "woj-server-base:latest"
|
||||
$DOCKER push "git.0x7f.app/woj/ubuntu-full:latest"
|
||||
$DOCKER push "git.0x7f.app/woj/ubuntu-run:latest"
|
||||
}
|
||||
|
||||
function build_server() {
|
||||
log_info "[+] Building Server"
|
||||
$DOCKER build -t "git.0x7f.app/woj/woj-server:latest" -f Server.Dockerfile . ||
|
||||
(log_error "[!] Failed to build Server" && exit 1)
|
||||
}
|
||||
|
||||
function build_runner() {
|
||||
log_info "[+] Building Runner"
|
||||
$DOCKER build \
|
||||
--cap-add=sys_admin \
|
||||
--security-opt label=disable \
|
||||
-t "git.0x7f.app/woj/woj-runner:latest" \
|
||||
-f Runner.Dockerfile . ||
|
||||
(log_error "[!] Failed to build Runner" && exit 1)
|
||||
}
|
||||
|
||||
function push_server() {
|
||||
log_info "[+] Pushing Server Images"
|
||||
docker_push "woj-server:$VERSION"
|
||||
$DOCKER tag "$IMAGE_PREFIX/woj-server:$VERSION" "$IMAGE_PREFIX/woj-server:latest"
|
||||
docker_push "woj-server:latest"
|
||||
$DOCKER push "git.0x7f.app/woj/woj-server:latest"
|
||||
$DOCKER tag "git.0x7f.app/woj/woj-server:latest" "git.0x7f.app/woj/woj-server:$VERSION"
|
||||
$DOCKER push "git.0x7f.app/woj/woj-server:$VERSION"
|
||||
}
|
||||
|
||||
function push_runner() {
|
||||
log_info "[+] Pushing Runner Images"
|
||||
docker_push "woj-runner:$VERSION"
|
||||
$DOCKER tag "$IMAGE_PREFIX/woj-runner:$VERSION" "$IMAGE_PREFIX/woj-runner:latest"
|
||||
docker_push "woj-runner:latest"
|
||||
$DOCKER push "git.0x7f.app/woj/woj-runner:latest"
|
||||
$DOCKER tag "git.0x7f.app/woj/woj-runner:latest" "git.0x7f.app/woj/woj-runner:$VERSION"
|
||||
$DOCKER push "git.0x7f.app/woj/woj-runner:$VERSION"
|
||||
}
|
||||
|
||||
if [ "$1" == "rootfs" ]; then
|
||||
build_rootfs
|
||||
push_rootfs
|
||||
exit 0
|
||||
elif [ "$1" == "base" ]; then
|
||||
if [ "$1" == "base" ]; then
|
||||
build_base
|
||||
push_base
|
||||
exit 0
|
||||
@ -98,8 +65,6 @@ elif [ "$1" == "runner" ]; then
|
||||
push_runner
|
||||
exit 0
|
||||
elif [ "$1" == "all" ]; then
|
||||
build_rootfs
|
||||
push_rootfs
|
||||
build_base
|
||||
push_base
|
||||
build_server
|
||||
@ -108,6 +73,6 @@ elif [ "$1" == "all" ]; then
|
||||
push_runner
|
||||
exit 0
|
||||
else
|
||||
log_error "Usage: $0 [rootfs|base|server|runner|all]"
|
||||
log_error "Usage: $0 [base|server|runner|all]"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -75,12 +75,10 @@ func getBuildTime() time.Time {
|
||||
|
||||
func setupSentry() {
|
||||
err := sentry.Init(sentry.ClientOptions{
|
||||
Dsn: SentryDSN,
|
||||
AttachStacktrace: true,
|
||||
EnableTracing: false,
|
||||
IgnoreErrors: []string{},
|
||||
SendDefaultPII: true,
|
||||
Release: GitCommit,
|
||||
Dsn: SentryDSN,
|
||||
EnableTracing: false,
|
||||
SendDefaultPII: true,
|
||||
Release: GitCommit,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("sentry.Init: %s", err)
|
||||
|
@ -38,8 +38,7 @@ Storage:
|
||||
Bucket: ${STORAGE_BUCKET}
|
||||
|
||||
Runner:
|
||||
CGroup: ${CGROUP_PATH}
|
||||
Concurrency: ${RUNNER_CONCURRENCY}
|
||||
Address: ${RUNNER_ADDRESS}
|
||||
|
||||
Metrics:
|
||||
Namespace: ${METRICS_NAMESPACE}
|
||||
|
@ -1,6 +1,6 @@
|
||||
services:
|
||||
server:
|
||||
image: quay.io/ldcraft/woj-server:1.3.1-dev
|
||||
image: git.0x7f.app/woj/woj-server:1.2.3-dev
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8000/health" ]
|
||||
@ -18,19 +18,22 @@ services:
|
||||
- STORAGE_BUCKET=woj
|
||||
- DEVELOPMENT=true
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
depends_on:
|
||||
- storage
|
||||
- cache
|
||||
- db
|
||||
storage:
|
||||
condition: service_healthy
|
||||
cache:
|
||||
condition: service_healthy
|
||||
db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
runner:
|
||||
image: quay.io/ldcraft/woj-runner:1.3.1-dev
|
||||
image: git.0x7f.app/woj/woj-runner:1.2.3-dev
|
||||
restart: unless-stopped
|
||||
command: runner
|
||||
# moby/moby#42040, enable privileged option to make cgroup2 mount as rw
|
||||
privileged: true
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
@ -41,24 +44,29 @@ services:
|
||||
- STORAGE_SECRET_KEY=secret_key
|
||||
- STORAGE_BUCKET=woj
|
||||
- DEVELOPMENT=true
|
||||
- START_CONTAINERD=true
|
||||
volumes:
|
||||
- runner:/app/resource/runner/user
|
||||
- container:/var/lib/containerd
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
depends_on:
|
||||
- storage
|
||||
- cache
|
||||
- db
|
||||
storage:
|
||||
condition: service_healthy
|
||||
cache:
|
||||
condition: service_healthy
|
||||
|
||||
storage:
|
||||
image: quay.io/minio/minio:latest
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live" ]
|
||||
interval: 5s
|
||||
entrypoint: sh
|
||||
command: -c 'mkdir -p /data/woj && minio server /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: "access_key"
|
||||
MINIO_ROOT_PASSWORD: "secret_key"
|
||||
ports:
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- storage:/data
|
||||
|
||||
@ -68,8 +76,6 @@ services:
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "ping" ]
|
||||
interval: 5s
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- cache:/data
|
||||
|
||||
@ -83,8 +89,6 @@ services:
|
||||
- POSTGRES_USER=dev
|
||||
- POSTGRES_PASSWORD=password
|
||||
- POSTGRES_DB=dev
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
|
||||
|
@ -74,8 +74,7 @@ function extract_storage() {
|
||||
}
|
||||
|
||||
function extract_runner() {
|
||||
check_env "CGROUP_PATH" "/sys/fs/cgroup/nsjail" true
|
||||
check_env "RUNNER_CONCURRENCY" 0 false
|
||||
check_env "RUNNER_ADDRESS" "/run/containerd/containerd.sock" true
|
||||
}
|
||||
|
||||
function extract_metrics() {
|
||||
@ -112,13 +111,13 @@ function generate_config() {
|
||||
|
||||
# dump env vars
|
||||
log_info "creating config.yaml"
|
||||
. /tmp/tmp.yaml || { log_error "failed to create config.yaml"; exit 1; }
|
||||
. /tmp/tmp.yaml || (log_error "failed to create config.yaml" && exit 1)
|
||||
|
||||
# cleanup
|
||||
rm -f /tmp/tmp.yaml
|
||||
}
|
||||
|
||||
setup_cgroups() {
|
||||
startup_containerd() {
|
||||
# taken from https://github.com/moby/moby/blob/ee6cbc540e9c62feb143c2a8d3f0c86d2a468767/hack/dind#L59-L69
|
||||
# cgroup v2: enable nesting
|
||||
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
|
||||
@ -131,51 +130,15 @@ setup_cgroups() {
|
||||
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \
|
||||
> /sys/fs/cgroup/cgroup.subtree_control
|
||||
fi
|
||||
|
||||
# create nsjail group
|
||||
mkdir -p /sys/fs/cgroup/nsjail
|
||||
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/nsjail/cgroup.controllers > /sys/fs/cgroup/nsjail/cgroup.subtree_control
|
||||
nohup containerd &
|
||||
log_info 'containerd started'
|
||||
}
|
||||
|
||||
setup_user_runner() {
|
||||
# runner use debian as base image
|
||||
groupadd --gid 1000 woj || true
|
||||
useradd --gid 1000 --uid 1000 woj || true
|
||||
# runner data
|
||||
chown -R woj:woj /app/resource/runner/problem
|
||||
chown -R woj:woj /app/resource/runner/tmp
|
||||
chown -R woj:woj /app/resource/runner/user
|
||||
# rootfs mount path
|
||||
chown -R woj:woj /app/resource/runner/framework/rootfs/full/woj
|
||||
chown -R woj:woj /app/resource/runner/framework/rootfs/run/woj
|
||||
# cgroups
|
||||
chown -R woj:woj /sys/fs/cgroup/nsjail
|
||||
chown -R woj:root /sys/fs/cgroup/cgroup.procs
|
||||
# create run dir: nsjail will try to use it
|
||||
mkdir -p /run/user/1000
|
||||
chown -R woj:woj /run/user/1000
|
||||
chmod 700 /run/user/1000
|
||||
}
|
||||
if [ -n "$START_CONTAINERD" ]; then
|
||||
startup_containerd
|
||||
fi
|
||||
|
||||
setup_user_server() {
|
||||
# server use alpine as base image
|
||||
addgroup -g 1000 -S woj || true
|
||||
adduser -u 1000 -S -G woj woj || true
|
||||
}
|
||||
|
||||
setup_user() {
|
||||
if [ -n "$RUNNER_IMAGE" ]; then
|
||||
setup_user_runner
|
||||
else
|
||||
setup_user_server
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$RUNNER_IMAGE" ]; then setup_cgroups; fi
|
||||
generate_config
|
||||
setup_user
|
||||
|
||||
log_info "starting woj"
|
||||
if [ -n "$RUNNER_IMAGE" ]; then EXEC=gosu; else EXEC=su-exec; fi
|
||||
exec $EXEC woj /app/woj "$@"
|
||||
|
||||
exec /app/woj "$@"
|
||||
|
147
go.mod
147
go.mod
@ -1,97 +1,136 @@
|
||||
module git.0x7f.app/WOJ/woj-server
|
||||
|
||||
go 1.22.0
|
||||
go 1.21.6
|
||||
|
||||
require (
|
||||
github.com/TheZeroSlave/zapsentry v1.23.0
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/getsentry/sentry-go v0.28.1
|
||||
github.com/gin-contrib/cors v1.7.2
|
||||
github.com/gin-contrib/pprof v1.5.0
|
||||
github.com/gin-contrib/static v1.1.2
|
||||
github.com/gin-contrib/zap v1.1.3
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/TheZeroSlave/zapsentry v1.20.2
|
||||
github.com/containerd/containerd v1.7.12
|
||||
github.com/coreos/go-oidc/v3 v3.9.0
|
||||
github.com/getsentry/sentry-go v0.26.0
|
||||
github.com/gin-contrib/cors v1.5.0
|
||||
github.com/gin-contrib/pprof v1.4.0
|
||||
github.com/gin-contrib/zap v0.2.0
|
||||
github.com/gin-gonic/contrib v0.0.0-20221130124618-7e01895a63f2
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/hibiken/asynq v0.24.1
|
||||
github.com/jackc/pgtype v1.14.3
|
||||
github.com/minio/minio-go/v7 v7.0.74
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/redis/go-redis/v9 v9.5.4
|
||||
github.com/jackc/pgtype v1.14.1
|
||||
github.com/minio/minio-go/v7 v7.0.66
|
||||
github.com/opencontainers/runtime-spec v1.1.1-0.20230823135140-4fec88fd00a4
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/redis/go-redis/v9 v9.4.0
|
||||
github.com/samber/do v1.6.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.3
|
||||
github.com/urfave/cli/v2 v2.27.2
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/oauth2 v0.21.0
|
||||
golang.org/x/text v0.16.0
|
||||
github.com/swaggo/swag v1.16.2
|
||||
github.com/urfave/cli/v2 v2.27.1
|
||||
go.uber.org/zap v1.26.0
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/oauth2 v0.16.0
|
||||
golang.org/x/text v0.14.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/postgres v1.5.9
|
||||
gorm.io/gorm v1.25.11
|
||||
gorm.io/driver/postgres v1.5.4
|
||||
gorm.io/gorm v1.25.6
|
||||
moul.io/zapgorm2 v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bytedance/sonic v1.11.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/bytedance/sonic v1.10.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||
github.com/containerd/continuity v0.4.3 // indirect
|
||||
github.com/containerd/fifo v1.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/ttrpc v1.2.2 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||
github.com/go-openapi/spec v0.20.14 // indirect
|
||||
github.com/go-openapi/swag v0.22.9 // 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.22.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/go-playground/validator/v10 v10.17.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
||||
github.com/jackc/pgx/v4 v4.18.1 // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/klauspost/compress v1.17.5 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/leodido/go-urn v1.3.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.1 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/user v0.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.46.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/rs/xid v1.5.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
|
||||
go.opentelemetry.io/otel v1.22.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.22.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.22.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
|
||||
google.golang.org/grpc v1.61.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
)
|
||||
|
442
go.sum
442
go.sum
@ -1,9 +1,18 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIScnXFlF784X79oi7MzVT6GWqr/W1uUt0pB5CsDs9M=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/TheZeroSlave/zapsentry v1.23.0 h1:TKyzfEL7LRlRr+7AvkukVLZ+jZPC++ebCUv7ZJHl1AU=
|
||||
github.com/TheZeroSlave/zapsentry v1.23.0/go.mod h1:3DRFLu4gIpnCTD4V9HMCBSaqYP8gYU7mZickrs2/rIY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.2 h1:gfKebjq3Mq17Ys+4cjE8vc2h6tZVeqCGb9a7vBVqpAk=
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.2/go.mod h1:G2TZhBED5frlh/hsuxV5CDh/ylkSFknPAMPpQg9owQw=
|
||||
github.com/TheZeroSlave/zapsentry v1.20.2 h1:llgC91ZJdoU/OzGxYpUlEhKinf65mw9hJ2KkZ7+cGIk=
|
||||
github.com/TheZeroSlave/zapsentry v1.20.2/go.mod h1:D1YMfSuu6xnkhwFXxrronesmsiyDhIqo+86I3Ok+r64=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
@ -13,92 +22,156 @@ github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdb
|
||||
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg=
|
||||
github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
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.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
||||
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
|
||||
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
|
||||
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
|
||||
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
|
||||
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
|
||||
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
|
||||
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs=
|
||||
github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak=
|
||||
github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
|
||||
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
|
||||
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
|
||||
github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo=
|
||||
github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
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/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/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/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
|
||||
github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k=
|
||||
github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
|
||||
github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
|
||||
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
|
||||
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/getsentry/sentry-go v0.26.0 h1:IX3++sF6/4B5JcevhdZfdKIHfyvMmAq/UnqcyT2H6mA=
|
||||
github.com/getsentry/sentry-go v0.26.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||
github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk=
|
||||
github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
||||
github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU=
|
||||
github.com/gin-contrib/pprof v1.5.0/go.mod h1:GqFL6LerKoCQ/RSWnkYczkTJ+tOAUVN/8sbnEtaqOKs=
|
||||
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=
|
||||
github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90=
|
||||
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/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4=
|
||||
github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
|
||||
github.com/gin-contrib/zap v1.1.3 h1:9e/U9fYd4/OBfmSEBs5hHZq114uACn7bpuzvCkcJySA=
|
||||
github.com/gin-contrib/zap v1.1.3/go.mod h1:+BD/6NYZKJyUpqVoJEvgeq9GLz8pINEQvak9LHNOTSE=
|
||||
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-contrib/zap v0.2.0 h1:HLvt3rZXyC8XC+s2lHzMFow3UDqiEbfrBWJyHHS6L8A=
|
||||
github.com/gin-contrib/zap v0.2.0/go.mod h1:eqfbe9ZmI+GgTZF6nRiC2ZwDeM4DK1Viwc8OxTCphh0=
|
||||
github.com/gin-gonic/contrib v0.0.0-20221130124618-7e01895a63f2 h1:dyuNlYlG1faymw39NdJddnzJICy6587tiGSVioWhYoE=
|
||||
github.com/gin-gonic/contrib v0.0.0-20221130124618-7e01895a63f2/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
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/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
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-jose/go-jose/v4 v4.0.3 h1:o8aphO8Hv6RPmH+GfzVuyf7YXSBibp+8YyHdOoDESGo=
|
||||
github.com/go-jose/go-jose/v4 v4.0.3/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
|
||||
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
|
||||
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
|
||||
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
|
||||
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
|
||||
github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
|
||||
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
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.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
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.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
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.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74=
|
||||
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
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/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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=
|
||||
@ -115,8 +188,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
|
||||
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
||||
github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q=
|
||||
github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
@ -132,30 +205,31 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0=
|
||||
github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus=
|
||||
github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
|
||||
github.com/jackc/pgtype v1.14.1 h1:LyDar7M2K0tShCWqzJ/ctzF1QC3Wzc9c8a6cHE0PFdc=
|
||||
github.com/jackc/pgtype v1.14.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
|
||||
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
||||
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||
github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
|
||||
github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
|
||||
github.com/jackc/pgx/v5 v5.5.2 h1:iLlpgp4Cp/gC9Xuscl7lFL1PhhW+ZLtXZcrfCt4C3tA=
|
||||
github.com/jackc/pgx/v5 v5.5.2/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
|
||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
@ -168,17 +242,20 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
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/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.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E=
|
||||
github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
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=
|
||||
@ -186,8 +263,9 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
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/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/go-urn v1.3.0 h1:jX8FDLfW4ThVXctBNZ+3cIWnCSnrACDV73r76dy0aQQ=
|
||||
github.com/leodido/go-urn v1.3.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@ -200,42 +278,68 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
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/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.74 h1:fTo/XlPBTSpo3BAMshlwKL5RspXRv9us5UeHEGYCFe0=
|
||||
github.com/minio/minio-go/v7 v7.0.74/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa+LDEPogjD8=
|
||||
github.com/minio/minio-go/v7 v7.0.66 h1:bnTOXOHjOqv/gcMuiVbN9o2ngRItvqE774dG9nq0Dzw=
|
||||
github.com/minio/minio-go/v7 v7.0.66/go.mod h1:DHAgmyQEGdW3Cif0UooKOyrT3Vxs82zNdV6tkKhRtbs=
|
||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
|
||||
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
|
||||
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
|
||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/runtime-spec v1.1.1-0.20230823135140-4fec88fd00a4 h1:EctkgBjZ1y4q+sibyuuIgiKpa0QSd2elFtSSdNvBVow=
|
||||
github.com/opencontainers/runtime-spec v1.1.1-0.20230823135140-4fec88fd00a4/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
|
||||
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
|
||||
github.com/redis/go-redis/v9 v9.5.4 h1:vOFYDKKVgrI5u++QvnMT7DksSMYg7Aw/Np4vLJLKLwY=
|
||||
github.com/redis/go-redis/v9 v9.5.4/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
|
||||
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
@ -243,6 +347,8 @@ github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
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/samber/do v1.6.0 h1:Jy/N++BXINDB6lAx5wBlbpHlUdl0FKpLWgGEV9YWqaU=
|
||||
@ -252,6 +358,9 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
@ -260,35 +369,49 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
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/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
|
||||
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
|
||||
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
|
||||
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
|
||||
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 v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
|
||||
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
|
||||
go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y=
|
||||
go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI=
|
||||
go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg=
|
||||
go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY=
|
||||
go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0=
|
||||
go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
@ -296,8 +419,8 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
@ -310,54 +433,69 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/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.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -368,63 +506,100 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/text v0.3.0/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.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo=
|
||||
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
|
||||
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -432,17 +607,22 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=
|
||||
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
|
||||
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||
gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo=
|
||||
gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0=
|
||||
gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
||||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A=
|
||||
gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
moul.io/zapgorm2 v1.3.0 h1:+CzUTMIcnafd0d/BvBce8T4uPn6DQnpIrz64cyixlkk=
|
||||
moul.io/zapgorm2 v1.3.0/go.mod h1:nPVy6U9goFKHR4s+zfSo1xVFaoU7Qgd5DoCdOfzoCqs=
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgtype"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@ -16,17 +15,15 @@ import (
|
||||
// @Description Callback endpoint from OAuth2
|
||||
// @Tags oauth
|
||||
// @Produce json
|
||||
// @Router /v1/oauth/callback [get]
|
||||
// @Router /oauth/callback [get]
|
||||
func (h *handler) CallbackHandler() gin.HandlerFunc {
|
||||
// TODO: Figure out a better way to cooperate with frontend
|
||||
// Currently using /login?redirect_token=xxx to pass jwt token
|
||||
// /error?message=xxx to pass error message
|
||||
// TODO: we are returning e.Response directly here, we should redirect to a trampoline page, passing the response as query string
|
||||
|
||||
return func(c *gin.Context) {
|
||||
// Extract key from cookie
|
||||
key, err := c.Cookie(oauthStateCookieName)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.InvalidParameter.QueryString())
|
||||
e.Pong[any](c, e.InvalidParameter, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@ -34,90 +31,69 @@ func (h *handler) CallbackHandler() gin.HandlerFunc {
|
||||
key = fmt.Sprintf(oauthStateKey, key)
|
||||
expected, err := h.cache.Get().Get(context.Background(), key).Result()
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.RedisError.QueryString())
|
||||
e.Pong[any](c, e.RedisError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Whether state is valid, delete it
|
||||
h.cache.Get().Unlink(context.Background(), key)
|
||||
c.SetCookie(oauthStateCookieName, "", -1, "/", "", false, true)
|
||||
|
||||
// Verify state
|
||||
if c.Query("state") != expected {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.OAuthStateMismatch.QueryString())
|
||||
e.Pong[any](c, e.OAuthStateMismatch, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Exchange code for token
|
||||
token, err := h.conf.Exchange(context.Background(), c.Query("code"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.OAuthExchangeFailed.QueryString())
|
||||
e.Pong[any](c, e.OAuthExchangeFailed, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Extract the ID Token from OAuth2 token.
|
||||
raw, ok := token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.OAuthExchangeFailed.QueryString())
|
||||
e.Pong[any](c, e.OAuthExchangeFailed, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse and verify ID Token payload.
|
||||
idToken, err := h.verifier.Verify(context.Background(), raw)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.OAuthVerifyFailed.QueryString())
|
||||
e.Pong[any](c, e.OAuthVerifyFailed, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Extract custom claims
|
||||
// TODO: extract role from claims: need to modify oidc provider
|
||||
// TODO: extract role from claims
|
||||
var claims struct {
|
||||
Sub string `json:"sub"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// Exp uint64 `json:"exp"`
|
||||
// Iat uint64 `json:"iat"`
|
||||
// AuthTime uint64 `json:"auth_time"`
|
||||
// Jti string `json:"jti"`
|
||||
// Iss string `json:"iss"`
|
||||
// Aud string `json:"aud"`
|
||||
// Typ string `json:"typ"`
|
||||
// Azp string `json:"azp"`
|
||||
// SessionState string `json:"session_state"`
|
||||
// AtHash string `json:"at_hash"`
|
||||
// Acr string `json:"acr"`
|
||||
// Sid string `json:"sid"`
|
||||
// PreferredUsername string `json:"preferred_username"`
|
||||
// GivenName string `json:"given_name"`
|
||||
// FamilyName string `json:"family_name"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
Nickname string `json:"preferred_username"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
if err := idToken.Claims(&claims); err != nil {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.OAuthGetClaimsFailed.QueryString())
|
||||
e.Pong[any](c, e.OAuthGetClaimsFailed, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if claims.Name == "" || claims.Sub == "" {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.UserInvalid.QueryString())
|
||||
return
|
||||
}
|
||||
|
||||
uid := pgtype.UUID{}
|
||||
if err := uid.Set(claims.Sub); err != nil {
|
||||
c.Redirect(http.StatusFound, "/error?message="+e.UserInvalid.QueryString())
|
||||
if !claims.EmailVerified || claims.Email == "" || claims.Nickname == "" {
|
||||
e.Pong[any](c, e.UserInvalid, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Check user existence
|
||||
u, status := h.user.ProfileOrCreate(&user.CreateData{UID: uid, NickName: claims.Name})
|
||||
u, status := h.user.ProfileOrCreate(&user.CreateData{Email: claims.Email, NickName: claims.Nickname})
|
||||
if status != e.Success {
|
||||
c.Redirect(http.StatusFound, "/error?message="+status.QueryString())
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Increment user version
|
||||
version, status := h.user.IncrVersion(u.ID)
|
||||
if status != e.Success {
|
||||
c.Redirect(http.StatusFound, "/error?message="+status.QueryString())
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@ -129,10 +105,12 @@ func (h *handler) CallbackHandler() gin.HandlerFunc {
|
||||
}
|
||||
jwt, status := h.jwt.SignClaim(claim)
|
||||
if status != e.Success {
|
||||
c.Redirect(http.StatusFound, "/error?message="+status.QueryString())
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Figure out a better way to cooperate with frontend
|
||||
c.Redirect(http.StatusFound, "/login?redirect_token="+jwt)
|
||||
// e.Pong(c, status, userApi.LoginResponse{Token: jwt, NickName: u.NickName})
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||
ClientSecret: conf.WebServer.OAuth.ClientSecret,
|
||||
RedirectURL: conf.WebServer.PublicBase + rg.BasePath() + "/callback",
|
||||
Endpoint: app.provider.Endpoint(),
|
||||
Scopes: []string{oidc.ScopeOpenID, "email", "profile"},
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile", "email", "roles"},
|
||||
}
|
||||
|
||||
rg.POST("/login", app.LoginHandler())
|
||||
|
@ -6,24 +6,16 @@ import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type LoginResponse struct {
|
||||
Url string `json:"url"`
|
||||
Cookie struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Live int `json:"live"`
|
||||
} `json:"cookie"`
|
||||
}
|
||||
|
||||
// LoginHandler
|
||||
// @Summary Login with OAuth2
|
||||
// @Description Get OAuth2 Login URL
|
||||
// @Tags oauth
|
||||
// @Produce json
|
||||
// @Response 200 {object} e.Response[oauth.LoginResponse] "random string"
|
||||
// @Router /v1/oauth/login [post]
|
||||
// @Response 200 {object} e.Response[string] "random string"
|
||||
// @Router /oauth/login [post]
|
||||
func (h *handler) LoginHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
state := utils.RandomString(64)
|
||||
@ -35,17 +27,10 @@ func (h *handler) LoginHandler() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
e.Pong(c, e.Success, LoginResponse{
|
||||
Url: h.conf.AuthCodeURL(state),
|
||||
Cookie: struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Live int `json:"live"`
|
||||
}{
|
||||
Name: oauthStateCookieName,
|
||||
Value: key,
|
||||
Live: int(oauthStateLiveness.Seconds()),
|
||||
},
|
||||
})
|
||||
c.SetSameSite(http.SameSiteStrictMode)
|
||||
c.SetCookie(oauthStateCookieName, key, int(oauthStateLiveness.Seconds()), "/", "", false, true)
|
||||
|
||||
url := h.conf.AuthCodeURL(state)
|
||||
e.Pong(c, e.Success, url)
|
||||
}
|
||||
}
|
||||
|
@ -69,5 +69,5 @@ func (h *handler) CreateVersion(c *gin.Context) {
|
||||
_, status = h.taskService.ProblemBuild(payload)
|
||||
e.Pong[any](c, status, nil)
|
||||
|
||||
// consumer/problemUpdate.go will update problem version status
|
||||
// TODO: if failed, delete problem version
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ func (h *handler) Details(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Only Admin is able to view disabled problems
|
||||
claim, exist := c.Get("claim")
|
||||
shouldEnable := !exist || claim.(*model.Claim).Role < model.RoleAdmin
|
||||
|
||||
|
@ -16,7 +16,7 @@ type searchRequest struct {
|
||||
|
||||
// Search
|
||||
// @Summary search for problems
|
||||
// @Description Search for problems based on keywords. If the keyword is empty, return all problems. Admin could view all problems.
|
||||
// @Description Search for problems based on keywords. If the keyword is empty, return all problems.
|
||||
// @Tags problem
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
@ -33,16 +33,12 @@ func (h *handler) Search(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Only Admin is able to view disabled problems
|
||||
claim, exist := c.Get("claim")
|
||||
shouldEnable := !exist || claim.(*model.Claim).Role < model.RoleAdmin
|
||||
|
||||
var count int64
|
||||
param := problem.QueryData{
|
||||
Keyword: req.Keyword,
|
||||
Tag: req.Tag,
|
||||
Associations: true,
|
||||
ShouldEnable: shouldEnable,
|
||||
ShouldEnable: true,
|
||||
Offset: req.Offset,
|
||||
Limit: req.Limit,
|
||||
Count: &count,
|
||||
|
@ -19,7 +19,7 @@ func (h *handler) Build(_ context.Context, t *asynq.Task) error {
|
||||
}
|
||||
|
||||
h.log.Debug("build", zap.Any("payload", p))
|
||||
meta := runner.JudgeMeta{Run: runner.JudgeMetaRun{Version: p.ProblemVersionID}}
|
||||
meta := runner.JudgeMeta{Version: p.ProblemVersionID}
|
||||
|
||||
status, ctx := func() (e.Status, string) {
|
||||
url, status := h.storageService.Get(p.StorageKey, time.Second*60*5)
|
||||
|
@ -35,9 +35,9 @@ func NewRunner(i *do.Injector) (Handler, error) {
|
||||
storageService: do.MustInvoke[storage.Service](i),
|
||||
}
|
||||
|
||||
status := hnd.runnerService.EnsureDeps()
|
||||
status := hnd.runnerService.EnsureDeps(false)
|
||||
if status != e.Success {
|
||||
hnd.log.Fatal("failed to ensure runner dependencies", zap.String("status", status.String()))
|
||||
hnd.log.Error("failed to ensure runner dependencies", zap.String("status", status.String()))
|
||||
return nil, errors.New("failed to ensure dependencies")
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
statusSystemError = runner.JudgeStatus{
|
||||
Message: "System Error",
|
||||
CompileMessage: "",
|
||||
Tasks: []runner.TaskStatus{{Verdict: runner.VerdictSystemError, Message: "System Error"}},
|
||||
}
|
||||
)
|
||||
|
||||
func (h *handler) Judge(_ context.Context, t *asynq.Task) error {
|
||||
var p model.SubmitJudgePayload
|
||||
if err := json.Unmarshal(t.Payload(), &p); err != nil {
|
||||
@ -31,61 +23,46 @@ func (h *handler) Judge(_ context.Context, t *asynq.Task) error {
|
||||
|
||||
user := utils.RandomString(16)
|
||||
h.log.Debug("judge", zap.Any("payload", p), zap.String("user", user))
|
||||
meta := runner.JudgeMeta{
|
||||
Run: runner.JudgeMetaRun{
|
||||
Version: p.ProblemVersionID,
|
||||
User: user,
|
||||
Lang: p.Submission.Language,
|
||||
},
|
||||
meta := runner.JudgeMeta{Version: p.ProblemVersionID, User: user, Lang: p.Submission.Language}
|
||||
|
||||
SystemError := &runner.JudgeStatus{
|
||||
Message: "System Error",
|
||||
Tasks: []runner.TaskStatus{{Verdict: runner.VerdictSystemError, Message: "API Error"}},
|
||||
}
|
||||
|
||||
status, point, ctx := func() (e.Status, int32, *runner.JudgeStatus) {
|
||||
|
||||
// 1. write user code
|
||||
userCode := filepath.Join(runner.UserDir, user, fmt.Sprintf("%s.%s", user, p.Submission.Language))
|
||||
if !file.Touch(userCode) {
|
||||
return e.InternalError, 0, &statusSystemError
|
||||
return e.InternalError, 0, SystemError
|
||||
}
|
||||
err := file.Write(userCode, []byte(p.Submission.Code))
|
||||
if err != nil {
|
||||
return e.InternalError, 0, &statusSystemError
|
||||
return e.InternalError, 0, SystemError
|
||||
}
|
||||
|
||||
// 2. check problem
|
||||
if !h.runnerService.ProblemExists(&meta) {
|
||||
url, status := h.storageService.Get(p.StorageKey, time.Second*60*5)
|
||||
if status != e.Success {
|
||||
return status, 0, &statusSystemError
|
||||
return status, 0, SystemError
|
||||
}
|
||||
|
||||
_, status = h.runnerService.NewProblem(&meta, url, false)
|
||||
if status != e.Success {
|
||||
return status, 0, &statusSystemError
|
||||
return status, 0, SystemError
|
||||
}
|
||||
}
|
||||
|
||||
// 3. validate
|
||||
if ret, status := h.runnerService.ValidatePath(&meta); status != e.Success {
|
||||
return status, 0, ret
|
||||
}
|
||||
|
||||
// 4. extract config
|
||||
if status := h.runnerService.GetConfig(&meta, true); status != e.Success {
|
||||
return e.RunnerProblemParseFailed, 0, &runner.JudgeStatus{
|
||||
Message: fmt.Sprintf("System Error: Problem Malformed (%d:%s)", status, status.String()),
|
||||
CompileMessage: "",
|
||||
Tasks: []runner.TaskStatus{{Verdict: runner.VerdictSystemError, Message: "System Error"}},
|
||||
}
|
||||
}
|
||||
|
||||
// 5. compile
|
||||
// 3. compile
|
||||
compileResult, status := h.runnerService.Compile(&meta)
|
||||
if status != e.Success {
|
||||
return status, 0, compileResult
|
||||
}
|
||||
|
||||
// 6. run and judge
|
||||
// 4. run and judge
|
||||
result, point, status := h.runnerService.RunAndJudge(&meta)
|
||||
result.CompileMessage = compileResult.CompileMessage
|
||||
return status, point, result
|
||||
}()
|
||||
|
||||
|
@ -3,7 +3,6 @@ package submission
|
||||
import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/service/submission"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -48,13 +47,6 @@ func (h *handler) Create(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// check problem enabled
|
||||
_, status := h.problemService.Query(&problem.QueryData{ID: req.Pid, Associations: false, ShouldEnable: role < model.RoleAdmin})
|
||||
if status != e.Success {
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// query latest version
|
||||
pv, status := h.problemService.QueryLatestVersion(req.Pid)
|
||||
if status != e.Success {
|
||||
|
69
internal/api/user/create.go
Normal file
69
internal/api/user/create.go
Normal file
@ -0,0 +1,69 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/mail"
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
Email string `form:"email" json:"email" binding:"required"`
|
||||
NickName string `form:"nickname" json:"nickname" binding:"required"`
|
||||
Password string `form:"password" json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
// Create
|
||||
// @Summary create a new user
|
||||
// @Description create a new user
|
||||
// @Tags user
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param email formData string true "email"
|
||||
// @Param nickname formData string true "nickname"
|
||||
// @Param password formData string true "password"
|
||||
// @Response 200 {object} e.Response[string] "jwt token"
|
||||
// @Router /v1/user/create [post]
|
||||
func (h *handler) Create(c *gin.Context) {
|
||||
req := new(createRequest)
|
||||
if err := c.ShouldBind(req); err != nil {
|
||||
e.Pong(c, e.InvalidParameter, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// verify email is valid
|
||||
_, err := mail.ParseAddress(req.Email)
|
||||
if err != nil {
|
||||
e.Pong[any](c, e.InvalidParameter, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// create user
|
||||
createData := &user.CreateData{
|
||||
Email: req.Email,
|
||||
NickName: req.NickName,
|
||||
Password: req.Password,
|
||||
}
|
||||
u, status := h.userService.Create(createData)
|
||||
if status != e.Success {
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// update version in cache
|
||||
version, status := h.userService.IncrVersion(u.ID)
|
||||
if status != e.Success {
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// sign jwt token
|
||||
claim := &model.Claim{
|
||||
UID: u.ID,
|
||||
Role: u.Role,
|
||||
Version: version,
|
||||
}
|
||||
token, status := h.jwtService.SignClaim(claim)
|
||||
e.Pong(c, status, token)
|
||||
}
|
@ -12,6 +12,8 @@ import (
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
Create(c *gin.Context)
|
||||
Login(c *gin.Context)
|
||||
Logout(c *gin.Context)
|
||||
Profile(c *gin.Context)
|
||||
}
|
||||
@ -29,6 +31,8 @@ func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||
userService: do.MustInvoke[user.Service](i),
|
||||
}
|
||||
|
||||
rg.POST("/create", app.Create)
|
||||
rg.POST("/login", app.Login)
|
||||
rg.POST("/logout", app.jwtService.Handler(true), app.Logout)
|
||||
rg.POST("/profile", app.jwtService.Handler(true), app.Profile)
|
||||
}
|
||||
|
61
internal/api/user/login.go
Normal file
61
internal/api/user/login.go
Normal file
@ -0,0 +1,61 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type loginRequest struct {
|
||||
Email string `form:"email" json:"email" binding:"required"`
|
||||
Password string `form:"password" json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
NickName string `json:"nickname"`
|
||||
}
|
||||
|
||||
// Login
|
||||
// @Summary login
|
||||
// @Description login and return token
|
||||
// @Tags user
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param email formData string true "email"
|
||||
// @Param password formData string true "password"
|
||||
// @Response 200 {object} e.Response[LoginResponse] "jwt token and user's nickname"
|
||||
// @Router /v1/user/login [post]
|
||||
func (h *handler) Login(c *gin.Context) {
|
||||
req := new(loginRequest)
|
||||
if err := c.ShouldBind(req); err != nil {
|
||||
e.Pong(c, e.InvalidParameter, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// check password
|
||||
loginData := &user.LoginData{
|
||||
Email: req.Email,
|
||||
Password: req.Password,
|
||||
}
|
||||
u, status := h.userService.Login(loginData)
|
||||
if status != e.Success {
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// sign and return token
|
||||
version, status := h.userService.IncrVersion(u.ID)
|
||||
if status != e.Success {
|
||||
e.Pong[any](c, status, nil)
|
||||
return
|
||||
}
|
||||
claim := &model.Claim{
|
||||
UID: u.ID,
|
||||
Role: u.Role,
|
||||
Version: version,
|
||||
}
|
||||
token, status := h.jwtService.SignClaim(claim)
|
||||
e.Pong(c, status, LoginResponse{Token: token, NickName: u.NickName})
|
||||
}
|
@ -29,7 +29,7 @@ func (h *handler) Profile(c *gin.Context) {
|
||||
}
|
||||
|
||||
uid := claim.(*model.Claim).UID
|
||||
// role := claim.(*model.Claim).Role
|
||||
role := claim.(*model.Claim).Role
|
||||
|
||||
req := new(profileRequest)
|
||||
if err := c.ShouldBind(req); err != nil {
|
||||
@ -43,5 +43,10 @@ func (h *handler) Profile(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if role < model.RoleAdmin && user.ID != uid {
|
||||
e.Pong[any](c, e.UserUnauthorized, nil)
|
||||
return
|
||||
}
|
||||
|
||||
e.Pong(c, status, user)
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
package e
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
)
|
||||
import "errors"
|
||||
|
||||
type Status int
|
||||
|
||||
@ -15,10 +12,6 @@ func (code Status) String() string {
|
||||
return msgText[InternalError]
|
||||
}
|
||||
|
||||
func (code Status) QueryString() string {
|
||||
return url.QueryEscape(code.String())
|
||||
}
|
||||
|
||||
func (code Status) AsError() error {
|
||||
return errors.New(code.String())
|
||||
}
|
||||
|
@ -22,8 +22,9 @@ type Service interface {
|
||||
|
||||
func NewService(i *do.Injector) (Service, error) {
|
||||
srv := &service{}
|
||||
srv.confService = do.MustInvoke[config.Service](i)
|
||||
|
||||
c := do.MustInvoke[config.Service](i).GetConfig()
|
||||
c := srv.confService.GetConfig()
|
||||
cfg := zap.Config{
|
||||
Level: zap.NewAtomicLevelAt(utils.If(
|
||||
c.Development,
|
||||
@ -57,9 +58,9 @@ func NewService(i *do.Injector) (Service, error) {
|
||||
|
||||
func attachSentry(log *zap.Logger) *zap.Logger {
|
||||
cfg := zapsentry.Configuration{
|
||||
Level: zapcore.DPanicLevel,
|
||||
Level: zapcore.ErrorLevel,
|
||||
EnableBreadcrumbs: true,
|
||||
BreadcrumbLevel: zapcore.DebugLevel,
|
||||
BreadcrumbLevel: zapcore.InfoLevel,
|
||||
}
|
||||
|
||||
core, err := zapsentry.NewCore(cfg, zapsentry.NewSentryClientFromClient(sentry.CurrentHub().Client()))
|
||||
@ -72,7 +73,10 @@ func attachSentry(log *zap.Logger) *zap.Logger {
|
||||
return log.With(zapsentry.NewScope())
|
||||
}
|
||||
|
||||
type service struct{ logger *zap.Logger }
|
||||
type service struct {
|
||||
confService config.Service
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func (s *service) GetRawLogger() *zap.Logger {
|
||||
return s.logger
|
||||
|
@ -18,7 +18,6 @@ type Problem struct {
|
||||
type ProblemVersion struct {
|
||||
gorm.Model `json:"meta"`
|
||||
ProblemID uint `json:"-" gorm:"not null;index"`
|
||||
Problem Problem `json:"problem" gorm:"foreignKey:ProblemID"`
|
||||
Context pgtype.JSON `json:"context" gorm:"type:json"`
|
||||
StorageKey string `json:"-" gorm:"not null"`
|
||||
IsEnabled bool `json:"is_enabled" gorm:"not null;index"`
|
||||
|
@ -1,14 +1,14 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/jackc/pgtype"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model `json:"meta"`
|
||||
UID pgtype.UUID `json:"-" gorm:"not null;uniqueIndex"`
|
||||
NickName string `json:"nick_name" gorm:"not null"`
|
||||
Role Role `json:"role" gorm:"not null"`
|
||||
IsEnabled bool `json:"is_enabled" gorm:"not null;index"`
|
||||
Email string `json:"email" gorm:"not null;uniqueIndex"`
|
||||
NickName string `json:"nick_name" gorm:"not null;uniqueIndex"`
|
||||
Role Role `json:"role" gorm:"not null"`
|
||||
Password []byte `json:"-"`
|
||||
IsEnabled bool `json:"is_enabled" gorm:"not null;index"`
|
||||
}
|
||||
|
@ -50,8 +50,7 @@ type ConfigStorage struct {
|
||||
}
|
||||
|
||||
type ConfigRunner struct {
|
||||
CGroup string `yaml:"CGroup"`
|
||||
Concurrency int `yaml:"Concurrency"`
|
||||
Address string `yaml:"Address"`
|
||||
}
|
||||
|
||||
type ConfigMetrics struct {
|
||||
|
@ -11,30 +11,21 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
Prefix = "./resource/runner"
|
||||
|
||||
ProblemDir = "./problem/"
|
||||
UserDir = "./user/"
|
||||
TmpDir = "./tmp/"
|
||||
NSJailFile = "./framework/scripts/nsjail"
|
||||
RootfsFullDir = "./framework/rootfs/full"
|
||||
RootfsRunDir = "./framework/rootfs/run"
|
||||
Prefix = "./resource/runner"
|
||||
ProblemDir = "./problem/"
|
||||
UserDir = "./user/"
|
||||
TmpDir = "./tmp/"
|
||||
)
|
||||
|
||||
type JudgeMetaRun struct {
|
||||
Version uint // problem version id
|
||||
User string // user id
|
||||
Lang string // language
|
||||
}
|
||||
|
||||
type JudgeMetaConfig struct {
|
||||
All *Config
|
||||
Lang *ConfigLanguage
|
||||
}
|
||||
const (
|
||||
ContainerImageFull = "git.0x7f.app/woj/ubuntu-full:latest"
|
||||
ContainerImageRun = "git.0x7f.app/woj/ubuntu-run:latest"
|
||||
)
|
||||
|
||||
type JudgeMeta struct {
|
||||
Run JudgeMetaRun
|
||||
Cfg JudgeMetaConfig
|
||||
Version uint
|
||||
User string
|
||||
Lang string
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -47,53 +38,36 @@ func init() {
|
||||
ProblemDir = path.Join(Prefix, ProblemDir)
|
||||
UserDir = path.Join(Prefix, UserDir)
|
||||
TmpDir = path.Join(Prefix, TmpDir)
|
||||
NSJailFile = path.Join(Prefix, NSJailFile)
|
||||
RootfsFullDir = path.Join(Prefix, RootfsFullDir)
|
||||
RootfsRunDir = path.Join(Prefix, RootfsRunDir)
|
||||
}
|
||||
|
||||
func (s *service) ProblemExists(meta *JudgeMeta) bool {
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
return file.Exist(problemPath)
|
||||
}
|
||||
|
||||
func (s *service) ValidatePath(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
gen := func(status e.Status) (*JudgeStatus, e.Status) {
|
||||
return &JudgeStatus{
|
||||
Message: fmt.Sprintf("System Error: Problem/User Files Not Found (%d:%s)", status, status.String()),
|
||||
CompileMessage: "",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "System Error"}},
|
||||
}, status
|
||||
}
|
||||
|
||||
func (s *service) ValidatePath(meta *JudgeMeta) e.Status {
|
||||
if !s.ProblemExists(meta) {
|
||||
s.log.Error("problem not exists", zap.Uint("version", meta.Run.Version))
|
||||
return gen(e.RunnerProblemNotExist)
|
||||
s.log.Info("problem not exists", zap.Uint("version", meta.Version))
|
||||
return e.RunnerProblemNotExist
|
||||
}
|
||||
|
||||
userPath := filepath.Join(UserDir, meta.Run.User, fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang))
|
||||
userPath := filepath.Join(UserDir, meta.User, fmt.Sprintf("%s.%s", meta.User, meta.Lang))
|
||||
if !file.Exist(userPath) {
|
||||
s.log.Error("user program not exists", zap.String("user", meta.Run.User), zap.String("lang", meta.Run.Lang))
|
||||
return gen(e.RunnerUserNotExist)
|
||||
s.log.Info("user program not exists", zap.String("user", meta.User), zap.String("lang", meta.Lang))
|
||||
return e.RunnerUserNotExist
|
||||
}
|
||||
|
||||
return nil, e.Success
|
||||
}
|
||||
|
||||
func (s *service) GetConfig(meta *JudgeMeta, skipCheck bool) e.Status {
|
||||
config, err := s.ParseConfig(meta, skipCheck)
|
||||
if err != nil {
|
||||
return e.RunnerProblemParseFailed
|
||||
}
|
||||
|
||||
lang, ok := config.FilterLanguage(meta.Run.Lang)
|
||||
if !ok {
|
||||
return e.RunnerLanguageNotSupported
|
||||
}
|
||||
|
||||
meta.Cfg = JudgeMetaConfig{
|
||||
All: config,
|
||||
Lang: lang,
|
||||
}
|
||||
return e.Success
|
||||
}
|
||||
|
||||
func (s *service) GetConfig(meta *JudgeMeta, skipCheck bool) (*Config, *ConfigLanguage, e.Status) {
|
||||
config, err := s.ParseConfig(meta, skipCheck)
|
||||
if err != nil {
|
||||
return nil, nil, e.RunnerProblemParseFailed
|
||||
}
|
||||
cLang, ok := config.FilterLanguage(meta.Lang)
|
||||
if !ok {
|
||||
return nil, nil, e.RunnerLanguageNotSupported
|
||||
}
|
||||
return config, cLang, e.Success
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"go.uber.org/zap"
|
||||
"io"
|
||||
"os"
|
||||
@ -13,85 +14,94 @@ import (
|
||||
)
|
||||
|
||||
func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
// 0. maybe we can skip compile
|
||||
if v, ok := AllowedLanguages[meta.Cfg.Lang.Lang]; !ok || v.Interpreter != "" {
|
||||
return &JudgeStatus{}, e.Success
|
||||
// 1. ensure problem/user exists
|
||||
status := s.ValidatePath(meta)
|
||||
if status != e.Success {
|
||||
return &JudgeStatus{Message: "check failed"}, status
|
||||
}
|
||||
|
||||
// 1. prepare judge environment
|
||||
workDir := filepath.Join(UserDir, meta.Run.User)
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
|
||||
config, cLang, status := s.GetConfig(meta, true)
|
||||
if status != e.Success {
|
||||
s.log.Error("[compile] parse config failed", zap.Any("meta", *meta))
|
||||
return &JudgeStatus{
|
||||
Message: "parse config failed",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "parse config failed"}},
|
||||
}, e.RunnerProblemParseFailed
|
||||
}
|
||||
|
||||
sourceFile := filepath.Join(workDir, fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.Run.User))
|
||||
// 2. prepare judge environment
|
||||
workDir := filepath.Join(UserDir, meta.User)
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge")
|
||||
|
||||
logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", meta.Run.User))
|
||||
sourceFile := filepath.Join(workDir, fmt.Sprintf("%s.%s", meta.User, meta.Lang))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.User))
|
||||
|
||||
logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", meta.User))
|
||||
log, err := os.Create(logFile)
|
||||
if err != nil {
|
||||
s.log.Error("[compile] create log file failed", zap.Error(err))
|
||||
return &JudgeStatus{
|
||||
Message: "System Error: Unable to create log file",
|
||||
CompileMessage: "",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "System Error"}},
|
||||
Message: "create log file failed",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "create log file failed"}},
|
||||
}, e.RunnerUserCompileFailed
|
||||
}
|
||||
defer func(log *os.File) {
|
||||
_ = log.Close()
|
||||
}(log)
|
||||
|
||||
// 2. compile
|
||||
// 3. compile
|
||||
err = utils.NewMust().
|
||||
DoAny(func() error { return os.Remove(targetFile) }).
|
||||
Do(func() error { return file.TouchErr(targetFile) }).
|
||||
Do(func() error {
|
||||
script := meta.Cfg.Lang.JudgeScript()
|
||||
l, ok := config.FilterLanguage(meta.Lang)
|
||||
if !ok {
|
||||
return e.RunnerProblemParseFailed.AsError()
|
||||
}
|
||||
script := l.JudgeScript()
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{
|
||||
Args: []string{"/bin/sh", "-c", fmt.Sprintf("cd /woj/user && make -f %s compile", script)},
|
||||
Env: []string{fmt.Sprintf("USER_PROG=%s", meta.Run.User), fmt.Sprintf("LANG=%s", meta.Run.Lang)},
|
||||
Args: []string{"sh", "-c", fmt.Sprintf("cd /woj/user && make -f %s compile", script)},
|
||||
Env: []string{fmt.Sprintf("USER_PROG=%s", meta.User), fmt.Sprintf("LANG=%s", meta.Lang)},
|
||||
},
|
||||
Runtime: RuntimeArgs{
|
||||
Rootfs: RootfsFullDir,
|
||||
Pid: int64(utils.If(meta.Cfg.Lang.Runtime.Compile.NProcLimit == 0, 0, meta.Cfg.Lang.Runtime.Compile.NProcLimit+2)), // bash + make
|
||||
Memory: uint64(meta.Cfg.Lang.Runtime.Compile.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Compile.TimeLimit+1000)/1000) * time.Second,
|
||||
Image: ContainerImageFull,
|
||||
Pid: int64(cLang.Runtime.Compile.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(cLang.Runtime.Compile.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((cLang.Runtime.Compile.TimeLimit+1000)/1000) * time.Second,
|
||||
},
|
||||
IO: IOArgs{
|
||||
Output: log,
|
||||
Limit: 4 * 1024, // 4 KB
|
||||
},
|
||||
}
|
||||
args.Runtime.Mount = []MountInfo{
|
||||
args.Runtime.Mount = []specs.Mount{
|
||||
{
|
||||
Source: judgeDir,
|
||||
Destination: "/woj/problem/judge",
|
||||
Readonly: true,
|
||||
},
|
||||
{
|
||||
// Rust will write intermediate files into source directory instead of /tmp
|
||||
Source: "",
|
||||
Destination: "/woj/user",
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: sourceFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.%s", meta.Run.User, meta.Run.Lang),
|
||||
Readonly: true,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.%s", meta.User, meta.Lang),
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: targetFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.Run.User),
|
||||
Readonly: false,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.User),
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
}
|
||||
|
||||
id := s.JailRunPool(args)
|
||||
ret := s.pool.WaitForTask(id)
|
||||
return ret.Error
|
||||
id := s.ContainerRunPool(args)
|
||||
return s.pool.WaitForTask(id)
|
||||
}).
|
||||
Done()
|
||||
|
||||
status := e.Success
|
||||
if err != nil {
|
||||
s.log.Info("[compile] compile failed", zap.Error(err), zap.Any("meta", *meta))
|
||||
status = e.RunnerUserCompileFailed
|
||||
@ -103,16 +113,12 @@ func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
msg = utils.If(err == nil, msg, nil)
|
||||
msgText := string(msg)
|
||||
|
||||
if status != e.Success || !file.Exist(targetFile) || file.Empty(targetFile) {
|
||||
if !file.Exist(targetFile) || file.Empty(targetFile) {
|
||||
return &JudgeStatus{
|
||||
Message: "Compile Failed",
|
||||
CompileMessage: msgText,
|
||||
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
||||
Message: "compile failed",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
||||
utils.If(status == e.Success, e.RunnerUserCompileFailed, status)
|
||||
}
|
||||
|
||||
// 5. grant permission
|
||||
_ = os.Chmod(targetFile, 0755)
|
||||
|
||||
return &JudgeStatus{CompileMessage: msgText}, status
|
||||
return &JudgeStatus{}, e.Success
|
||||
}
|
||||
|
@ -9,74 +9,30 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
AllowedLanguages = map[string]struct {
|
||||
Interpreter string
|
||||
}{
|
||||
"c": {""},
|
||||
"cpp": {""},
|
||||
"go": {""},
|
||||
"python3": {"/usr/bin/python3"},
|
||||
"pypy3": {"/usr/bin/pypy3"},
|
||||
"rust": {""},
|
||||
}
|
||||
)
|
||||
|
||||
type ConfigRuntime struct {
|
||||
TimeLimit int `json:"TimeLimit"` // in ms
|
||||
MemoryLimit int `json:"MemoryLimit"` // in mb
|
||||
SoftMemoryLimit int `json:"SoftMemoryLimit"` // in mb
|
||||
NProcLimit int `json:"NProcLimit"`
|
||||
WriteFileLimit int `json:"WriteFileLimit"` // in mb
|
||||
TimeLimit int `json:"TimeLimit"`
|
||||
MemoryLimit int `json:"MemoryLimit"`
|
||||
NProcLimit int `json:"NProcLimit"`
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultPrebuildRuntime = ConfigRuntime{
|
||||
TimeLimit: 300000,
|
||||
MemoryLimit: 256,
|
||||
SoftMemoryLimit: 256,
|
||||
NProcLimit: 64,
|
||||
WriteFileLimit: 1024,
|
||||
TimeLimit: 300000,
|
||||
MemoryLimit: 256,
|
||||
NProcLimit: 64,
|
||||
}
|
||||
DefaultCompileRuntime = ConfigRuntime{
|
||||
TimeLimit: 60000,
|
||||
MemoryLimit: 256,
|
||||
SoftMemoryLimit: 256,
|
||||
NProcLimit: 64,
|
||||
WriteFileLimit: 64,
|
||||
TimeLimit: 60000,
|
||||
MemoryLimit: 256,
|
||||
NProcLimit: 64,
|
||||
}
|
||||
DefaultCheckRuntime = ConfigRuntime{
|
||||
TimeLimit: 60000,
|
||||
MemoryLimit: 128,
|
||||
SoftMemoryLimit: 128,
|
||||
NProcLimit: 64,
|
||||
WriteFileLimit: 16,
|
||||
TimeLimit: 60000,
|
||||
MemoryLimit: 128,
|
||||
NProcLimit: 64,
|
||||
}
|
||||
)
|
||||
|
||||
func (c *ConfigRuntime) InitWithDefault(fallback *ConfigRuntime) {
|
||||
if c.Validate() != nil {
|
||||
*c = *fallback
|
||||
} else {
|
||||
c.FillDefault()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfigRuntime) FillDefault() {
|
||||
if c.SoftMemoryLimit <= 0 {
|
||||
// default to memory limit
|
||||
c.SoftMemoryLimit = c.MemoryLimit
|
||||
}
|
||||
if c.NProcLimit <= 0 {
|
||||
// default to not limited
|
||||
c.NProcLimit = 0
|
||||
}
|
||||
if c.WriteFileLimit <= 0 {
|
||||
// default to 1mb
|
||||
c.WriteFileLimit = 1
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfigRuntime) Validate() error {
|
||||
if c.TimeLimit <= 0 {
|
||||
return errors.New("time limit <= 0")
|
||||
@ -84,16 +40,8 @@ func (c *ConfigRuntime) Validate() error {
|
||||
if c.MemoryLimit <= 0 {
|
||||
return errors.New("memory limit <= 0")
|
||||
}
|
||||
if c.SoftMemoryLimit <= 0 {
|
||||
// default to memory limit
|
||||
c.SoftMemoryLimit = c.MemoryLimit
|
||||
}
|
||||
if c.NProcLimit <= 0 {
|
||||
c.NProcLimit = 0
|
||||
}
|
||||
if c.WriteFileLimit <= 0 {
|
||||
// default to 1mb
|
||||
c.WriteFileLimit = 1
|
||||
return errors.New("nproc limit <= 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -148,10 +96,6 @@ func (l *ConfigLanguage) JudgeScript() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ConfigLanguage) JudgeInterpreter() string {
|
||||
return AllowedLanguages[l.Lang].Interpreter
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Languages []ConfigLanguage `json:"Languages"`
|
||||
Prebuild ConfigRuntime `json:"Prebuild,omitempty"`
|
||||
@ -162,9 +106,18 @@ type Config struct {
|
||||
}
|
||||
|
||||
func (c *Config) Validate(base string) error {
|
||||
allowedLang := map[string]struct{}{
|
||||
"c": {},
|
||||
"cpp": {},
|
||||
"go": {},
|
||||
"rust": {},
|
||||
"python3": {},
|
||||
"pypy3": {},
|
||||
}
|
||||
|
||||
// check per language config
|
||||
for _, lang := range c.Languages {
|
||||
if _, ok := AllowedLanguages[lang.Lang]; !ok {
|
||||
if _, ok := allowedLang[lang.Lang]; !ok {
|
||||
return fmt.Errorf("language %s is not allowed", lang.Lang)
|
||||
}
|
||||
|
||||
@ -228,7 +181,7 @@ func (c *Config) FilterLanguage(lang string) (*ConfigLanguage, bool) {
|
||||
}
|
||||
|
||||
func (s *service) ParseConfig(meta *JudgeMeta, skipCheck bool) (*Config, error) {
|
||||
base := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
base := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
file := filepath.Join(base, "config.json")
|
||||
|
||||
data, err := os.ReadFile(file)
|
||||
@ -245,11 +198,16 @@ func (s *service) ParseConfig(meta *JudgeMeta, skipCheck bool) (*Config, error)
|
||||
|
||||
// fill default
|
||||
for idx := range config.Languages {
|
||||
config.Languages[idx].Runtime.Compile.InitWithDefault(&DefaultCompileRuntime)
|
||||
config.Languages[idx].Runtime.Check.InitWithDefault(&DefaultCheckRuntime)
|
||||
config.Languages[idx].Runtime.Run.FillDefault()
|
||||
if config.Languages[idx].Runtime.Compile.Validate() != nil {
|
||||
config.Languages[idx].Runtime.Compile = DefaultCompileRuntime
|
||||
}
|
||||
if config.Languages[idx].Runtime.Check.Validate() != nil {
|
||||
config.Languages[idx].Runtime.Check = DefaultCheckRuntime
|
||||
}
|
||||
}
|
||||
if config.Prebuild.Validate() != nil {
|
||||
config.Prebuild = DefaultPrebuildRuntime
|
||||
}
|
||||
config.Prebuild.InitWithDefault(&DefaultPrebuildRuntime)
|
||||
|
||||
if skipCheck {
|
||||
return config, nil
|
142
internal/service/runner/container.go
Normal file
142
internal/service/runner/container.go
Normal file
@ -0,0 +1,142 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"go.uber.org/zap"
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProgramArgs struct {
|
||||
Args []string
|
||||
Env []string
|
||||
}
|
||||
|
||||
type RuntimeArgs struct {
|
||||
Image string
|
||||
Pid int64
|
||||
Memory uint64
|
||||
Timeout time.Duration
|
||||
Mount []specs.Mount
|
||||
}
|
||||
|
||||
func (r *RuntimeArgs) Normalize() {
|
||||
r.Pid = utils.If(r.Pid <= 0, 64, r.Pid)
|
||||
r.Memory = utils.If(r.Memory <= 0, 128*1024*1024, r.Memory)
|
||||
r.Timeout = utils.If(r.Timeout <= 0, time.Minute, r.Timeout)
|
||||
}
|
||||
|
||||
type IOArgs struct {
|
||||
Output *os.File
|
||||
// Limit is the max size of output in chars.
|
||||
// if Limit = 0, output to stderr if verbose, discard output if not.
|
||||
// if Limit < 0, discard output.
|
||||
Limit int64
|
||||
}
|
||||
|
||||
type RunArgs struct {
|
||||
Program ProgramArgs
|
||||
Runtime RuntimeArgs
|
||||
IO IOArgs
|
||||
}
|
||||
|
||||
func (s *service) ContainerRun(arg *RunArgs) error {
|
||||
identifier := fmt.Sprintf("%d", s.container.count.Add(1))
|
||||
|
||||
// prepare args
|
||||
arg.Runtime.Normalize()
|
||||
|
||||
// prepare output
|
||||
var writer io.Writer = nil
|
||||
if arg.IO.Limit == 0 && s.verbose {
|
||||
writer = os.Stderr
|
||||
} else if arg.IO.Limit > 0 && arg.IO.Output != nil {
|
||||
writer = &file.LimitedWriter{
|
||||
File: arg.IO.Output,
|
||||
Limit: arg.IO.Limit,
|
||||
}
|
||||
}
|
||||
|
||||
// debug log
|
||||
s.log.Debug("container started", zap.String("identifier", identifier), zap.Any("args", arg))
|
||||
defer func(identifier string) {
|
||||
s.log.Debug("container finished", zap.String("identifier", identifier))
|
||||
}(identifier)
|
||||
|
||||
// get image
|
||||
image, err := s.container.client.GetImage(s.container.ctx, arg.Runtime.Image)
|
||||
// TODO: we could cache the image struct
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create container
|
||||
container, err := s.container.client.NewContainer(s.container.ctx, "task-"+identifier,
|
||||
containerd.WithNewSnapshot("snapshot-"+identifier, image),
|
||||
containerd.WithNewSpec(
|
||||
oci.WithImageConfig(image),
|
||||
oci.WithMemoryLimit(arg.Runtime.Memory),
|
||||
oci.WithPidsLimit(arg.Runtime.Pid),
|
||||
oci.WithMounts(arg.Runtime.Mount),
|
||||
oci.WithProcessArgs(arg.Program.Args...),
|
||||
oci.WithEnv(arg.Program.Env),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(container containerd.Container, ctx context.Context, opts ...containerd.DeleteOpts) {
|
||||
_ = container.Delete(ctx, opts...)
|
||||
}(container, s.container.ctx, containerd.WithSnapshotCleanup)
|
||||
|
||||
// create task
|
||||
task, err := container.NewTask(s.container.ctx, cio.NewCreator(cio.WithStreams(nil, writer, writer)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(task containerd.Task, ctx context.Context, opts ...containerd.ProcessDeleteOpts) {
|
||||
_, _ = task.Delete(ctx, opts...)
|
||||
}(task, s.container.ctx, containerd.WithProcessKill)
|
||||
|
||||
// wait
|
||||
ctx2, cancel := context.WithTimeout(s.container.ctx, arg.Runtime.Timeout)
|
||||
defer cancel()
|
||||
exitStatusC, err := task.Wait(ctx2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start
|
||||
err = task.Start(s.container.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// kill on timeout
|
||||
status := <-exitStatusC
|
||||
code, _, _ := status.Result()
|
||||
if code == containerd.UnknownExitStatus {
|
||||
// containerd is C/S architecture, timeout means grpc timeout, resulting in unknown exit status
|
||||
// manually kill the task
|
||||
s.log.Debug("container timeout", zap.String("identifier", identifier))
|
||||
err := task.Kill(s.container.ctx, syscall.SIGKILL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) ContainerRunPool(arg *RunArgs) int {
|
||||
return s.pool.AddTask(func() error { return s.ContainerRun(arg) })
|
||||
}
|
@ -1,18 +1,96 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/containerd/containerd"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func (s *service) EnsureDeps() e.Status {
|
||||
// A very SIMPLE check
|
||||
full := filepath.Join(RootfsFullDir, "woj")
|
||||
run := filepath.Join(RootfsRunDir, "woj")
|
||||
if !file.Exist(full) || !file.Exist(run) {
|
||||
type depConfig struct {
|
||||
tarball string
|
||||
image string
|
||||
}
|
||||
|
||||
func (s *service) LoadImageFromTarball(path string) error {
|
||||
if !file.Exist(path) {
|
||||
return errors.New("tarball not exists")
|
||||
}
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
_ = f.Close()
|
||||
}(f)
|
||||
|
||||
g, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(g *gzip.Reader) {
|
||||
_ = g.Close()
|
||||
}(g)
|
||||
|
||||
_, err = s.container.client.Import(s.container.ctx, g)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) LoadImageFromRegistry(image string) error {
|
||||
_, err := s.container.client.Pull(s.container.ctx, image, containerd.WithPullUnpack)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) LoadImage(cfg *depConfig) e.Status {
|
||||
err := utils.NewTryErr().
|
||||
Try(func() error { return s.LoadImageFromTarball(cfg.tarball) }).
|
||||
Or(func() error { return s.LoadImageFromRegistry(cfg.image) }).
|
||||
Done()
|
||||
|
||||
if err != nil {
|
||||
s.log.Warn("[deps] load image failed", zap.Error(err))
|
||||
return e.RunnerDepsBuildFailed
|
||||
}
|
||||
|
||||
return e.Success
|
||||
}
|
||||
|
||||
func (s *service) EnsureDeps(force bool) e.Status {
|
||||
mark := filepath.Join(Prefix, ".mark.image")
|
||||
|
||||
// check mark
|
||||
if force {
|
||||
_ = os.Remove(mark)
|
||||
} else if file.Exist(mark) {
|
||||
return e.Success
|
||||
}
|
||||
|
||||
// full
|
||||
fullImage := &depConfig{
|
||||
tarball: filepath.Join(TmpDir, "ubuntu-full.tar.gz"),
|
||||
image: ContainerImageFull,
|
||||
}
|
||||
if s.LoadImage(fullImage) != e.Success {
|
||||
return e.RunnerDepsBuildFailed
|
||||
}
|
||||
|
||||
// tiny
|
||||
tinyImage := &depConfig{
|
||||
tarball: filepath.Join(TmpDir, "ubuntu-tiny.tar.gz"),
|
||||
image: ContainerImageRun,
|
||||
}
|
||||
if s.LoadImage(tinyImage) != e.Success {
|
||||
return e.RunnerDepsBuildFailed
|
||||
}
|
||||
|
||||
// mark
|
||||
_, _ = os.Create(mark)
|
||||
|
||||
return e.Success
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/down"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/unzip"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -14,8 +14,8 @@ import (
|
||||
)
|
||||
|
||||
func (s *service) DownloadProblem(meta *JudgeMeta, url string) e.Status {
|
||||
zipPath := filepath.Join(TmpDir, fmt.Sprintf("%d.zip", meta.Run.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
zipPath := filepath.Join(TmpDir, fmt.Sprintf("%d.zip", meta.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
|
||||
err := down.Down(zipPath, url)
|
||||
if err != nil {
|
||||
@ -37,51 +37,53 @@ func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e
|
||||
return e.RunnerProblemNotExist
|
||||
}
|
||||
|
||||
mark := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), ".mark.prebuild")
|
||||
mark := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), ".mark.prebuild")
|
||||
if force {
|
||||
_ = os.Remove(mark)
|
||||
} else if file.Exist(mark) {
|
||||
return e.Success
|
||||
}
|
||||
|
||||
prebuildScript := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge", "prebuild.Makefile")
|
||||
prebuildScript := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge", "prebuild.Makefile")
|
||||
if !file.Exist(prebuildScript) {
|
||||
s.log.Info("[new] prebuild script not found", zap.String("path", prebuildScript), zap.Uint("version", meta.Run.Version))
|
||||
s.log.Info("[new] prebuild script not found", zap.String("path", prebuildScript), zap.Uint("version", meta.Version))
|
||||
return e.Success
|
||||
}
|
||||
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge")
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{
|
||||
Args: []string{"/bin/sh", "-c", "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild"},
|
||||
Args: []string{"sh", "-c", "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild"},
|
||||
},
|
||||
Runtime: RuntimeArgs{
|
||||
Rootfs: RootfsFullDir,
|
||||
Pid: int64(utils.If(config.Prebuild.NProcLimit == 0, 0, config.Prebuild.NProcLimit+3)), // sh + bash + make
|
||||
Image: ContainerImageFull,
|
||||
Pid: int64(config.Prebuild.NProcLimit + 3), // sh + bash + make
|
||||
Memory: uint64(config.Prebuild.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((config.Prebuild.TimeLimit+1000)/1000) * time.Second,
|
||||
},
|
||||
}
|
||||
args.Runtime.Mount = []MountInfo{
|
||||
args.Runtime.Mount = []specs.Mount{
|
||||
{
|
||||
Source: dataDir,
|
||||
Destination: "/woj/problem/data",
|
||||
Readonly: false,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
{
|
||||
Source: judgeDir,
|
||||
Destination: "/woj/problem/judge",
|
||||
Readonly: false,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
}
|
||||
|
||||
id := s.JailRunPool(args)
|
||||
ret := s.pool.WaitForTask(id)
|
||||
id := s.ContainerRunPool(args)
|
||||
err := s.pool.WaitForTask(id)
|
||||
|
||||
if ret.Error != nil {
|
||||
s.log.Warn("[new] prebuild problem failed", zap.Any("ret", ret), zap.Uint("version", meta.Run.Version))
|
||||
if err != nil {
|
||||
s.log.Warn("[new] prebuild problem failed", zap.Error(err), zap.Uint("version", meta.Version))
|
||||
return e.RunnerProblemPrebuildFailed
|
||||
}
|
||||
|
||||
@ -90,7 +92,7 @@ func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e
|
||||
|
||||
func (s *service) NewProblem(meta *JudgeMeta, url string, force bool) (*Config, e.Status) {
|
||||
if force {
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
_ = os.RemoveAll(problemPath)
|
||||
}
|
||||
|
||||
@ -103,7 +105,7 @@ func (s *service) NewProblem(meta *JudgeMeta, url string, force bool) (*Config,
|
||||
|
||||
cfg, err := s.ParseConfig(meta, false)
|
||||
if err != nil {
|
||||
s.log.Info("[new] parse problem failed", zap.Error(err), zap.Uint("version", meta.Run.Version))
|
||||
s.log.Info("[new] parse problem failed", zap.Error(err), zap.Uint("version", meta.Version))
|
||||
return &Config{}, e.RunnerProblemParseFailed
|
||||
}
|
||||
|
||||
|
@ -1,182 +0,0 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"go.uber.org/zap"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProgramArgs struct {
|
||||
Args []string
|
||||
Env []string
|
||||
}
|
||||
|
||||
func (p *ProgramArgs) EnvArgs() []string {
|
||||
var env []string
|
||||
for _, e := range p.Env {
|
||||
env = append(env, "-E", e)
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
type MountInfo struct {
|
||||
Source string
|
||||
Destination string
|
||||
Readonly bool
|
||||
}
|
||||
|
||||
func (m *MountInfo) Args() []string {
|
||||
mapping := m.Source + ":" + m.Destination
|
||||
if m.Source == "" {
|
||||
// 64MB tmpfs
|
||||
return []string{"-m", "none:" + m.Destination + ":tmpfs:size=67108864"}
|
||||
} else if m.Readonly {
|
||||
return []string{"-R", mapping}
|
||||
} else {
|
||||
return []string{"-B", mapping}
|
||||
}
|
||||
}
|
||||
|
||||
type RuntimeArgs struct {
|
||||
Rootfs string
|
||||
CPU int
|
||||
Pid int64
|
||||
Memory uint64 // Memory is in bytes
|
||||
Timeout time.Duration
|
||||
Mount []MountInfo
|
||||
}
|
||||
|
||||
func (r *RuntimeArgs) Args() []string {
|
||||
cpus := runtime.NumCPU()
|
||||
cpus = utils.If(r.CPU < cpus, r.CPU, cpus)
|
||||
cpus = utils.If(r.CPU == 0, 1, cpus)
|
||||
|
||||
args := []string{
|
||||
"-c", r.Rootfs,
|
||||
"--cgroup_pids_max", strconv.FormatInt(r.Pid, 10),
|
||||
"--cgroup_mem_max", strconv.FormatUint(r.Memory, 10),
|
||||
"--max_cpus", strconv.FormatInt(int64(cpus), 10),
|
||||
"-t", strconv.FormatInt(int64(r.Timeout.Seconds()), 10),
|
||||
}
|
||||
for _, m := range r.Mount {
|
||||
args = append(args, m.Args()...)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
type IOArgs struct {
|
||||
Output *os.File
|
||||
// Limit is the max size of output in chars.
|
||||
// if Limit = 0, output to stderr if verbose, discard output if not.
|
||||
// if Limit < 0, discard output.
|
||||
Limit int64
|
||||
}
|
||||
|
||||
type RunArgs struct {
|
||||
Program ProgramArgs
|
||||
Runtime RuntimeArgs
|
||||
IO IOArgs
|
||||
}
|
||||
|
||||
func (s *service) JailRun(arg *RunArgs) (RuntimeStatus, error) {
|
||||
// check cgroup creation
|
||||
if arg.Runtime.Pid == 0 && arg.Runtime.Memory == 0 {
|
||||
s.log.Warn("cgroup pid and memory not set, resource tracing by cgroup will not work")
|
||||
}
|
||||
|
||||
// create stats file
|
||||
statFile, err := os.CreateTemp("", "jail-stats-*")
|
||||
if err != nil {
|
||||
s.log.Warn("create stats file failed", zap.Error(err))
|
||||
return RuntimeStatus{}, err
|
||||
}
|
||||
_ = statFile.Close()
|
||||
|
||||
// prepare output
|
||||
var writer io.Writer = nil
|
||||
if arg.IO.Limit == 0 && s.verbose {
|
||||
writer = os.Stderr
|
||||
} else if arg.IO.Limit > 0 && arg.IO.Output != nil {
|
||||
writer = &file.LimitedWriter{
|
||||
File: arg.IO.Output,
|
||||
Limit: arg.IO.Limit,
|
||||
}
|
||||
}
|
||||
|
||||
// build args
|
||||
args := []string{
|
||||
"--really_quiet",
|
||||
"--use_cgroupv2",
|
||||
"--disable_rlimits",
|
||||
"-m", "none:/tmp:tmpfs:size=67108864", // 64MB tmpfs
|
||||
"-T", "/dev", "-R", "/dev/null", "-R", "/dev/zero", "-R", "/dev/full", "-R", "/dev/random", "-R", "/dev/urandom",
|
||||
"-E", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
// following envs must sync with resource/runner
|
||||
"-E", "WOJ_LAUNCHER=/woj/framework/scripts/woj_launcher",
|
||||
"-E", "TEMPLATE=/woj/framework/template",
|
||||
"-E", "TESTLIB=/woj/framework/template/testlib",
|
||||
"-E", "PREFIX=/woj",
|
||||
}
|
||||
args = append(args, "--cgroupv2_mount", s.cgroup)
|
||||
args = append(args, "--dump_stats", "--dump_stats_file", statFile.Name())
|
||||
args = append(args, arg.Program.EnvArgs()...)
|
||||
args = append(args, arg.Runtime.Args()...)
|
||||
args = append(args, "--")
|
||||
args = append(args, arg.Program.Args...)
|
||||
|
||||
// run
|
||||
s.log.Debug("jail run", zap.Strings("args", args))
|
||||
cmd := exec.Command(NSJailFile, args...)
|
||||
cmd.Dir = Prefix
|
||||
if s.verbose {
|
||||
cmd.Stdout = writer
|
||||
cmd.Stderr = writer
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
s.log.Warn("jail run failed", zap.Error(err))
|
||||
return RuntimeStatus{}, err
|
||||
}
|
||||
|
||||
// re-open stat file
|
||||
statFile, err = os.Open(statFile.Name())
|
||||
if err != nil {
|
||||
s.log.Error("open stats file failed", zap.Error(err))
|
||||
return RuntimeStatus{}, err
|
||||
}
|
||||
defer func(statFile *os.File) {
|
||||
_ = statFile.Close()
|
||||
_ = os.Remove(statFile.Name())
|
||||
}(statFile)
|
||||
|
||||
// collect metrics
|
||||
status := RuntimeStatus{}
|
||||
scanner := bufio.NewScanner(statFile)
|
||||
for scanner.Scan() {
|
||||
var key string
|
||||
var value int
|
||||
_, _ = fmt.Sscanf(scanner.Text(), "%s %d", &key, &value)
|
||||
switch key {
|
||||
case "usage_usec":
|
||||
status.RealTime = value / 1000
|
||||
case "user_usec":
|
||||
status.CpuTime = value / 1000
|
||||
case "memory.peak":
|
||||
status.Memory = value / 1024
|
||||
}
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
|
||||
func (s *service) JailRunPool(arg *RunArgs) uint64 {
|
||||
return s.pool.AddTask(func() (interface{}, error) { return s.JailRun(arg) })
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkContainerRun(b *testing.B) {
|
||||
srv := GetService(false).(*service)
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{Args: []string{"/bin/sh", "-c", "echo hello world"}},
|
||||
Runtime: RuntimeArgs{Rootfs: RootfsRunDir, Memory: 16 * 1024 * 1024},
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := srv.JailRun(args)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkContainerRunPool(b *testing.B) {
|
||||
srv := GetService(false).(*service)
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{Args: []string{"/bin/sh", "-c", "echo hello world"}},
|
||||
Runtime: RuntimeArgs{Rootfs: RootfsRunDir, Memory: 16 * 1024 * 1024},
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
var ids []uint64
|
||||
for i := 0; i < b.N; i++ {
|
||||
id := srv.JailRunPool(args)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
buf := srv.pool.WaitForTask(id)
|
||||
if buf.Error != nil {
|
||||
b.Error(buf.Error)
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -12,99 +13,80 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProblemRunResult struct {
|
||||
QueueId uint64
|
||||
Status RuntimeStatus
|
||||
}
|
||||
|
||||
type ProblemRunResults map[int]*ProblemRunResult
|
||||
|
||||
func (s *service) SandboxArgsBuilder(meta *JudgeMeta, id int) string {
|
||||
func (s *service) SandboxArgsBuilder(meta *JudgeMeta, cLang *ConfigLanguage, id int) string {
|
||||
var args []string
|
||||
|
||||
args = append(args, fmt.Sprintf("--memory_limit=%d", meta.Cfg.Lang.Runtime.Run.SoftMemoryLimit))
|
||||
args = append(args, fmt.Sprintf("--nproc_limit=%d", meta.Cfg.Lang.Runtime.Run.NProcLimit))
|
||||
args = append(args, fmt.Sprintf("--time_limit=%d", meta.Cfg.Lang.Runtime.Run.TimeLimit))
|
||||
args = append(args, fmt.Sprintf("--fsize_limit=%d", meta.Cfg.Lang.Runtime.Run.WriteFileLimit))
|
||||
args = append(args, fmt.Sprintf("--sandbox_template=%s", meta.Cfg.Lang.Lang))
|
||||
args = append(args, fmt.Sprintf("--sandbox_action=%s", "ret"))
|
||||
args = append(args, fmt.Sprintf("--uid=%d", 1000))
|
||||
args = append(args, fmt.Sprintf("--gid=%d", 1000))
|
||||
args = append(args, fmt.Sprintf("--memory_limit=%d", cLang.Runtime.Run.MemoryLimit))
|
||||
args = append(args, fmt.Sprintf("--nproc_limit=%d", cLang.Runtime.Run.NProcLimit))
|
||||
args = append(args, fmt.Sprintf("--time_limit=%d", cLang.Runtime.Run.TimeLimit))
|
||||
args = append(args, fmt.Sprintf("--sandbox_template=%s", cLang.Lang))
|
||||
args = append(args, fmt.Sprintf("--sandbox_action=ret"))
|
||||
args = append(args, fmt.Sprintf("--uid=1000"))
|
||||
args = append(args, fmt.Sprintf("--gid=1000"))
|
||||
args = append(args, fmt.Sprintf("--file_input=/woj/problem/data/input/%d.input", id))
|
||||
args = append(args, fmt.Sprintf("--file_output=/woj/user/%d.out.usr", id))
|
||||
args = append(args, fmt.Sprintf("--file_info=/woj/user/%d.info", id))
|
||||
|
||||
if meta.Cfg.Lang.JudgeInterpreter() != "" {
|
||||
sourceFile := fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang)
|
||||
|
||||
args = append(args, fmt.Sprintf("--program=%s", meta.Cfg.Lang.JudgeInterpreter()))
|
||||
args = append(args, fmt.Sprintf("--program_arg=/woj/user/%s", sourceFile))
|
||||
} else {
|
||||
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.Run.User))
|
||||
}
|
||||
|
||||
s.log.Debug("[run] sandbox args", zap.Strings("args", args))
|
||||
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.User))
|
||||
|
||||
return strings.Join(args, " ")
|
||||
}
|
||||
|
||||
func (s *service) ProblemRun(meta *JudgeMeta) ProblemRunResults {
|
||||
workDir := filepath.Join(UserDir, meta.Run.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data", "input")
|
||||
func (s *service) ProblemRun(meta *JudgeMeta, config *Config, cLang *ConfigLanguage) {
|
||||
workDir := filepath.Join(UserDir, meta.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "data", "input")
|
||||
|
||||
runtimeArgs := RuntimeArgs{
|
||||
Rootfs: RootfsRunDir,
|
||||
Image: ContainerImageRun,
|
||||
// sh, woj_launcher:program, woj_launcher:killer, woj_launcher:stat
|
||||
Pid: int64(utils.If(meta.Cfg.Lang.Runtime.Run.NProcLimit == 0, 0, meta.Cfg.Lang.Runtime.Run.NProcLimit+4)),
|
||||
// use SoftMemoryLimit when run, judge with MemoryLimit
|
||||
Memory: uint64(meta.Cfg.Lang.Runtime.Run.SoftMemoryLimit * 1024 * 1024),
|
||||
Pid: int64(cLang.Runtime.Run.NProcLimit + 4),
|
||||
Memory: uint64(cLang.Runtime.Run.MemoryLimit * 1024 * 1024),
|
||||
// woj-sandbox killer will add 1 more second, here we add 1 also
|
||||
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Run.TimeLimit+1000)/1000+1+1) * time.Second,
|
||||
Timeout: time.Duration((cLang.Runtime.Run.TimeLimit+1000)/1000+1+1) * time.Second,
|
||||
}
|
||||
|
||||
result := make(ProblemRunResults)
|
||||
for _, task := range meta.Cfg.All.Tasks {
|
||||
f := func(id int) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
ids := make([]int, 0)
|
||||
for _, task := range config.Tasks {
|
||||
f := func(id int) func() error {
|
||||
return func() error {
|
||||
testCase := filepath.Join(dataDir, fmt.Sprintf("%d.input", id))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.User))
|
||||
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
|
||||
ifoFile := filepath.Join(workDir, fmt.Sprintf("%d.info", id))
|
||||
|
||||
targetFile := fmt.Sprintf("%s.out", meta.Run.User)
|
||||
targetPath := filepath.Join(workDir, targetFile)
|
||||
sourceFile := fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang)
|
||||
sourcePath := filepath.Join(workDir, sourceFile)
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{
|
||||
Args: []string{
|
||||
"/bin/sh", "-c",
|
||||
"sh", "-c",
|
||||
"cd /woj/user && /woj/framework/scripts/woj_launcher " +
|
||||
s.SandboxArgsBuilder(meta, id),
|
||||
s.SandboxArgsBuilder(meta, cLang, id),
|
||||
},
|
||||
},
|
||||
Runtime: runtimeArgs,
|
||||
}
|
||||
args.Runtime.Mount = []MountInfo{
|
||||
args.Runtime.Mount = []specs.Mount{
|
||||
{
|
||||
Source: testCase,
|
||||
Destination: fmt.Sprintf("/woj/problem/data/input/%d.input", id),
|
||||
Readonly: true,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: utils.If(meta.Cfg.Lang.JudgeInterpreter() != "", sourcePath, targetPath),
|
||||
Destination: fmt.Sprintf("/woj/user/%s", utils.If(meta.Cfg.Lang.JudgeInterpreter() != "", sourceFile, targetFile)),
|
||||
Readonly: true,
|
||||
Source: targetFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.User),
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: ansFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%d.out.usr", id),
|
||||
Readonly: false,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
{
|
||||
Source: ifoFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%d.info", id),
|
||||
Readonly: false,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
}
|
||||
|
||||
@ -113,114 +95,95 @@ func (s *service) ProblemRun(meta *JudgeMeta) ProblemRunResults {
|
||||
DoAny(func() error { return os.Remove(ifoFile) }).
|
||||
Do(func() error { return file.TouchErr(ansFile) }).
|
||||
Do(func() error { return file.TouchErr(ifoFile) }).
|
||||
Do(func() error { return s.ContainerRun(args) }).
|
||||
Done()
|
||||
|
||||
if err != nil {
|
||||
s.log.Info("[run] prepare failed", zap.Error(err), zap.Any("meta", *meta))
|
||||
return nil, err
|
||||
s.log.Info("[run] run failed", zap.Error(err), zap.Any("meta", *meta))
|
||||
}
|
||||
|
||||
return s.JailRun(args)
|
||||
return err
|
||||
}
|
||||
}(task.Id)
|
||||
|
||||
queueId := s.pool.AddTask(f)
|
||||
result[task.Id] = &ProblemRunResult{
|
||||
QueueId: queueId,
|
||||
}
|
||||
id := s.pool.AddTask(f)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
for i := range result {
|
||||
waitBuf := s.pool.WaitForTask(result[i].QueueId)
|
||||
if waitBuf.Error != nil {
|
||||
s.log.Error(
|
||||
"[run] wait for problem run failed",
|
||||
zap.Error(waitBuf.Error),
|
||||
zap.Any("meta", *meta))
|
||||
continue
|
||||
}
|
||||
val, ok := waitBuf.Value.(RuntimeStatus)
|
||||
if !ok {
|
||||
s.log.Error(
|
||||
"[run] container run is not returning RuntimeStatus",
|
||||
zap.Any("waitBuf", waitBuf),
|
||||
zap.Any("meta", *meta))
|
||||
continue
|
||||
}
|
||||
|
||||
result[i].Status = val
|
||||
for _, id := range ids {
|
||||
_ = s.pool.WaitForTask(id)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *service) ProblemJudge(meta *JudgeMeta) {
|
||||
workDir := filepath.Join(UserDir, meta.Run.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
|
||||
script := meta.Cfg.Lang.JudgeScript()
|
||||
func (s *service) ProblemJudge(meta *JudgeMeta, config *Config, cLang *ConfigLanguage) {
|
||||
workDir := filepath.Join(UserDir, meta.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge")
|
||||
script := cLang.JudgeScript()
|
||||
|
||||
runtimeArgs := RuntimeArgs{
|
||||
Rootfs: RootfsFullDir,
|
||||
Pid: int64(meta.Cfg.Lang.Runtime.Check.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(meta.Cfg.Lang.Runtime.Check.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Check.TimeLimit+1000)/1000) * time.Second,
|
||||
Image: ContainerImageFull,
|
||||
Pid: int64(cLang.Runtime.Check.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(cLang.Runtime.Check.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((cLang.Runtime.Check.TimeLimit+1000)/1000) * time.Second,
|
||||
}
|
||||
|
||||
ids := make([]uint64, 0)
|
||||
for _, task := range meta.Cfg.All.Tasks {
|
||||
f := func(id int) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
ids := make([]int, 0)
|
||||
for _, task := range config.Tasks {
|
||||
f := func(id int) func() error {
|
||||
return func() error {
|
||||
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
|
||||
jdgFile := filepath.Join(workDir, fmt.Sprintf("%d.judge", id))
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{
|
||||
Args: []string{
|
||||
"/bin/sh", "-c",
|
||||
"sh", "-c",
|
||||
fmt.Sprintf("cd /woj/user && make -f %s judge", script),
|
||||
},
|
||||
Env: []string{
|
||||
fmt.Sprintf("TEST_NUM=%d", id),
|
||||
fmt.Sprintf("CMP=%s", meta.Cfg.Lang.Judge.Cmp),
|
||||
fmt.Sprintf("CMP=%s", cLang.Judge.Cmp),
|
||||
},
|
||||
},
|
||||
Runtime: runtimeArgs,
|
||||
}
|
||||
args.Runtime.Mount = []MountInfo{
|
||||
args.Runtime.Mount = []specs.Mount{
|
||||
{
|
||||
Source: judgeDir,
|
||||
Destination: "/woj/problem/judge",
|
||||
Readonly: true,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: dataDir,
|
||||
Destination: "/woj/problem/data",
|
||||
Readonly: true,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: ansFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%d.out.usr", id),
|
||||
Readonly: true,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
{
|
||||
Source: jdgFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%d.judge", id),
|
||||
Readonly: false,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
}
|
||||
|
||||
err := utils.NewMust().
|
||||
DoAny(func() error { return os.Remove(jdgFile) }).
|
||||
Do(func() error { return file.TouchErr(jdgFile) }).
|
||||
Do(func() error { return s.ContainerRun(args) }).
|
||||
Done()
|
||||
|
||||
if err != nil {
|
||||
s.log.Info("[judge] judge prepare failed", zap.Error(err), zap.Any("meta", *meta))
|
||||
return nil, err
|
||||
s.log.Info("[judge] judge failed", zap.Error(err), zap.Any("meta", *meta))
|
||||
}
|
||||
|
||||
return s.JailRun(args)
|
||||
return err
|
||||
}
|
||||
}(task.Id)
|
||||
|
||||
@ -234,14 +197,26 @@ func (s *service) ProblemJudge(meta *JudgeMeta) {
|
||||
}
|
||||
|
||||
func (s *service) RunAndJudge(meta *JudgeMeta) (*JudgeStatus, int32, e.Status) {
|
||||
// 1. run user program
|
||||
results := s.ProblemRun(meta)
|
||||
// 1. ensure problem/user exists
|
||||
status := s.ValidatePath(meta)
|
||||
if status != e.Success {
|
||||
return &JudgeStatus{Message: "check failed"}, 0, status
|
||||
}
|
||||
|
||||
// 2. run judge
|
||||
s.ProblemJudge(meta)
|
||||
// 2. config
|
||||
config, cLang, status := s.GetConfig(meta, true)
|
||||
if status != e.Success {
|
||||
return &JudgeStatus{Message: status.String()}, 0, status
|
||||
}
|
||||
|
||||
// 3. final JudgeStatus
|
||||
status, pts := s.CheckResults(meta, results)
|
||||
// 3. run user program
|
||||
s.ProblemRun(meta, config, cLang)
|
||||
|
||||
return status, pts, e.Success
|
||||
// 4. run judge
|
||||
s.ProblemJudge(meta, config, cLang)
|
||||
|
||||
// 5. check result
|
||||
result, pts := s.CheckResults(meta, config, cLang)
|
||||
|
||||
return result, pts, e.Success
|
||||
}
|
||||
|
@ -1,21 +1,25 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/pool"
|
||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/samber/do"
|
||||
"go.uber.org/zap"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
type Service interface {
|
||||
// EnsureDeps build docker images
|
||||
EnsureDeps() e.Status
|
||||
EnsureDeps(force bool) e.Status
|
||||
// NewProblem = Download + Parse + Prebuild
|
||||
NewProblem(meta *JudgeMeta, url string, force bool) (*Config, e.Status)
|
||||
|
||||
@ -28,38 +32,43 @@ type Service interface {
|
||||
ParseConfig(meta *JudgeMeta, skipCheck bool) (*Config, error)
|
||||
// ProblemExists check if problem exists
|
||||
ProblemExists(meta *JudgeMeta) bool
|
||||
// ValidatePath check if problem/user exists
|
||||
ValidatePath(meta *JudgeMeta) (*JudgeStatus, e.Status)
|
||||
// GetConfig return config and filter language config, will fill result to meta.Config
|
||||
GetConfig(meta *JudgeMeta, skipCheck bool) e.Status
|
||||
|
||||
HealthCheck() error
|
||||
Shutdown() error
|
||||
}
|
||||
|
||||
func NewService(i *do.Injector) (Service, error) {
|
||||
concurrency := utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1)
|
||||
cfg := do.MustInvoke[config.Service](i).GetConfig()
|
||||
|
||||
concurrency := cfg.Runner.Concurrency
|
||||
if concurrency <= 0 {
|
||||
concurrency = utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1)
|
||||
}
|
||||
|
||||
srv := &service{
|
||||
log: do.MustInvoke[log.Service](i).GetLogger("runner"),
|
||||
pool: pool.NewTaskPool(concurrency, concurrency),
|
||||
cgroup: cfg.Runner.CGroup,
|
||||
verbose: cfg.Development,
|
||||
}
|
||||
|
||||
var err error
|
||||
srv.container.client, err = containerd.New(cfg.Runner.Address)
|
||||
if err != nil {
|
||||
srv.log.Error("failed to connect to containerd", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srv.container.ctx = namespaces.WithNamespace(context.Background(), "woj")
|
||||
srv.container.count.Store(0)
|
||||
|
||||
srv.pool.Start()
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
type service struct {
|
||||
log *zap.Logger
|
||||
pool *pool.TaskPool
|
||||
cgroup string
|
||||
log *zap.Logger
|
||||
pool *pool.TaskPool
|
||||
container struct {
|
||||
client *containerd.Client
|
||||
ctx context.Context
|
||||
count atomic.Uint64
|
||||
}
|
||||
verbose bool
|
||||
}
|
||||
|
||||
@ -69,5 +78,10 @@ func (s *service) HealthCheck() error {
|
||||
|
||||
func (s *service) Shutdown() error {
|
||||
s.pool.Stop()
|
||||
if s.container.client != nil {
|
||||
// TODO: wait and kill all containers
|
||||
_ = s.container.client.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"github.com/samber/do"
|
||||
)
|
||||
|
||||
type FakeConfigService struct {
|
||||
conf model.Config
|
||||
}
|
||||
|
||||
func (s *FakeConfigService) GetConfig() *model.Config {
|
||||
return &s.conf
|
||||
}
|
||||
|
||||
func (s *FakeConfigService) HealthCheck() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetService(dev bool) Service {
|
||||
injector := do.New()
|
||||
|
||||
cfg := &FakeConfigService{conf: model.Config{
|
||||
Development: dev,
|
||||
Runner: model.ConfigRunner{
|
||||
CGroup: "/sys/fs/cgroup/nsjail",
|
||||
Concurrency: 0,
|
||||
},
|
||||
}}
|
||||
|
||||
do.ProvideValue[config.Service](injector, cfg)
|
||||
do.Provide(injector, log.NewService)
|
||||
do.Provide(injector, NewService)
|
||||
|
||||
return do.MustInvoke[Service](injector)
|
||||
}
|
@ -31,18 +31,14 @@ type TestLibReport struct {
|
||||
Result string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type RuntimeStatus struct {
|
||||
RealTime int `json:"real_time"` // in ms
|
||||
CpuTime int `json:"cpu_time"` // in ms
|
||||
Memory int `json:"memory"` // in kb
|
||||
}
|
||||
|
||||
type TaskStatus struct {
|
||||
Id int `json:"id"`
|
||||
Points int32 `json:"points"`
|
||||
Runtime RuntimeStatus `json:"runtime"`
|
||||
Verdict int `json:"verdict"`
|
||||
Message string `json:"message"`
|
||||
Id int `json:"id"`
|
||||
Points int32 `json:"points"`
|
||||
RealTime int `json:"real_time"`
|
||||
CpuTime int `json:"cpu_time"`
|
||||
Memory int `json:"memory"`
|
||||
Verdict int `json:"verdict"`
|
||||
Message string `json:"message"`
|
||||
|
||||
infoText []byte
|
||||
info map[string]interface{}
|
||||
@ -51,12 +47,11 @@ type TaskStatus struct {
|
||||
}
|
||||
|
||||
type JudgeStatus struct {
|
||||
Message string `json:"message"`
|
||||
CompileMessage string `json:"compile_message"`
|
||||
Tasks []TaskStatus `json:"tasks"`
|
||||
Message string `json:"message"`
|
||||
Tasks []TaskStatus `json:"tasks"`
|
||||
}
|
||||
|
||||
func (t *TaskStatus) ReadSandboxInfo(infoFile string) *TaskStatus {
|
||||
func (t *TaskStatus) getInfoText(infoFile string) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
@ -71,7 +66,7 @@ func (t *TaskStatus) ReadSandboxInfo(infoFile string) *TaskStatus {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) ExtractSandboxInfo() *TaskStatus {
|
||||
func (t *TaskStatus) getInfo() *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
@ -81,57 +76,15 @@ func (t *TaskStatus) ExtractSandboxInfo() *TaskStatus {
|
||||
t.Verdict = VerdictSystemError
|
||||
t.Message = "cannot parse info file"
|
||||
} else {
|
||||
t.Runtime = RuntimeStatus{
|
||||
RealTime: int(t.info["real_time"].(float64)),
|
||||
CpuTime: int(t.info["cpu_time"].(float64)),
|
||||
Memory: int(t.info["memory"].(float64)),
|
||||
}
|
||||
t.RealTime = int(t.info["real_time"].(float64))
|
||||
t.CpuTime = int(t.info["cpu_time"].(float64))
|
||||
t.Memory = int(t.info["memory"].(float64))
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) MergeContainerInfo(status *RuntimeStatus) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
|
||||
t.Runtime.RealTime = max(t.Runtime.RealTime, status.RealTime)
|
||||
t.Runtime.CpuTime = max(t.Runtime.CpuTime, status.CpuTime)
|
||||
t.Runtime.Memory = max(t.Runtime.Memory, status.Memory)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) CheckTime(cLang *ConfigLanguage) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
|
||||
if t.Runtime.RealTime > cLang.Runtime.Run.TimeLimit+5 ||
|
||||
t.Runtime.CpuTime > cLang.Runtime.Run.TimeLimit+5 {
|
||||
t.Verdict = VerdictTimeLimitExceeded
|
||||
t.Message = fmt.Sprintf("real_time: %v cpu_time: %v", t.Runtime.RealTime, t.Runtime.CpuTime)
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) CheckMemory(cLang *ConfigLanguage) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
|
||||
// t.Runtime.Memory is in kb
|
||||
if t.Runtime.Memory > (cLang.Runtime.Run.MemoryLimit+1)*1024 {
|
||||
t.Verdict = VerdictMemoryLimitExceeded
|
||||
t.Message = fmt.Sprintf("memory: %v", t.Runtime.Memory)
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) CheckExitCode() *TaskStatus {
|
||||
func (t *TaskStatus) checkExit() *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
@ -144,7 +97,33 @@ func (t *TaskStatus) CheckExitCode() *TaskStatus {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) ReadJudgeReport(judgeFile string) *TaskStatus {
|
||||
func (t *TaskStatus) checkTime(cLang *ConfigLanguage) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
|
||||
if t.info["real_time"].(float64) > float64(cLang.Runtime.Run.TimeLimit)+5 {
|
||||
t.Verdict = VerdictTimeLimitExceeded
|
||||
t.Message = fmt.Sprintf("real_time: %v cpu_time: %v", t.info["real_time"], t.info["cpu_time"])
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) checkMemory(cLang *ConfigLanguage) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
|
||||
if t.info["memory"].(float64) > float64((cLang.Runtime.Run.MemoryLimit+1)*1024) {
|
||||
t.Verdict = VerdictMemoryLimitExceeded
|
||||
t.Message = fmt.Sprintf("memory: %v", t.info["memory"])
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) getJudgeText(judgeFile string) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
@ -152,7 +131,7 @@ func (t *TaskStatus) ReadJudgeReport(judgeFile string) *TaskStatus {
|
||||
j, err := file.Read(judgeFile)
|
||||
if err != nil {
|
||||
t.Verdict = VerdictSystemError
|
||||
t.Message = "cannot read judge report"
|
||||
t.Message = "cannot read judge file"
|
||||
} else {
|
||||
t.judgeText = string(j)
|
||||
}
|
||||
@ -160,7 +139,7 @@ func (t *TaskStatus) ReadJudgeReport(judgeFile string) *TaskStatus {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) DecodeJudgeReport() *TaskStatus {
|
||||
func (t *TaskStatus) getJudge() *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
@ -179,13 +158,13 @@ func (t *TaskStatus) DecodeJudgeReport() *TaskStatus {
|
||||
err := d.Decode(&t.judge)
|
||||
if err != nil {
|
||||
t.Verdict = VerdictSystemError
|
||||
t.Message = "cannot parse judge report"
|
||||
t.Message = "cannot parse judge file"
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TaskStatus) CheckJudgeReport(pts *map[int]int32) *TaskStatus {
|
||||
func (t *TaskStatus) checkJudge(pts *map[int]int32) *TaskStatus {
|
||||
if t.Verdict != VerdictAccepted {
|
||||
return t
|
||||
}
|
||||
@ -214,33 +193,32 @@ func (t *TaskStatus) CheckJudgeReport(pts *map[int]int32) *TaskStatus {
|
||||
return t
|
||||
}
|
||||
|
||||
func (s *service) CheckResults(meta *JudgeMeta, prResults ProblemRunResults) (*JudgeStatus, int32) {
|
||||
func (s *service) CheckResults(meta *JudgeMeta, config *Config, cLang *ConfigLanguage) (*JudgeStatus, int32) {
|
||||
// CE will be processed in phase compile
|
||||
|
||||
pts := map[int]int32{}
|
||||
for _, task := range meta.Cfg.All.Tasks {
|
||||
for _, task := range config.Tasks {
|
||||
pts[task.Id] = task.Points
|
||||
}
|
||||
|
||||
var results []TaskStatus
|
||||
dir := filepath.Join(UserDir, meta.Run.User)
|
||||
dir := filepath.Join(UserDir, meta.User)
|
||||
var sum int32 = 0
|
||||
|
||||
for i := 1; i <= len(meta.Cfg.All.Tasks); i++ {
|
||||
for i := 1; i <= len(config.Tasks); i++ {
|
||||
result := TaskStatus{Id: i, Verdict: VerdictAccepted, Points: 0}
|
||||
|
||||
info := filepath.Join(dir, fmt.Sprintf("%d.info", i))
|
||||
judge := filepath.Join(dir, fmt.Sprintf("%d.judge", i))
|
||||
|
||||
result.ReadSandboxInfo(info).
|
||||
ExtractSandboxInfo().
|
||||
MergeContainerInfo(&prResults[i].Status).
|
||||
CheckTime(meta.Cfg.Lang).
|
||||
CheckMemory(meta.Cfg.Lang).
|
||||
CheckExitCode().
|
||||
ReadJudgeReport(judge).
|
||||
DecodeJudgeReport().
|
||||
CheckJudgeReport(&pts)
|
||||
result.getInfoText(info).
|
||||
getInfo().
|
||||
checkTime(cLang).
|
||||
checkMemory(cLang).
|
||||
checkExit().
|
||||
getJudgeText(judge).
|
||||
getJudge().
|
||||
checkJudge(&pts)
|
||||
|
||||
sum += result.Points
|
||||
results = append(results, result)
|
@ -3,25 +3,33 @@ package user
|
||||
import (
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"github.com/jackc/pgtype"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateData struct {
|
||||
UID pgtype.UUID
|
||||
Email string
|
||||
NickName string
|
||||
Password string
|
||||
}
|
||||
|
||||
func (s *service) Create(data *CreateData) (*model.User, e.Status) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(data.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
s.log.Warn("BcryptError", zap.Error(err), zap.String("password", data.Password))
|
||||
return nil, e.InternalError
|
||||
}
|
||||
|
||||
user := &model.User{
|
||||
UID: data.UID,
|
||||
Email: data.Email,
|
||||
NickName: data.NickName,
|
||||
Password: hashed,
|
||||
Role: model.RoleGeneral,
|
||||
IsEnabled: true,
|
||||
}
|
||||
|
||||
err := s.db.Get().Create(user).Error
|
||||
err = s.db.Get().Create(user).Error
|
||||
if err != nil && strings.Contains(err.Error(), "duplicate key") {
|
||||
return nil, e.UserDuplicated
|
||||
}
|
||||
|
43
internal/service/user/login.go
Normal file
43
internal/service/user/login.go
Normal file
@ -0,0 +1,43 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type LoginData struct {
|
||||
Email string
|
||||
Password string
|
||||
}
|
||||
|
||||
func (s *service) Login(data *LoginData) (*model.User, e.Status) {
|
||||
user := &model.User{Email: data.Email}
|
||||
|
||||
err := s.db.Get().Where(user).First(&user).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, e.UserNotFound
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("user", user))
|
||||
return nil, e.DatabaseError
|
||||
}
|
||||
|
||||
if !user.IsEnabled {
|
||||
return nil, e.UserDisabled
|
||||
}
|
||||
if len(user.Password) == 0 {
|
||||
// created by oauth
|
||||
return nil, e.UserWithoutPassword
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword(user.Password, []byte(data.Password))
|
||||
if err != nil {
|
||||
return nil, e.UserWrongPassword
|
||||
}
|
||||
|
||||
return user, e.Success
|
||||
}
|
@ -25,26 +25,19 @@ func (s *service) Profile(uid uint) (*model.User, e.Status) {
|
||||
|
||||
func (s *service) ProfileOrCreate(data *CreateData) (*model.User, e.Status) {
|
||||
user := &model.User{
|
||||
UID: data.UID,
|
||||
Email: data.Email,
|
||||
NickName: data.NickName,
|
||||
Role: model.RoleGeneral,
|
||||
IsEnabled: true,
|
||||
}
|
||||
|
||||
// Notice: FirstOrCreate will not update the record if it exists
|
||||
err := s.db.Get().Where(model.User{UID: data.UID}).FirstOrCreate(&user, data).Error
|
||||
// Notice: FirstOrCreate will not update the record if it exists, and also we should not update the record
|
||||
// Notice: OAuth2 created user will not have password
|
||||
err := s.db.Get().Where(model.User{Email: data.Email}).FirstOrCreate(&user, data).Error
|
||||
if err != nil {
|
||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("user", user))
|
||||
return nil, e.DatabaseError
|
||||
}
|
||||
|
||||
if user.NickName != data.NickName {
|
||||
err = s.db.Get().Model(&user).Update("nick_name", data.NickName).Error
|
||||
if err != nil {
|
||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("user", user))
|
||||
return nil, e.DatabaseError
|
||||
}
|
||||
}
|
||||
|
||||
return user, e.Success
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ var _ Service = (*service)(nil)
|
||||
|
||||
type Service interface {
|
||||
Create(data *CreateData) (*model.User, e.Status)
|
||||
Login(data *LoginData) (*model.User, e.Status)
|
||||
IncrVersion(uid uint) (int64, e.Status)
|
||||
Profile(uid uint) (*model.User, e.Status)
|
||||
ProfileOrCreate(data *CreateData) (*model.User, e.Status)
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// @title WOJ Server API Documentation
|
||||
// @version 1.3.1
|
||||
// @version 1.2.0
|
||||
// @BasePath /api
|
||||
// @securityDefinitions.apikey Authentication
|
||||
// @in header
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
sentrygin "github.com/getsentry/sentry-go/gin"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-contrib/static"
|
||||
ginZap "github.com/gin-contrib/zap"
|
||||
"github.com/gin-gonic/contrib/static"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/samber/do"
|
||||
@ -135,11 +135,6 @@ func (s *service) initRouters(conf *model.Config, injector *do.Injector) *gin.En
|
||||
api := r.Group("/api/")
|
||||
s.setupApi(api, injector)
|
||||
|
||||
// do not allow crawling
|
||||
r.GET("/robots.txt", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "User-agent: *\nDisallow: /")
|
||||
})
|
||||
|
||||
// static files
|
||||
r.Use(static.Serve("/", static.LocalFile("./resource/frontend", true)))
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package pool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type TaskPool struct {
|
||||
@ -10,29 +10,18 @@ type TaskPool struct {
|
||||
queue chan Task
|
||||
wg sync.WaitGroup
|
||||
|
||||
curTaskID atomic.Uint64
|
||||
waitMap sync.Map
|
||||
}
|
||||
|
||||
type ErrTaskNotFound struct{}
|
||||
|
||||
func (m *ErrTaskNotFound) Error() string {
|
||||
return "task not found"
|
||||
}
|
||||
|
||||
type WaitBuf struct {
|
||||
Value interface{}
|
||||
Error error
|
||||
lck sync.Mutex
|
||||
curTaskID int
|
||||
waitMap map[int]chan error
|
||||
}
|
||||
|
||||
func NewTaskPool(maxWorkers, bufferSize int) *TaskPool {
|
||||
tp := &TaskPool{
|
||||
return &TaskPool{
|
||||
workers: maxWorkers,
|
||||
queue: make(chan Task, bufferSize),
|
||||
waitMap: sync.Map{},
|
||||
curTaskID: atomic.Uint64{},
|
||||
waitMap: make(map[int]chan error),
|
||||
curTaskID: 1, // task id starts from 1
|
||||
}
|
||||
return tp
|
||||
}
|
||||
|
||||
func (tp *TaskPool) Start() {
|
||||
@ -43,11 +32,16 @@ func (tp *TaskPool) Start() {
|
||||
}
|
||||
}
|
||||
|
||||
func (tp *TaskPool) AddTask(f func() (interface{}, error)) uint64 {
|
||||
id := tp.curTaskID.Add(1)
|
||||
func (tp *TaskPool) AddTask(f func() error) int {
|
||||
tp.lck.Lock()
|
||||
|
||||
waitChan := make(chan WaitBuf, 1)
|
||||
tp.waitMap.Store(id, waitChan)
|
||||
id := tp.curTaskID
|
||||
tp.curTaskID++
|
||||
|
||||
waitChan := make(chan error, 1)
|
||||
tp.waitMap[id] = waitChan
|
||||
|
||||
tp.lck.Unlock()
|
||||
|
||||
task := Task{id: id, f: f}
|
||||
tp.queue <- task
|
||||
@ -55,29 +49,35 @@ func (tp *TaskPool) AddTask(f func() (interface{}, error)) uint64 {
|
||||
return id
|
||||
}
|
||||
|
||||
func (tp *TaskPool) WaitForTask(taskID uint64) WaitBuf {
|
||||
val, ok := tp.waitMap.Load(taskID)
|
||||
func (tp *TaskPool) WaitForTask(taskID int) error {
|
||||
tp.lck.Lock()
|
||||
waitChan, ok := tp.waitMap[taskID]
|
||||
if !ok {
|
||||
return WaitBuf{nil, &ErrTaskNotFound{}}
|
||||
tp.lck.Unlock()
|
||||
return errors.New("task not found")
|
||||
}
|
||||
waitChan := val.(chan WaitBuf)
|
||||
tp.lck.Unlock()
|
||||
|
||||
ret := <-waitChan
|
||||
close(waitChan)
|
||||
tp.waitMap.Delete(taskID)
|
||||
|
||||
tp.lck.Lock()
|
||||
delete(tp.waitMap, taskID)
|
||||
tp.lck.Unlock()
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (tp *TaskPool) markTaskComplete(taskID uint64, buf WaitBuf) {
|
||||
val, ok := tp.waitMap.Load(taskID)
|
||||
func (tp *TaskPool) markTaskComplete(taskID int, err error) {
|
||||
tp.lck.Lock()
|
||||
waitChan, ok := tp.waitMap[taskID]
|
||||
if !ok {
|
||||
// should never happen here
|
||||
panic("worker: task destroyed before completion")
|
||||
tp.lck.Unlock()
|
||||
return
|
||||
}
|
||||
tp.lck.Unlock()
|
||||
|
||||
waitChan := val.(chan WaitBuf)
|
||||
waitChan <- buf
|
||||
waitChan <- err
|
||||
}
|
||||
|
||||
func (tp *TaskPool) Stop() {
|
||||
|
@ -2,6 +2,7 @@ package pool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@ -15,8 +16,8 @@ func TestTaskPool_Stop(t *testing.T) {
|
||||
counter := 0
|
||||
|
||||
for i := 1; i <= 10; i++ {
|
||||
f := func(i int) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
f := func(i int) func() error {
|
||||
return func() error {
|
||||
lck.Lock()
|
||||
t.Log("task", i, "locked")
|
||||
counter += i
|
||||
@ -26,7 +27,7 @@ func TestTaskPool_Stop(t *testing.T) {
|
||||
time.Sleep(time.Duration(i*100) * time.Millisecond)
|
||||
t.Log("task", i, "finished")
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
}(i)
|
||||
pool.AddTask(f)
|
||||
@ -46,12 +47,11 @@ func TestTaskPool_WaitForTask(t *testing.T) {
|
||||
counter := 0
|
||||
|
||||
for i := 1; i <= 10; i++ {
|
||||
f := func(i int) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
f := func(i int) func() error {
|
||||
return func() error {
|
||||
counter += 1
|
||||
t.Log("task", i, "finished")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return i, nil
|
||||
return errors.New(strconv.Itoa(i))
|
||||
}
|
||||
}(i)
|
||||
id := pool.AddTask(f)
|
||||
@ -60,11 +60,8 @@ func TestTaskPool_WaitForTask(t *testing.T) {
|
||||
if counter != 1 {
|
||||
t.Errorf("Counter mismatch: expected %d, got %d, task %d", 1, counter, id)
|
||||
}
|
||||
if ret.Error != nil {
|
||||
t.Errorf("Return error: %v, task %d", ret.Error, id)
|
||||
}
|
||||
if ret.Value.(int) != i {
|
||||
t.Errorf("Return value mismatch: expected %d, got %v, task %d", i, ret, id)
|
||||
if ret.Error() != strconv.Itoa(i) {
|
||||
t.Errorf("Return value mismatch: expected %s, got %s, task %d", strconv.Itoa(i), ret.Error(), id)
|
||||
}
|
||||
counter -= 1
|
||||
}
|
||||
@ -72,31 +69,6 @@ func TestTaskPool_WaitForTask(t *testing.T) {
|
||||
pool.Stop()
|
||||
}
|
||||
|
||||
func TestTaskPool_DoubleWait(t *testing.T) {
|
||||
pool := NewTaskPool(1, 1)
|
||||
pool.Start()
|
||||
|
||||
f := func() (interface{}, error) {
|
||||
t.Log("task invoked")
|
||||
return nil, nil
|
||||
}
|
||||
id := pool.AddTask(f)
|
||||
|
||||
ret := pool.WaitForTask(id)
|
||||
if ret.Error != nil {
|
||||
t.Errorf("task returned error: %v", ret)
|
||||
}
|
||||
|
||||
ret2 := pool.WaitForTask(id)
|
||||
if ret2.Error == nil {
|
||||
t.Errorf("2nd wait returned nil")
|
||||
} else if !errors.Is(ret2.Error, &ErrTaskNotFound{}) {
|
||||
t.Errorf("2nd wait returned wrong error: %v", ret2)
|
||||
}
|
||||
|
||||
pool.Stop()
|
||||
}
|
||||
|
||||
func TestTaskPool_One(t *testing.T) {
|
||||
pool := NewTaskPool(1, 1)
|
||||
pool.Start()
|
||||
@ -104,10 +76,10 @@ func TestTaskPool_One(t *testing.T) {
|
||||
lck := sync.Mutex{}
|
||||
counter := 0
|
||||
|
||||
ids := make([]uint64, 0)
|
||||
ids := make([]int, 0)
|
||||
for i := 1; i <= 10; i++ {
|
||||
f := func(i int) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
f := func(i int) func() error {
|
||||
return func() error {
|
||||
lck.Lock()
|
||||
t.Log("task", i, "locked")
|
||||
counter += i
|
||||
@ -117,7 +89,7 @@ func TestTaskPool_One(t *testing.T) {
|
||||
time.Sleep(time.Duration(i*10) * time.Millisecond)
|
||||
t.Log("task", i, "finished")
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
}(i)
|
||||
id := pool.AddTask(f)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package pool
|
||||
|
||||
type Task struct {
|
||||
id uint64
|
||||
f func() (interface{}, error)
|
||||
id int
|
||||
f func() error
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func (w *Worker) Start(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
for task := range w.queue {
|
||||
val, err := task.f()
|
||||
w.pool.markTaskComplete(task.id, WaitBuf{Value: val, Error: err})
|
||||
err := task.f()
|
||||
w.pool.markTaskComplete(task.id, err)
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: runner
|
||||
image: git.0x7f.app/woj/woj-runner:1.3.1-dev
|
||||
image: git.0x7f.app/woj/woj-runner:1.3.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- runner
|
||||
@ -61,14 +61,19 @@ spec:
|
||||
key: MINIO_ROOT_PASSWORD
|
||||
- name: STORAGE_BUCKET
|
||||
value: "woj"
|
||||
- name: SETUP_CGROUP
|
||||
- name: START_CONTAINERD
|
||||
value: "true"
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: runner-vol
|
||||
mountPath: /app/resource/runner/user
|
||||
- name: container-vol
|
||||
mountPath: /var/lib/containerd
|
||||
volumes:
|
||||
- name: runner-vol
|
||||
persistentVolumeClaim:
|
||||
claimName: runner-pvc
|
||||
- name: container-vol
|
||||
persistentVolumeClaim:
|
||||
claimName: runner-pvc
|
||||
|
@ -20,7 +20,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: server
|
||||
image: git.0x7f.app/woj/woj-server:1.3.1-dev
|
||||
image: git.0x7f.app/woj/woj-server:1.3.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- server
|
||||
|
@ -1,4 +0,0 @@
|
||||
// watch: https://github.com/golang/go/issues/42965
|
||||
|
||||
module ignore_me
|
||||
go 1.22.0
|
2
resource/runner/.gitignore
vendored
2
resource/runner/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
# docker image mark
|
||||
.mark.*
|
||||
# other tmp files
|
||||
*.zip
|
||||
|
3
resource/runner/framework/rootfs/.gitignore
vendored
3
resource/runner/framework/rootfs/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/full
|
||||
/run
|
||||
*.tar
|
3
resource/runner/framework/scripts/.gitignore
vendored
3
resource/runner/framework/scripts/.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
# bin
|
||||
/libwoj_sandbox.so
|
||||
/woj_launcher
|
||||
/nsjail
|
||||
# source
|
||||
/woj-sandbox
|
||||
/nsjail-src
|
@ -1,43 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
|
||||
COLOR_RED="\e[0;31m"
|
||||
COLOR_GREEN="\e[0;32m"
|
||||
COLOR_NONE="\e[0m"
|
||||
function log_info() { echo -e "${COLOR_GREEN}$*${COLOR_NONE}" 1>&2; }
|
||||
function log_error() { echo -e "${COLOR_RED}$*${COLOR_NONE}" 1>&2; }
|
||||
rm -rf woj-sandbox
|
||||
git clone https://git.0x7f.app/WOJ/woj-sandbox.git >/dev/null 2>&1 || exit 1
|
||||
cd woj-sandbox && ./build_libseccomp.sh || exit 1
|
||||
|
||||
function build_woj_launcher {
|
||||
rm -rf woj-sandbox
|
||||
mkdir -p build && cd build || exit 1
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release || exit 1
|
||||
make -j || exit 1
|
||||
|
||||
git clone https://git.0x7f.app/WOJ/woj-sandbox.git woj-sandbox >/dev/null 2>&1 || { log_error "Failed to clone woj-sandbox"; exit 1; }
|
||||
cd woj-sandbox || { log_error "Failed to enter woj-sandbox"; exit 1; }
|
||||
./build_libseccomp.sh || { log_error "Failed to build libseccomp"; exit 1; }
|
||||
mkdir -p build || { log_error "Failed to create build directory"; exit 1; }
|
||||
cd build || { log_error "Failed to enter build directory"; exit 1; }
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release || { log_error "Failed to configure woj-sandbox"; exit 1; }
|
||||
make -j || { log_error "Failed to build woj-sandbox"; exit 1; }
|
||||
|
||||
cd ../..
|
||||
rm -f woj_launcher
|
||||
cp woj-sandbox/build/woj_launcher .
|
||||
rm -rf woj-sandbox
|
||||
}
|
||||
|
||||
function build_nsjail {
|
||||
rm -rf nsjail-src
|
||||
|
||||
git clone https://git.0x7f.app/woj/nsjail nsjail-src >/dev/null 2>&1 || { log_error "Failed to clone nsjail"; exit 1; }
|
||||
cd nsjail-src || { log_error "Failed to enter nsjail"; exit 1; }
|
||||
make -j || { log_error "Failed to build nsjail"; exit 1; }
|
||||
|
||||
cd ..
|
||||
rm -f nsjail
|
||||
cp nsjail-src/nsjail .
|
||||
rm -rf nsjail-src
|
||||
}
|
||||
|
||||
log_info "Building woj_launcher..."
|
||||
build_woj_launcher
|
||||
|
||||
log_info "Building nsjail..."
|
||||
build_nsjail
|
||||
cd ../..
|
||||
cp woj-sandbox/build/woj_launcher . || exit 1
|
||||
rm -rf woj-sandbox || exit 1
|
||||
|
@ -1,7 +1,7 @@
|
||||
include ${TEMPLATE}/go.mk ${TEMPLATE}/Judger.mk
|
||||
|
||||
compile:
|
||||
@env GOCACHE=$(GOCACHE) $(GO) build $(GO_BUILD_FLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG)
|
||||
@$(GO) build $(GO_BUILD_FLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG)
|
||||
|
||||
judge:
|
||||
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes
|
||||
|
@ -1,7 +0,0 @@
|
||||
include ${TEMPLATE}/pypy3.mk ${TEMPLATE}/Judger.mk
|
||||
|
||||
compile:
|
||||
@echo no need to compile
|
||||
|
||||
judge:
|
||||
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes
|
@ -1,7 +0,0 @@
|
||||
include ${TEMPLATE}/python3.mk ${TEMPLATE}/Judger.mk
|
||||
|
||||
compile:
|
||||
@echo no need to compile
|
||||
|
||||
judge:
|
||||
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes
|
@ -1,7 +0,0 @@
|
||||
include ${TEMPLATE}/rust.mk ${TEMPLATE}/Judger.mk
|
||||
|
||||
compile:
|
||||
@$(RUSTC) $(RUSTFLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG)
|
||||
|
||||
judge:
|
||||
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes
|
@ -1,3 +1,2 @@
|
||||
GO=/usr/bin/go
|
||||
GO=/usr/local/go/bin/go
|
||||
GO_BUILD_FLAGS=-trimpath
|
||||
GOCACHE=/tmp/go-build
|
@ -1 +0,0 @@
|
||||
NODEJS=/usr/bin/node
|
@ -1 +0,0 @@
|
||||
PYTHON=/usr/bin/pypy3
|
@ -1 +0,0 @@
|
||||
PYTHON=/usr/bin/python3
|
@ -1,2 +0,0 @@
|
||||
RUSTC = /usr/bin/rustc
|
||||
RUSTFLAGS = -C opt-level=2 -W warnings
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -1,46 +0,0 @@
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
#define LEN 1000
|
||||
|
||||
int a[LEN], c[LEN];
|
||||
|
||||
void clear(int a[]) {
|
||||
for (int i = 0; i < LEN; ++i) a[i] = 0;
|
||||
}
|
||||
|
||||
void print(int a[]) {
|
||||
int i;
|
||||
for (i = LEN - 1; i >= 1; --i)
|
||||
if (a[i] != 0) break;
|
||||
for (; i >= 0; --i) putchar(a[i] + '0');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void mul(int a[], int b, int c[]) {
|
||||
clear(c);
|
||||
for (int i = 0; i < LEN - 1; ++i) {
|
||||
c[i] += a[i] * b;
|
||||
if (c[i] >= 10) {
|
||||
c[i + 1] += c[i] / 10;
|
||||
c[i] %= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
clear(a), clear(c);
|
||||
scanf("%d", &n);
|
||||
|
||||
a[0] = 1;
|
||||
int *p1 = a, *p2 = c;
|
||||
|
||||
for (int i = 2; i <= n; ++i) {
|
||||
mul(p1, i, p2);
|
||||
std::swap(p1, p2);
|
||||
}
|
||||
|
||||
print(p1);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
n = int(input().strip())
|
||||
a = 1
|
||||
for i in range(1, n + 1):
|
||||
a *= i
|
||||
print(a)
|
@ -1,36 +0,0 @@
|
||||
use std::io;
|
||||
|
||||
// Powered by Github Copilot :)
|
||||
|
||||
fn factorial(n: u64) -> Vec<u64> {
|
||||
let mut result = vec![1];
|
||||
for i in 2..=n {
|
||||
let mut carry = 0;
|
||||
for num in &mut result {
|
||||
*num = *num * i + carry;
|
||||
carry = *num / 10;
|
||||
*num %= 10;
|
||||
}
|
||||
while carry > 0 {
|
||||
result.push(carry % 10);
|
||||
carry /= 10;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn print_factorial(result: Vec<u64>) {
|
||||
for num in result.iter().rev() {
|
||||
print!("{}", num);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
let n: u64 = input.trim().parse().unwrap();
|
||||
|
||||
let result = factorial(n);
|
||||
print_factorial(result);
|
||||
}
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "FCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "FCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "FCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "FCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "LCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "LCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "LCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "LCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -2,33 +2,13 @@
|
||||
"Languages": [
|
||||
{
|
||||
"Lang" : "c",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "cpp",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Judge:" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 2000, "MemoryLimit": 128, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "HCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}}
|
||||
}
|
||||
],
|
||||
"Tasks" : [
|
||||
|
@ -34,28 +34,12 @@
|
||||
"Judge" : {"Type": "custom", "Script": "custom.Makefile", "Cmp": ""},
|
||||
// 运行时配置:时间(ms) 内存(MB) 进/线程数目
|
||||
"Runtime": {
|
||||
// 编译阶段,可选,若缺失整个字段则替换为如下默认值
|
||||
"Compile": {
|
||||
"TimeLimit" : 60000,
|
||||
"MemoryLimit" : 256,
|
||||
// NProcLimit 为可选字段,不填默认为 0
|
||||
"NProcLimit" : 64,
|
||||
// WriteFileLimit 为可选字段,不填默认为 1
|
||||
"WriteFileLimit": 64
|
||||
},
|
||||
// 编译阶段,可选,默认值见下
|
||||
"Compile": {"TimeLimit": 60000, "MemoryLimit": 256, "NProcLimit": 64},
|
||||
// 运行阶段,必选
|
||||
"Run" : {
|
||||
"TimeLimit" : 1000,
|
||||
"MemoryLimit" : 16,
|
||||
// SoftMemoryLimit 为可选字段,不填默认为 MemoryLimit
|
||||
// SoftMemoryLimit 仅适用于运行时沙箱设置,实际判断内存超标时使用 MemoryLimit
|
||||
"SoftMemoryLimit": 16,
|
||||
"NProcLimit" : 1,
|
||||
// WriteFileLimit 为可选字段,不填默认为 1
|
||||
"WriteFileLimit" : 1
|
||||
},
|
||||
// 答案检查阶段,可选,规则与 Compile 相同
|
||||
"Check" : {"TimeLimit": 60000, "MemoryLimit": 128, "NProcLimit": 64, "WriteFileLimit": 16}
|
||||
"Run" : {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1},
|
||||
// 答案检查阶段,可选,默认值见下
|
||||
"Check" : {"TimeLimit": 60000, "MemoryLimit": 128, "NProcLimit": 64}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -67,40 +51,10 @@
|
||||
"Runtime": {
|
||||
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Lang" : "python3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {
|
||||
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Lang" : "pypy3",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {
|
||||
// pypy3 运行时内存常数开销大,A+B 问题内存至少给到 80 MB
|
||||
"Run": {"TimeLimit": 1000, "MemoryLimit": 80, "NProcLimit": 1}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Lang" : "rust",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {
|
||||
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Lang" : "go",
|
||||
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
|
||||
"Runtime": {
|
||||
// Go 运行时会申请大量内存与线程
|
||||
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0}
|
||||
}
|
||||
}
|
||||
],
|
||||
// 题目构建阶段,用于生成测试数据等,可选,规则与 Compile 相同
|
||||
"Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64, "WriteFileLimit": 1024},
|
||||
// 题目构建阶段,用于生成测试数据等,可选,默认值见下
|
||||
"Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64},
|
||||
// 评测点信息,总分应当为 100 分
|
||||
"Tasks" : [
|
||||
// 第一个评测点,分值 10 分,使用 ./data/{input,output}/1.{input,output} 为测试数据
|
||||
@ -115,7 +69,7 @@
|
||||
### 评测脚本
|
||||
|
||||
1. 默认评测脚本目前只支持 `c` 语言和 `cpp`,参见 `../../framework/template/default/{c,cpp}.Makefile`
|
||||
2. 自定义评测脚本参见 `./judge/custom.Makefile`
|
||||
2. 自定义评测脚本参见 `./judge/XYZ.Makefile`
|
||||
3. `prebuild.Makefile`: 题目初始化脚本,用于编译辅助程序、生成数据等。如果存在该文件,系统会在题目分发到判机后自动执行,否则跳过该步骤
|
||||
|
||||
## 注意事项
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user