Merge pull request #1542 from crawlab-team/develop

Develop
This commit is contained in:
Marvin Zhang
2025-01-19 17:20:37 +08:00
committed by GitHub
800 changed files with 56273 additions and 56561 deletions

2
.env.local Normal file
View File

@@ -0,0 +1,2 @@
CRAWLAB_TAG=develop
CRAWLAB_PORT=8082

View File

@@ -1,197 +0,0 @@
name: "Docker Image CI: crawlab (tencent)"
on:
push:
branches: [ develop, main ]
#pull_request:
# branches: [ main ]
release:
types: [ published ]
workflow_dispatch:
repository_dispatch:
types: [ docker-crawlab ]
env:
IMAGE_PATH_CRAWLAB_BACKEND: backend
IMAGE_PATH_CRAWLAB_FRONTEND: frontend
IMAGE_NAME_CRAWLAB: ccr.ccs.tencentyun.com/crawlab/crawlab
IMAGE_NAME_CRAWLAB_BACKEND: crawlabteam/crawlab-backend
IMAGE_NAME_CRAWLAB_FRONTEND: crawlabteam/crawlab-frontend
jobs:
setup:
runs-on: ubuntu-latest
outputs:
is_matched_backend: ${{ steps.check_changed_files.outputs.is_matched_backend }}
is_matched_frontend: ${{ steps.check_changed_files.outputs.is_matched_frontend }}
is_matched_dockerfile: ${{ steps.check_changed_files.outputs.is_matched_dockerfile }}
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v2
- name: Get changed files
id: changed_files
uses: tj-actions/changed-files@v18.7
- id: check_changed_files
name: Check changed files
run: |
# check changed files
is_matched_backend=0
is_matched_frontend=0
is_matched_dockerfile=0
for file in ${{ steps.changed_files.outputs.all_changed_files }}; do
if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_BACKEND}/.* ]]; then
file_backend=$file
is_matched_backend=1
fi
if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_FRONTEND}/.* ]]; then
file_frontend=$file
is_matched_frontend=1
fi
if [[ $file == Dockerfile ]]; then
file_dockerfile=$file
is_matched_dockerfile=1
fi
done
# set outputs
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
is_matched_backend=1
is_matched_frontend=1
is_matched_dockerfile=1
fi
echo "::set-output name=is_matched_backend::$is_matched_backend"
echo "::set-output name=is_matched_frontend::$is_matched_frontend"
echo "::set-output name=is_matched_dockerfile::$is_matched_dockerfile"
# echo outputs
echo "is_matched_backend=$is_matched_backend, file_backend=$file_backend"
echo "is_matched_frontend=$is_matched_frontend, file_frontend=$file_frontend"
echo "is_matched_dockerfile=$is_matched_dockerfile, file_dockerfile=$file_dockerfile"
- id: version
name: Get version
run: |
# Strip git ref prefix from version
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# Strip "v" prefix from tag name
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# Use Docker `latest` tag convention
[ "$VERSION" == "main" ] && VERSION=latest
echo "::set-output name=version::$VERSION"
build-backend:
needs: [ setup ]
if: needs.setup.outputs.is_matched_backend == '1'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v18.7
- name: Build image
run: |
cd $IMAGE_PATH_CRAWLAB_BACKEND
docker build . --file Dockerfile --tag image
- name: Log into registry
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Push image
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
IMAGE_NAME=$IMAGE_NAME_CRAWLAB_BACKEND
docker tag image $IMAGE_NAME:$IMAGE_VERSION
docker push $IMAGE_NAME:$IMAGE_VERSION
build-frontend:
needs: [ setup ]
if: needs.setup.outputs.is_matched_frontend == '1'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v18.7
- name: Build image
run: |
cd $IMAGE_PATH_CRAWLAB_FRONTEND
docker build . --file Dockerfile --tag image
- name: Log into registry
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Push image
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
IMAGE_NAME=$IMAGE_NAME_CRAWLAB_FRONTEND
docker tag image $IMAGE_NAME:$IMAGE_VERSION
docker push $IMAGE_NAME:$IMAGE_VERSION
build-crawlab:
if: ${{ always() }}
needs: [ setup, build-backend, build-frontend ]
runs-on: ubuntu-latest
services:
mongo:
image: mongo:4.2
ports:
- 27017:27017
steps:
- uses: actions/checkout@v2
- name: Update Dockerfile
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
if [[ $IMAGE_VERSION != "latest" ]]; then
for n in crawlab-backend crawlab-frontend; do
IMAGE_NAME=$n
sed -i "s/${IMAGE_NAME}:latest/${IMAGE_NAME}:${IMAGE_VERSION}/" Dockerfile
done
fi
- name: Build image
run: docker build . --file Dockerfile --tag image
- name: Test image
run: |
docker run --rm -d --name crawlab_master \
-e CRAWLAB_NODE_MASTER=true \
-e CRAWLAB_DEMO=true \
-e CRAWLAB_MONGO_HOST=localhost \
-e CRAWLAB_MONGO_PORT=27017 \
-p 8080:8080 \
--network host \
image
docker exec crawlab_master env
docker logs -f crawlab_master &
sleep 10
docker ps
cmd='curl http://localhost:8080/api/system-info -s'
echo "cmd: ${cmd}"
res=`${cmd}`
echo "res: ${res}"
if [[ $res =~ "success" ]]; then
:
else
exit 1
fi
docker stop crawlab_master
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.8'
- name: Test demo
run: |
pip install crawlab-demo
crawlab-demo validate
- name: Log into registry
run: echo ${{ secrets.DOCKER_TENCENT_PASSWORD }} | docker login -u ${{ secrets.DOCKER_TENCENT_USERNAME }} --password-stdin ccr.ccs.tencentyun.com
- name: Push image
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
IMAGE_ID=$IMAGE_NAME_CRAWLAB
docker tag image $IMAGE_ID:$IMAGE_VERSION
docker push $IMAGE_ID:$IMAGE_VERSION

View File

@@ -2,9 +2,7 @@ name: "Docker Image CI: crawlab"
on:
push:
branches: [ develop, main ]
#pull_request:
# branches: [ main ]
branches: [ develop, test, main ]
release:
types: [ published ]
workflow_dispatch:
@@ -14,61 +12,83 @@ on:
env:
IMAGE_PATH_CRAWLAB_BACKEND: backend
IMAGE_PATH_CRAWLAB_FRONTEND: frontend
IMAGE_NAME_CRAWLAB: crawlabteam/crawlab
IMAGE_NAME_CRAWLAB_BACKEND: crawlabteam/crawlab-backend
IMAGE_NAME_CRAWLAB_FRONTEND: crawlabteam/crawlab-frontend
GH_PKG_NAME_CRAWLAB_BASE: ${{ github.repository_owner }}/crawlab-base
GH_PKG_NAME_CRAWLAB_BACKEND: ${{ github.repository_owner }}/crawlab-backend
GH_PKG_NAME_CRAWLAB_FRONTEND: ${{ github.repository_owner }}/crawlab-frontend
GH_PKG_NAME_CRAWLAB: ${{ github.repository_owner }}/crawlab
IMAGE_NAME_CRAWLAB_BASE: ghcr.io/${{ github.repository_owner }}/crawlab-base
IMAGE_NAME_CRAWLAB_BACKEND: ghcr.io/${{ github.repository_owner }}/crawlab-backend
IMAGE_NAME_CRAWLAB_FRONTEND: ghcr.io/${{ github.repository_owner }}/crawlab-frontend
IMAGE_NAME_CRAWLAB_GH: ghcr.io/${{ github.repository_owner }}/crawlab
IMAGE_NAME_CRAWLAB_DOCKERHUB: crawlabteam/crawlab
IMAGE_NAME_CRAWLAB_TENCENT: ccr.ccs.tencentyun.com/crawlab/crawlab
E2E_TESTS_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/e2e-tests
E2E_TESTS_WORKSPACE: ${{ github.workspace }}/playwright-report
jobs:
setup:
name: Setup
runs-on: ubuntu-latest
outputs:
is_matched_backend: ${{ steps.check_changed_files.outputs.is_matched_backend }}
is_matched_frontend: ${{ steps.check_changed_files.outputs.is_matched_frontend }}
is_matched_dockerfile: ${{ steps.check_changed_files.outputs.is_matched_dockerfile }}
backend_changed: ${{ steps.check_changed_files.outputs.backend_changed }}
frontend_changed: ${{ steps.check_changed_files.outputs.frontend_changed }}
docker_changed: ${{ steps.check_changed_files.outputs.docker_changed }}
workflow_changed: ${{ steps.check_changed_files.outputs.workflow_changed }}
base_image_changed: ${{ steps.check_changed_files.outputs.base_image_changed }}
version: ${{ steps.version.outputs.version }}
test_script: ${{ steps.test_config.outputs.test_script }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Get changed files
id: changed_files
uses: tj-actions/changed-files@v18.7
uses: tj-actions/changed-files@v45
with:
files_yaml: |
backend:
- 'backend/**'
- 'core/**'
- 'fs/**'
- 'grpc/**'
- 'vcs/**'
- 'trace/**'
frontend:
- '${{ env.IMAGE_PATH_CRAWLAB_FRONTEND }}/**'
docker:
- 'Dockerfile'
- 'docker/bin/**'
- 'docker/nginx/**'
workflow:
- '.github/workflows/docker-crawlab.yml'
base_image:
- 'docker/base-image/**'
- id: check_changed_files
name: Check changed files
run: |
# check changed files
is_matched_backend=0
is_matched_frontend=0
is_matched_dockerfile=0
for file in ${{ steps.changed_files.outputs.all_changed_files }}; do
if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_BACKEND}/.* ]]; then
file_backend=$file
is_matched_backend=1
fi
if [[ $file =~ ^${IMAGE_PATH_CRAWLAB_FRONTEND}/.* ]]; then
file_frontend=$file
is_matched_frontend=1
fi
if [[ $file == Dockerfile ]]; then
file_dockerfile=$file
is_matched_dockerfile=1
fi
done
# set outputs
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
is_matched_backend=1
is_matched_frontend=1
is_matched_dockerfile=1
echo "backend_changed=true" >> $GITHUB_OUTPUT
echo "frontend_changed=true" >> $GITHUB_OUTPUT
echo "docker_changed=true" >> $GITHUB_OUTPUT
echo "workflow_changed=true" >> $GITHUB_OUTPUT
echo "base_image_changed=true" >> $GITHUB_OUTPUT
else
echo "backend_changed=${{ steps.changed_files.outputs.backend_any_changed }}" >> $GITHUB_OUTPUT
echo "frontend_changed=${{ steps.changed_files.outputs.frontend_any_changed }}" >> $GITHUB_OUTPUT
echo "docker_changed=${{ steps.changed_files.outputs.docker_any_changed }}" >> $GITHUB_OUTPUT
echo "workflow_changed=${{ steps.changed_files.outputs.workflow_any_changed }}" >> $GITHUB_OUTPUT
echo "base_image_changed=${{ steps.changed_files.outputs.base_image_any_changed }}" >> $GITHUB_OUTPUT
fi
echo "::set-output name=is_matched_backend::$is_matched_backend"
echo "::set-output name=is_matched_frontend::$is_matched_frontend"
echo "::set-output name=is_matched_dockerfile::$is_matched_dockerfile"
# echo outputs
echo "is_matched_backend=$is_matched_backend, file_backend=$file_backend"
echo "is_matched_frontend=$is_matched_frontend, file_frontend=$file_frontend"
echo "is_matched_dockerfile=$is_matched_dockerfile, file_dockerfile=$file_dockerfile"
# Display change status for each component
echo "Backend changed: ${{ steps.changed_files.outputs.backend_any_changed }}"
echo "Frontend changed: ${{ steps.changed_files.outputs.frontend_any_changed }}"
echo "Docker changed: ${{ steps.changed_files.outputs.docker_any_changed }}"
echo "Workflow changed: ${{ steps.changed_files.outputs.workflow_any_changed }}"
echo "Base image changed: ${{ steps.changed_files.outputs.base_image_any_changed }}"
- id: version
name: Get version
run: |
@@ -81,117 +101,270 @@ jobs:
# Use Docker `latest` tag convention
[ "$VERSION" == "main" ] && VERSION=latest
echo "::set-output name=version::$VERSION"
build-backend:
echo "version=$VERSION" >> $GITHUB_OUTPUT
- id: test_config
name: Set test configuration
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "test_script=test:full" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref }}" == "refs/heads/test" ]]; then
echo "test_script=test:extended" >> $GITHUB_OUTPUT
else
echo "test_script=test:normal" >> $GITHUB_OUTPUT
fi
build_base_image:
name: Build base image
needs: [ setup ]
if: needs.setup.outputs.is_matched_backend == '1'
if: needs.setup.outputs.base_image_changed == 'true' || needs.setup.outputs.workflow_changed == 'true'
runs-on: ubuntu-latest
outputs:
failed: ${{ steps.set_output.outputs.failed }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: ./docker/base-image
push: true
tags: ${{ env.IMAGE_NAME_CRAWLAB_BASE }}:${{ needs.setup.outputs.version }}
- name: Set output
id: set_output
if: failure()
run: echo "failed=true" >> $GITHUB_OUTPUT
test_backend:
name: Test backend
needs: [ setup ]
if: needs.setup.outputs.backend_changed == 'true' || needs.setup.outputs.workflow_changed == 'true'
runs-on: ubuntu-latest
outputs:
failed: ${{ steps.set_output.outputs.failed }}
services:
mongo:
image: mongo:5
ports:
- 27017:27017
strategy:
matrix:
package: [core]
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: '${{ matrix.package }}/go.mod'
cache-dependency-path: '${{ matrix.package }}/go.sum'
- name: Run tests
working-directory: ${{ matrix.package }}
run: |
# Find all directories containing *_test.go files
test_dirs=$(find . -name "*_test.go" -exec dirname {} \; | sort -u)
# Run go test on each directory
for dir in $test_dirs
do
echo "Running tests in $dir"
go test ./$dir
done
- name: Set output
id: set_output
if: failure()
run: echo "failed=true" >> $GITHUB_OUTPUT
build_backend:
name: Build backend
needs: [ setup, test_backend ]
if: needs.test_backend.result == 'success' || needs.setup.outputs.workflow_changed == 'true'
runs-on: ubuntu-latest
outputs:
failed: ${{ steps.set_output.outputs.failed }}
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
file: ${{ env.IMAGE_PATH_CRAWLAB_BACKEND }}/Dockerfile
push: true
tags: ${{ env.IMAGE_NAME_CRAWLAB_BACKEND }}:${{ needs.setup.outputs.version }}
- name: Set output
id: set_output
if: failure()
run: echo "failed=true" >> $GITHUB_OUTPUT
build_frontend:
name: Build frontend
needs: [ setup ]
if: needs.setup.outputs.frontend_changed == 'true' || needs.setup.outputs.workflow_changed == 'true'
runs-on: ubuntu-latest
outputs:
failed: ${{ steps.set_output.outputs.failed }}
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: ${{ env.IMAGE_PATH_CRAWLAB_FRONTEND }}
push: true
tags: ${{ env.IMAGE_NAME_CRAWLAB_FRONTEND }}:${{ needs.setup.outputs.version }}
- name: Set output
id: set_output
if: failure()
run: echo "failed=true" >> $GITHUB_OUTPUT
build_crawlab:
name: Build crawlab
needs: [setup, build_base_image, test_backend, build_backend, build_frontend]
if: |
always() &&
(
needs.test_backend.outputs.failed != 'true' &&
needs.build_backend.outputs.failed != 'true' &&
needs.build_frontend.outputs.failed != 'true' &&
needs.build_base_image.outputs.failed != 'true'
) &&
(
needs.setup.outputs.backend_changed == 'true' ||
needs.setup.outputs.frontend_changed == 'true' ||
needs.setup.outputs.docker_changed == 'true' ||
needs.setup.outputs.base_image_changed == 'true' ||
needs.setup.outputs.workflow_changed == 'true'
)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v18.7
- name: Build image
- uses: actions/checkout@v4
- name: Update Dockerfile
run: |
cd $IMAGE_PATH_CRAWLAB_BACKEND
docker build . --file Dockerfile --tag image
- name: Log into registry
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Push image
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
IMAGE_NAME=$IMAGE_NAME_CRAWLAB_BACKEND
docker tag image $IMAGE_NAME:$IMAGE_VERSION
docker push $IMAGE_NAME:$IMAGE_VERSION
IMAGE_NAMES=(
"crawlab-base"
"crawlab-backend"
"crawlab-frontend"
)
for name in "${IMAGE_NAMES[@]}"; do
IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/$name"
OLD_IMAGE="crawlabteam/${name}:"
NEW_IMAGE="${IMAGE_NAME}:"
sed -i "s|${OLD_IMAGE}|${NEW_IMAGE}|" Dockerfile
done
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
build-args: |
CRAWLAB_TAG=${{ needs.setup.outputs.version }}
push: true
tags: |
${{ env.IMAGE_NAME_CRAWLAB_GH }}:${{ needs.setup.outputs.version }}
build-frontend:
needs: [ setup ]
if: needs.setup.outputs.is_matched_frontend == '1'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v18.7
- name: Build image
run: |
cd $IMAGE_PATH_CRAWLAB_FRONTEND
docker build . --file Dockerfile --tag image
- name: Log into registry
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Push image
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
IMAGE_NAME=$IMAGE_NAME_CRAWLAB_FRONTEND
docker tag image $IMAGE_NAME:$IMAGE_VERSION
docker push $IMAGE_NAME:$IMAGE_VERSION
build-crawlab:
if: ${{ always() }}
needs: [ setup, build-backend, build-frontend ]
test_crawlab:
name: Test crawlab
needs: [setup, build_crawlab]
if: ${{ always() && needs.build_crawlab.result == 'success' }}
runs-on: ubuntu-latest
services:
mongo:
image: mongo:4.2
image: mongo:5
options: >-
--health-cmd "mongosh --eval 'db.adminCommand(\"ping\")' || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 5
master:
image: ghcr.io/${{ github.repository_owner }}/crawlab:${{ needs.setup.outputs.version }}
env:
CRAWLAB_NODE_MASTER: Y
CRAWLAB_MONGO_HOST: mongo
CRAWLAB_MONGO_PORT: 27017
ports:
- 27017:27017
- 8080:8080
worker:
image: ghcr.io/${{ github.repository_owner }}/crawlab:${{ needs.setup.outputs.version }}
env:
CRAWLAB_NODE_MASTER: N
CRAWLAB_MASTER_HOST: master
steps:
- uses: actions/checkout@v2
- name: Update Dockerfile
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
if [[ $IMAGE_VERSION != "latest" ]]; then
for n in crawlab-backend crawlab-frontend; do
IMAGE_NAME=$n
sed -i "s/${IMAGE_NAME}:latest/${IMAGE_NAME}:${IMAGE_VERSION}/" Dockerfile
done
fi
- name: Build image
run: docker build . --file Dockerfile --tag image
- name: Test image
run: |
docker run --rm -d --name crawlab_master \
-e CRAWLAB_NODE_MASTER=true \
-e CRAWLAB_DEMO=true \
-e CRAWLAB_MONGO_HOST=localhost \
-e CRAWLAB_MONGO_PORT=27017 \
-p 8080:8080 \
--network host \
image
docker exec crawlab_master env
docker logs -f crawlab_master &
sleep 10
docker ps
cmd='curl http://localhost:8080/api/system-info -s'
echo "cmd: ${cmd}"
res=`${cmd}`
echo "res: ${res}"
if [[ $res =~ "success" ]]; then
:
else
exit 1
fi
docker stop crawlab_master
- name: Set up Python
uses: actions/setup-python@v1
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
python-version: '3.8'
- name: Test demo
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull e2e test image
run: |
pip install crawlab-demo
crawlab-demo validate
- name: Log into registry
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Push image
docker pull ${{ env.E2E_TESTS_IMAGE_NAME }}:latest
- name: Run e2e test image
run: |
IMAGE_VERSION=${{needs.setup.outputs.version}}
IMAGE_ID=$IMAGE_NAME_CRAWLAB
docker tag image $IMAGE_ID:$IMAGE_VERSION
docker push $IMAGE_ID:$IMAGE_VERSION
docker run --network host \
-e BASE_URL=http://localhost:8080 \
-e TEST_SCRIPT=${{ needs.setup.outputs.test_script }} \
-v ${{ env.E2E_TESTS_WORKSPACE }}:/app/playwright-report \
${{ env.E2E_TESTS_IMAGE_NAME }}:latest
- name: Upload test results
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ needs.setup.outputs.version }}
path: ${{ env.E2E_TESTS_WORKSPACE }}
retention-days: 1
overwrite: true
push_images:
name: Push images
if: ${{ always() && needs.test_crawlab.result == 'success' }}
needs: [setup, test_crawlab]
runs-on: ubuntu-latest
strategy:
matrix:
registry: [dockerhub, tencent]
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull Docker image from GitHub Container Registry
run: docker pull ${{ env.IMAGE_NAME_CRAWLAB_GH }}:${{ needs.setup.outputs.version }}
- name: Login to DockerHub or Tencent Registry
uses: docker/login-action@v3
with:
registry: ${{ (matrix.registry == 'dockerhub' && 'https://index.docker.io/v1/') || (matrix.registry == 'tencent' && 'ccr.ccs.tencentyun.com') }}
username: ${{ (matrix.registry == 'dockerhub' && secrets.DOCKER_USERNAME) || (matrix.registry == 'tencent' && secrets.DOCKER_TENCENT_USERNAME) }}
password: ${{ (matrix.registry == 'dockerhub' && secrets.DOCKER_PASSWORD) || (matrix.registry == 'tencent' && secrets.DOCKER_TENCENT_PASSWORD) }}
- name: Tag and push image
if: ${{ matrix.registry == 'dockerhub' || (matrix.registry == 'tencent' && github.ref != 'refs/heads/develop') }}
run: |
docker tag ${{ env.IMAGE_NAME_CRAWLAB_GH }}:${{ needs.setup.outputs.version }} ${{ (matrix.registry == 'dockerhub' && env.IMAGE_NAME_CRAWLAB_DOCKERHUB) || (matrix.registry == 'tencent' && env.IMAGE_NAME_CRAWLAB_TENCENT) }}:${{ needs.setup.outputs.version }}
docker push ${{ (matrix.registry == 'dockerhub' && env.IMAGE_NAME_CRAWLAB_DOCKERHUB) || (matrix.registry == 'tencent' && env.IMAGE_NAME_CRAWLAB_TENCENT) }}:${{ needs.setup.outputs.version }}

View File

@@ -1,21 +0,0 @@
name: Qodana
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
- develop
jobs:
qodana:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2024.1
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "frontend/packages/crawlab-ui"]
path = frontend/packages/crawlab-ui
url = git@github.com:crawlab-team/crawlab-ui.git

View File

@@ -1,30 +1,24 @@
FROM crawlabteam/crawlab-backend:latest AS backend-build
ARG CRAWLAB_TAG=latest
FROM crawlabteam/crawlab-frontend:latest AS frontend-build
FROM crawlabteam/crawlab-backend:${CRAWLAB_TAG} AS backend-build
FROM crawlabteam/crawlab-public-plugins:latest AS public-plugins-build
FROM crawlabteam/crawlab-frontend:${CRAWLAB_TAG} AS frontend-build
# images
FROM crawlabteam/crawlab-base:latest
FROM crawlabteam/crawlab-base:${CRAWLAB_TAG}
# add files
COPY ./backend/conf /app/backend/conf
COPY ./nginx /app/nginx
COPY ./bin /app/bin
# copy backend files
RUN mkdir -p /opt/bin
COPY --from=backend-build /go/bin/crawlab /opt/bin
RUN cp /opt/bin/crawlab /usr/local/bin/crawlab-server
# copy frontend files
# Copy files
COPY --from=backend-build /go/bin/crawlab /usr/local/bin/crawlab-server
COPY --from=frontend-build /app/dist /app/dist
COPY ./backend/conf /app/backend/conf
COPY ./docker/nginx/crawlab.conf /etc/nginx/conf.d
COPY ./docker/bin/docker-init.sh /app/bin/docker-init.sh
# copy public-plugins files
COPY --from=public-plugins-build /app/plugins /app/plugins
# copy nginx config files
COPY ./nginx/crawlab.conf /etc/nginx/conf.d
# start backend
# Start backend
CMD ["/bin/bash", "/app/bin/docker-init.sh"]
# Frontend port
EXPOSE 8080
# Healthcheck for backend
HEALTHCHECK --interval=1m --timeout=3s \
CMD curl -f http://localhost:8000/health || exit 1

View File

@@ -1,47 +0,0 @@
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "/tmp"
[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ../tmp/main ./ "
# Binary file yields from `cmd`.
bin = "../tmp/main"
# Customize binary.
full_bin = "../tmp/main master"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# Watch these directories if you specified.
include_dir = ["../libs"]
# Exclude files.
exclude_file = []
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms
[log]
# Show log time
time = false
[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"
[misc]
# Delete tmp directory on exit
clean_on_exit = true

View File

@@ -1,47 +0,0 @@
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "/tmp"
[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ../tmp/main ./ "
# Binary file yields from `cmd`.
bin = "../tmp/main"
# Customize binary.
full_bin = "../tmp/main worker"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# Watch these directories if you specified.
include_dir = ["../libs"]
# Exclude files.
exclude_file = []
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms
[log]
# Show log time
time = false
[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"
[misc]
# Delete tmp directory on exit
clean_on_exit = true

48
backend/.dockerignore Normal file
View File

@@ -0,0 +1,48 @@
# Go build artifacts
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
# Go workspace file
go.work
# IDE directories
.idea/
.vscode/
# Dependencies
vendor/
# Build output
bin/
dist/
# Debug files
debug/
# Environment files
.env
*.env
# System files
.DS_Store
Thumbs.db
# Test coverage
coverage.txt
*.cover
# Temporary files
*.tmp
*~
**/tmp
# Git directories
.git/
# Node modules
**/node_modules

View File

@@ -1,12 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[{*.yml, *.yaml, *.json}]
indent_size = 2

View File

@@ -1,15 +1,24 @@
FROM golang:1.18 AS build
FROM golang:1.22.9 AS build
# Context path is the root of the repository
WORKDIR /go/src/app
COPY . .
# Copy the current directory (backend) first
COPY ./backend ./backend/
# Copy required modules from relative paths
COPY ./core ./core/
COPY ./grpc ./grpc/
COPY ./trace ./trace/
COPY ./vcs ./vcs/
ENV GO111MODULE on
#ENV GOPROXY https://goproxy.io
RUN go mod tidy \
&& go install -v ./...
# Build from the backend directory which contains the main.go
RUN cd backend && go install -v ./...
FROM alpine:3.14
# copy files
# Copy the built binary
COPY --from=build /go/bin/crawlab /go/bin/crawlab

View File

@@ -1,3 +0,0 @@
# crawlab-backend
Backend (Golang) for Crawlab

View File

@@ -1,12 +0,0 @@
version: '3'
tasks:
dev:
desc: Switch to dev mode for local development.
cmds:
- cp -f go.mod.dev go.mod
deploy:
desc: Switch to deploy mode for code publish.
cmds:
- echo 'not implemented'

View File

@@ -1,446 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
set -o errexit -o nounset -o pipefail
NAT='0|[1-9][0-9]*'
ALPHANUM='[0-9]*[A-Za-z-][0-9A-Za-z-]*'
IDENT="$NAT|$ALPHANUM"
FIELD='[0-9A-Za-z-]+'
SEMVER_REGEX="\
^[vV]?\
($NAT)\\.($NAT)\\.($NAT)\
(\\-(${IDENT})(\\.(${IDENT}))*)?\
(\\+${FIELD}(\\.${FIELD})*)?$"
PROG=semver
PROG_VERSION="3.4.0"
USAGE="\
Usage:
$PROG bump major <version>
$PROG bump minor <version>
$PROG bump patch <version>
$PROG bump prerel|prerelease [<prerel>] <version>
$PROG bump build <build> <version>
$PROG bump release <version>
$PROG get major <version>
$PROG get minor <version>
$PROG get patch <version>
$PROG get prerel|prerelease <version>
$PROG get build <version>
$PROG get release <version>
$PROG compare <version> <other_version>
$PROG diff <version> <other_version>
$PROG validate <version>
$PROG --help
$PROG --version
Arguments:
<version> A version must match the following regular expression:
\"${SEMVER_REGEX}\"
In English:
-- The version must match X.Y.Z[-PRERELEASE][+BUILD]
where X, Y and Z are non-negative integers.
-- PRERELEASE is a dot separated sequence of non-negative integers and/or
identifiers composed of alphanumeric characters and hyphens (with
at least one non-digit). Numeric identifiers must not have leading
zeros. A hyphen (\"-\") introduces this optional part.
-- BUILD is a dot separated sequence of identifiers composed of alphanumeric
characters and hyphens. A plus (\"+\") introduces this optional part.
<other_version> See <version> definition.
<prerel> A string as defined by PRERELEASE above. Or, it can be a PRERELEASE
prototype string followed by a dot.
<build> A string as defined by BUILD above.
Options:
-v, --version Print the version of this tool.
-h, --help Print this help message.
Commands:
bump Bump by one of major, minor, patch; zeroing or removing
subsequent parts. \"bump prerel\" (or its synonym \"bump prerelease\")
sets the PRERELEASE part and removes any BUILD part. A trailing dot
in the <prerel> argument introduces an incrementing numeric field
which is added or bumped. If no <prerel> argument is provided, an
incrementing numeric field is introduced/bumped. \"bump build\" sets
the BUILD part. \"bump release\" removes any PRERELEASE or BUILD parts.
The bumped version is written to stdout.
get Extract given part of <version>, where part is one of major, minor,
patch, prerel (alternatively: prerelease), build, or release.
compare Compare <version> with <other_version>, output to stdout the
following values: -1 if <other_version> is newer, 0 if equal, 1 if
older. The BUILD part is not used in comparisons.
diff Compare <version> with <other_version>, output to stdout the
difference between two versions by the release type (MAJOR, MINOR,
PATCH, PRERELEASE, BUILD).
validate Validate if <version> follows the SEMVER pattern (see <version>
definition). Print 'valid' to stdout if the version is valid, otherwise
print 'invalid'.
See also:
https://semver.org -- Semantic Versioning 2.0.0"
function error {
echo -e "$1" >&2
exit 1
}
function usage_help {
error "$USAGE"
}
function usage_version {
echo -e "${PROG}: $PROG_VERSION"
exit 0
}
# normalize the "part" keywords to a canonical string. At present,
# only "prerelease" is normalized to "prerel".
function normalize_part {
if [ "$1" == "prerelease" ]
then
echo "prerel"
else
echo "$1"
fi
}
function validate_version {
local version=$1
if [[ "$version" =~ $SEMVER_REGEX ]]; then
# if a second argument is passed, store the result in var named by $2
if [ "$#" -eq "2" ]; then
local major=${BASH_REMATCH[1]}
local minor=${BASH_REMATCH[2]}
local patch=${BASH_REMATCH[3]}
local prere=${BASH_REMATCH[4]}
local build=${BASH_REMATCH[8]}
eval "$2=(\"$major\" \"$minor\" \"$patch\" \"$prere\" \"$build\")"
else
echo "$version"
fi
else
error "version $version does not match the semver scheme 'X.Y.Z(-PRERELEASE)(+BUILD)'. See help for more information."
fi
}
function is_nat {
[[ "$1" =~ ^($NAT)$ ]]
}
function is_null {
[ -z "$1" ]
}
function order_nat {
[ "$1" -lt "$2" ] && { echo -1 ; return ; }
[ "$1" -gt "$2" ] && { echo 1 ; return ; }
echo 0
}
function order_string {
[[ $1 < $2 ]] && { echo -1 ; return ; }
[[ $1 > $2 ]] && { echo 1 ; return ; }
echo 0
}
# given two (named) arrays containing NAT and/or ALPHANUM fields, compare them
# one by one according to semver 2.0.0 spec. Return -1, 0, 1 if left array ($1)
# is less-than, equal, or greater-than the right array ($2). The longer array
# is considered greater-than the shorter if the shorter is a prefix of the longer.
#
function compare_fields {
local l="$1[@]"
local r="$2[@]"
local leftfield=( "${!l}" )
local rightfield=( "${!r}" )
local left
local right
local i=$(( -1 ))
local order=$(( 0 ))
while true
do
[ $order -ne 0 ] && { echo $order ; return ; }
: $(( i++ ))
left="${leftfield[$i]}"
right="${rightfield[$i]}"
is_null "$left" && is_null "$right" && { echo 0 ; return ; }
is_null "$left" && { echo -1 ; return ; }
is_null "$right" && { echo 1 ; return ; }
is_nat "$left" && is_nat "$right" && { order=$(order_nat "$left" "$right") ; continue ; }
is_nat "$left" && { echo -1 ; return ; }
is_nat "$right" && { echo 1 ; return ; }
{ order=$(order_string "$left" "$right") ; continue ; }
done
}
# shellcheck disable=SC2206 # checked by "validate"; ok to expand prerel id's into array
function compare_version {
local order
validate_version "$1" V
validate_version "$2" V_
# compare major, minor, patch
local left=( "${V[0]}" "${V[1]}" "${V[2]}" )
local right=( "${V_[0]}" "${V_[1]}" "${V_[2]}" )
order=$(compare_fields left right)
[ "$order" -ne 0 ] && { echo "$order" ; return ; }
# compare pre-release ids when M.m.p are equal
local prerel="${V[3]:1}"
local prerel_="${V_[3]:1}"
local left=( ${prerel//./ } )
local right=( ${prerel_//./ } )
# if left and right have no pre-release part, then left equals right
# if only one of left/right has pre-release part, that one is less than simple M.m.p
[ -z "$prerel" ] && [ -z "$prerel_" ] && { echo 0 ; return ; }
[ -z "$prerel" ] && { echo 1 ; return ; }
[ -z "$prerel_" ] && { echo -1 ; return ; }
# otherwise, compare the pre-release id's
compare_fields left right
}
# render_prerel -- return a prerel field with a trailing numeric string
# usage: render_prerel numeric [prefix-string]
#
function render_prerel {
if [ -z "$2" ]
then
echo "${1}"
else
echo "${2}${1}"
fi
}
# extract_prerel -- extract prefix and trailing numeric portions of a pre-release part
# usage: extract_prerel prerel prerel_parts
# The prefix and trailing numeric parts are returned in "prerel_parts".
#
PREFIX_ALPHANUM='[.0-9A-Za-z-]*[.A-Za-z-]'
DIGITS='[0-9][0-9]*'
EXTRACT_REGEX="^(${PREFIX_ALPHANUM})*(${DIGITS})$"
function extract_prerel {
local prefix; local numeric;
if [[ "$1" =~ $EXTRACT_REGEX ]]
then # found prefix and trailing numeric parts
prefix="${BASH_REMATCH[1]}"
numeric="${BASH_REMATCH[2]}"
else # no numeric part
prefix="${1}"
numeric=
fi
eval "$2=(\"$prefix\" \"$numeric\")"
}
# bump_prerel -- return the new pre-release part based on previous pre-release part
# and prototype for bump
# usage: bump_prerel proto previous
#
function bump_prerel {
local proto; local prev_prefix; local prev_numeric;
# case one: no trailing dot in prototype => simply replace previous with proto
if [[ ! ( "$1" =~ \.$ ) ]]
then
echo "$1"
return
fi
proto="${1%.}" # discard trailing dot marker from prototype
extract_prerel "${2#-}" prerel_parts # extract parts of previous pre-release
# shellcheck disable=SC2154
prev_prefix="${prerel_parts[0]}"
prev_numeric="${prerel_parts[1]}"
# case two: bump or append numeric to previous pre-release part
if [ "$proto" == "+" ] # dummy "+" indicates no prototype argument provided
then
if [ -n "$prev_numeric" ]
then
: $(( ++prev_numeric )) # previous pre-release is already numbered, bump it
render_prerel "$prev_numeric" "$prev_prefix"
else
render_prerel 1 "$prev_prefix" # append starting number
fi
return
fi
# case three: set, bump, or append using prototype prefix
if [ "$prev_prefix" != "$proto" ]
then
render_prerel 1 "$proto" # proto not same pre-release; set and start at '1'
elif [ -n "$prev_numeric" ]
then
: $(( ++prev_numeric )) # pre-release is numbered; bump it
render_prerel "$prev_numeric" "$prev_prefix"
else
render_prerel 1 "$prev_prefix" # start pre-release at number '1'
fi
}
function command_bump {
local new; local version; local sub_version; local command;
command="$(normalize_part "$1")"
case $# in
2) case "$command" in
major|minor|patch|prerel|release) sub_version="+."; version=$2;;
*) usage_help;;
esac ;;
3) case "$command" in
prerel|build) sub_version=$2 version=$3 ;;
*) usage_help;;
esac ;;
*) usage_help;;
esac
validate_version "$version" parts
# shellcheck disable=SC2154
local major="${parts[0]}"
local minor="${parts[1]}"
local patch="${parts[2]}"
local prere="${parts[3]}"
local build="${parts[4]}"
case "$command" in
major) new="$((major + 1)).0.0";;
minor) new="${major}.$((minor + 1)).0";;
patch) new="${major}.${minor}.$((patch + 1))";;
release) new="${major}.${minor}.${patch}";;
prerel) new=$(validate_version "${major}.${minor}.${patch}-$(bump_prerel "$sub_version" "$prere")");;
build) new=$(validate_version "${major}.${minor}.${patch}${prere}+${sub_version}");;
*) usage_help ;;
esac
echo "$new"
exit 0
}
function command_compare {
local v; local v_;
case $# in
2) v=$(validate_version "$1"); v_=$(validate_version "$2") ;;
*) usage_help ;;
esac
set +u # need unset array element to evaluate to null
compare_version "$v" "$v_"
exit 0
}
function command_diff {
validate_version "$1" v1_parts
# shellcheck disable=SC2154
local v1_major="${v1_parts[0]}"
local v1_minor="${v1_parts[1]}"
local v1_patch="${v1_parts[2]}"
local v1_prere="${v1_parts[3]}"
local v1_build="${v1_parts[4]}"
validate_version "$2" v2_parts
# shellcheck disable=SC2154
local v2_major="${v2_parts[0]}"
local v2_minor="${v2_parts[1]}"
local v2_patch="${v2_parts[2]}"
local v2_prere="${v2_parts[3]}"
local v2_build="${v2_parts[4]}"
if [ "${v1_major}" != "${v2_major}" ]; then
echo "major"
elif [ "${v1_minor}" != "${v2_minor}" ]; then
echo "minor"
elif [ "${v1_patch}" != "${v2_patch}" ]; then
echo "patch"
elif [ "${v1_prere}" != "${v2_prere}" ]; then
echo "prerelease"
elif [ "${v1_build}" != "${v2_build}" ]; then
echo "build"
fi
}
# shellcheck disable=SC2034
function command_get {
local part version
if [[ "$#" -ne "2" ]] || [[ -z "$1" ]] || [[ -z "$2" ]]; then
usage_help
exit 0
fi
part="$1"
version="$2"
validate_version "$version" parts
local major="${parts[0]}"
local minor="${parts[1]}"
local patch="${parts[2]}"
local prerel="${parts[3]:1}"
local build="${parts[4]:1}"
local release="${major}.${minor}.${patch}"
part="$(normalize_part "$part")"
case "$part" in
major|minor|patch|release|prerel|build) echo "${!part}" ;;
*) usage_help ;;
esac
exit 0
}
function command_validate {
if [[ "$#" -ne "1" ]]; then
usage_help
fi
if [[ "$1" =~ $SEMVER_REGEX ]]; then
echo "valid"
else
echo "invalid"
fi
exit 0
}
case $# in
0) echo "Unknown command: $*"; usage_help;;
esac
case $1 in
--help|-h) echo -e "$USAGE"; exit 0;;
--version|-v) usage_version ;;
bump) shift; command_bump "$@";;
get) shift; command_get "$@";;
compare) shift; command_compare "$@";;
diff) shift; command_diff "$@";;
validate) shift; command_validate "$@";;
*) echo "Unknown arguments: $*"; usage_help;;
esac

View File

@@ -1,4 +0,0 @@
#!/bin/bash
go get -u github.com/crawlab-team/crawlab/core@main
go mod tidy

View File

@@ -1,17 +0,0 @@
#!/bin/sh
# update version type (major, minor, patch, prerelease)
update_version_type="prerelease"
if [ -n "$1" ]; then
update_version_type="$1"
fi
# current version
current_version=$(grep -oEi 'version: v([0-9\.?]+)' conf/config.yml | sed -E 's/version: v//g')
# next version
next_version=$(./bin/semver.sh bump $update_version_type $current_version)
# update next version to conf/config.yml
sed -i '' "s/version: v$current_version/version: v$next_version/g" conf/config.yml

5
backend/conf/config.yml Executable file → Normal file
View File

@@ -1,3 +1,2 @@
info:
edition: global.edition.community
version: v0.6.3
edition: global.edition.community
version: v0.7.0

View File

@@ -1,118 +1,88 @@
module crawlab
go 1.22
go 1.22.9
replace (
github.com/crawlab-team/crawlab/core => ../core
github.com/crawlab-team/crawlab/db => ../db
github.com/crawlab-team/crawlab/fs => ../fs
github.com/crawlab-team/crawlab/grpc => ../grpc
github.com/crawlab-team/crawlab/template-parser => ../template-parser
github.com/crawlab-team/crawlab/trace => ../trace
github.com/crawlab-team/crawlab/vcs => ../vcs
)
require github.com/crawlab-team/crawlab/core v0.0.0-20240614095218-7b4ee8399ab0
require github.com/crawlab-team/crawlab/core v0.0.0
require (
cloud.google.com/go/auth v0.7.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
)
require (
cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/Masterminds/semver v1.4.2 // indirect
github.com/Masterminds/sprig v2.16.0+incompatible // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/PuerkitoBio/goquery v1.8.0 // indirect
github.com/PuerkitoBio/goquery v1.9.2 // indirect
github.com/ReneKroon/ttlcache v1.7.0 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aokoli/goutils v1.0.1 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/apex/log v1.9.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/crawlab-team/crawlab/db v0.0.0-20240614095218-7b4ee8399ab0 // indirect
github.com/crawlab-team/crawlab/fs v0.0.0-20240614095218-7b4ee8399ab0 // indirect
github.com/crawlab-team/crawlab/grpc v0.0.0-20240614111723-e5b20af9a40b // indirect
github.com/crawlab-team/crawlab/template-parser v0.0.0-20240614095218-7b4ee8399ab0 // indirect
github.com/crawlab-team/crawlab/trace v0.0.0-20240614095218-7b4ee8399ab0 // indirect
github.com/crawlab-team/crawlab/vcs v0.0.0-20240614095218-7b4ee8399ab0 // indirect
github.com/crawlab-team/goseaweedfs v0.6.3 // indirect
github.com/denisenkom/go-mssqldb v0.11.0 // indirect
github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect
github.com/elastic/go-elasticsearch/v8 v8.14.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/crawlab-team/crawlab/grpc v0.0.0 // indirect
github.com/crawlab-team/crawlab/trace v0.0.0 // indirect
github.com/crawlab-team/crawlab/vcs v0.0.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/gin-gonic/gin v1.10.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.12.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // 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.14.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomarkdown/markdown v0.0.0-20241105142532-d03b89096d81 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.2.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/imroc/req v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.11.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.2.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.10.0 // indirect
github.com/jackc/pgx/v4 v4.15.0 // indirect
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lib/pq v1.10.4 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/matcornic/hermes/v2 v2.1.0 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.3 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/olekukonko/tablewriter v0.0.1 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 // indirect
github.com/robfig/cron/v3 v3.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/segmentio/fasthash v1.0.3 // indirect
github.com/segmentio/kafka-go v0.4.39 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
@@ -122,46 +92,40 @@ require (
github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/thoas/go-funk v0.9.1 // indirect
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/upper/db/v4 v4.6.0 // indirect
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 // indirect
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/ztrue/tracerr v0.4.0 // indirect
go.mongodb.org/mongo-driver v1.15.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/dig v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.20.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
go.mongodb.org/mongo-driver v1.15.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.31.0 // indirect
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/api v0.189.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -1,20 +0,0 @@
module crawlab
go 1.16
replace (
github.com/crawlab-team/crawlab/core => ../../crawlab-core
github.com/crawlab-team/crawlab-vcs => ../../crawlab-vcs
github.com/crawlab-team/crawlab/fs => ../../crawlab-fs
github.com/crawlab-team/crawlab/db => ../../crawlab-db
)
require (
github.com/apex/log v1.9.0
github.com/crawlab-team/crawlab/core v0.6.0-beta.20211230.1200
github.com/crawlab-team/crawlab/vcs v0.1.1
github.com/gin-gonic/gin v1.7.1
github.com/spf13/cobra v1.1.3
github.com/spf13/viper v1.7.1
go.uber.org/dig v1.10.0
)

View File

@@ -1,20 +0,0 @@
module crawlab
go 1.16
replace (
github.com/crawlab-team/crawlab/core => /libs/crawlab-team/crawlab-core
github.com/crawlab-team/crawlab-vcs => /libs/crawlab-team/crawlab-vcs
github.com/crawlab-team/crawlab/fs => /libs/crawlab-team/crawlab-fs
github.com/crawlab-team/crawlab/db => /libs/crawlab-team/crawlab-db
)
require (
github.com/apex/log v1.9.0
github.com/crawlab-team/crawlab/core v0.6.0-beta.20211230.1200
github.com/crawlab-team/crawlab/vcs v0.1.1
github.com/gin-gonic/gin v1.7.1
github.com/spf13/cobra v1.1.3
github.com/spf13/viper v1.7.1
go.uber.org/dig v1.10.0
)

View File

@@ -27,14 +27,18 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
@@ -53,41 +57,25 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY=
github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
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/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
github.com/ReneKroon/ttlcache v1.7.0 h1:8BkjFfrzVFXyrqnMtezAaJ6AHPSsVV10m6w28N/Fgkk=
github.com/ReneKroon/ttlcache v1.7.0/go.mod h1:8BGGzdumrIjWxdRx8zpK6L3oGMWvIXdvB2GD1cfvd+I=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
@@ -107,19 +95,17 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc=
github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/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/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -129,6 +115,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -139,26 +129,17 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
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/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crawlab-team/goseaweedfs v0.6.3 h1:f96H2QCLrZpof9na1mhIKouKrv8p32XRUyouSVm4YHU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA=
github.com/elastic/go-elasticsearch/v8 v8.14.0 h1:1ywU8WFReLLcxE1WJqii3hTtbPUE2hc38ZK/j4mMFow=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@@ -177,25 +158,21 @@ github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gavv/httpexpect/v2 v2.16.0 h1:Ty2favARiTYTOkCRZGX7ojXXjGyNAIohM1lZ3vqaEwI=
github.com/gavv/httpexpect/v2 v2.16.0/go.mod h1:uJLaO+hQ25ukBJtQi750PsztObHybNllN+t+MbbW8PY=
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@@ -209,15 +186,15 @@ github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXY
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -226,24 +203,16 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -281,6 +250,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomarkdown/markdown v0.0.0-20241105142532-d03b89096d81 h1:5lyLWsV+qCkoYqsKUDuycESh9DEIPVKN6iCFeL7ag50=
github.com/gomarkdown/markdown v0.0.0-20241105142532-d03b89096d81/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -297,8 +268,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
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/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -319,27 +288,30 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/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=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
@@ -350,6 +322,8 @@ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@@ -371,71 +345,11 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U=
github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
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.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ=
github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
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=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
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.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
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.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38=
github.com/jackc/pgtype v1.10.0/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.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w=
github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw=
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.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ=
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -447,21 +361,18 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/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.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -469,24 +380,15 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/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.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
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=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
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/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/matcornic/hermes/v2 v2.1.0 h1:9TDYFBPFv6mcXanaDmRDEp/RTWj0dTTi+LpFnnnfNWc=
github.com/matcornic/hermes/v2 v2.1.0/go.mod h1:2+ziJeoyRfaLiATIL8VZ7f9hpzH4oDHqTmn0bhrsgVI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -494,22 +396,15 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -519,9 +414,6 @@ github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXx
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@@ -537,20 +429,15 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
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/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -575,10 +462,6 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 h1:ewTtJ72GFy2e0e8uyiDwMG3pKCS5mBh+hdSTYsPKEP8=
github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -586,11 +469,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
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=
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/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
@@ -598,37 +476,19 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/segmentio/kafka-go v0.4.39 h1:75smaomhvkYRwtuOwqLsdhgCG30B82NsbdkdDfFbvrw=
github.com/segmentio/kafka-go v0.4.39/go.mod h1:T0MLgygYvmqmBvC+s8aCcbVNfJN4znVne5j0Pzowp/Q=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
@@ -648,14 +508,10 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/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 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
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=
@@ -666,15 +522,12 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
@@ -682,25 +535,15 @@ github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/upper/db/v4 v4.6.0 h1:0VmASnqrl/XN8Ehoq++HBgZ4zRD5j3GXygW8FhP0C5I=
github.com/upper/db/v4 v4.6.0/go.mod h1:2mnRcPf+RcCXmVcD+o04LYlyu3UuF7ubamJia7CkN6s=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4=
github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0=
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 h1:L0rPdfzq43+NV8rfIx2kA4iSSLRj2jN5ijYHoeXRwvQ=
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w=
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe h1:9YnI5plmy+ad6BM+JCLJb2ZV7/TNiE5l7SNKfumYKgc=
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe/go.mod h1:JTFJA/t820uFDoyPpErFQ3rb3amdZoPtxcKervG0OE4=
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/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
@@ -709,40 +552,23 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw=
github.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4=
github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/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/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04=
github.com/ztrue/tracerr v0.4.0/go.mod h1:PaFfYlas0DfmXNpo7Eay4MFhZUONqvXM+T2HyGPpngk=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU=
go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -750,43 +576,35 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
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.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
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=
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/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY=
go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
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=
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/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/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/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029175232-7e6ffbd03851/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/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-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -794,18 +612,13 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
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-20210817164053-32db794688a5/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.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -816,8 +629,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -831,7 +644,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -847,9 +659,6 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -866,7 +675,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -893,15 +701,14 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -919,8 +726,8 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
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/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -934,8 +741,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
@@ -944,9 +751,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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=
golang.org/x/sys v0.0.0-20190225065934-cc5685c2db12/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -954,7 +759,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1000,7 +804,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1008,7 +811,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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=
@@ -1016,16 +818,19 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.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/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1039,8 +844,9 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1051,20 +857,15 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/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-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1072,7 +873,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1106,10 +906,6 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
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=
@@ -1146,6 +942,8 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1216,8 +1014,11 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1245,8 +1046,8 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
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=
@@ -1261,8 +1062,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
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.27.1/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.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
@@ -1275,14 +1076,9 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
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/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -1305,26 +1101,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
modernc.org/b v1.0.2/go.mod h1:fVGfCIzkZw5RsuF2A2WHbJmY7FiMIq30nP4s52uWsoY=
modernc.org/db v1.0.3/go.mod h1:L4ltUg8tu2pkSJk+fKaRrXs/3EdW79ZKYQ5PfVDT53U=
modernc.org/file v1.0.3/go.mod h1:CNj/pwOfCtCbqiHcXDUlHBB2vWrzdaDCWdcnjtS1+XY=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
modernc.org/internal v1.0.2/go.mod h1:bycJAcev709ZU/47nil584PeBD+kbu8nv61ozeMso9E=
modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk=
modernc.org/lldb v1.0.2/go.mod h1:ovbKqyzA9H/iPwHkAOH0qJbIQVT9rlijecenxDwVUi0=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/ql v1.4.0/go.mod h1:q4c29Bgdx+iAtxx47ODW5Xo2X0PDkjSCK9NdQl6KFxc=
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/zappy v1.0.3/go.mod h1:w/Akq8ipfols/xZJdR5IYiQNOqC80qz2mVvsEwEbkiI=
moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

View File

@@ -2,8 +2,20 @@ package main
import (
"github.com/crawlab-team/crawlab/core/cmd"
"github.com/crawlab-team/crawlab/core/config"
"github.com/crawlab-team/crawlab/core/utils"
)
func main() {
_ = cmd.Execute()
func init() {
config.InitConfig()
}
func main() {
go func() {
err := cmd.Execute()
if err != nil {
panic(err)
}
}()
utils.DefaultWait()
}

View File

@@ -1,10 +0,0 @@
{
"key": "master",
"is_master": true,
"name": "Master Node",
"ip": "",
"mac": "",
"hostname": "",
"description": "",
"auth_key": "Crawlab2021!"
}

View File

@@ -1,10 +0,0 @@
{
"key": "worker-01",
"is_master": false,
"name": "Worker Node 01",
"ip": "",
"mac": "",
"hostname": "",
"description": "",
"auth_key": "Crawlab2021!"
}

View File

@@ -1,10 +0,0 @@
{
"key": "worker-02",
"is_master": false,
"name": "Worker Node 02",
"ip": "",
"mac": "",
"hostname": "",
"description": "",
"auth_key": "Crawlab2021!"
}

View File

@@ -1,10 +0,0 @@
{
"key": "worker-03",
"is_master": false,
"name": "Worker Node 03",
"ip": "",
"mac": "",
"hostname": "",
"description": "",
"auth_key": "Crawlab2021!"
}

View File

@@ -1,10 +0,0 @@
{
"key": "worker-invalid-auth-key",
"is_master": false,
"name": "worker",
"ip": "",
"mac": "",
"hostname": "",
"description": "",
"auth_key": "invalid-auth-key"
}

View File

@@ -1,6 +0,0 @@
#!/bin/bash
# replace default api path to new one
python /app/bin/update_docker_js_api_address.py
crawlab-server server

119
core/apps/api.go Normal file
View File

@@ -0,0 +1,119 @@
package apps
import (
"context"
"errors"
"github.com/crawlab-team/crawlab/core/controllers"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/middlewares"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/gin-gonic/gin"
"net"
"net/http"
"sync"
"time"
)
func init() {
// set gin mode
gin.SetMode(utils.GetGinMode())
}
type Api struct {
// internals
app *gin.Engine
ln net.Listener
srv *http.Server
initialized bool
interfaces.Logger
}
func (app *Api) Init() {
// skip if already initialized
if app.initialized {
return
}
// initialize middlewares
_ = app.initModuleWithApp("middlewares", middlewares.InitMiddlewares)
// initialize routes
_ = app.initModuleWithApp("routes", controllers.InitRoutes)
// set initialized
app.initialized = true
}
func (app *Api) Start() {
// address
address := utils.GetServerAddress()
// http server
app.srv = &http.Server{
Handler: app.app,
Addr: address,
}
// listen
var err error
app.ln, err = net.Listen("tcp", address)
if err != nil {
panic(err)
}
app.Infof("api server listening on %s", address)
// serve
if err := http.Serve(app.ln, app.app); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
app.Errorf("run api server error: %v", err)
} else {
app.Info("api server graceful down")
}
}
}
func (app *Api) Wait() {
utils.DefaultWait()
}
func (app *Api) Stop() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := app.srv.Shutdown(ctx); err != nil {
app.Errorf("shutdown api server error: %v", err)
}
}
func (app *Api) GetGinEngine() *gin.Engine {
return app.app
}
func (app *Api) GetHttpServer() *http.Server {
return app.srv
}
func (app *Api) initModuleWithApp(name string, fn func(app *gin.Engine) error) (err error) {
return initModule(name, func() error {
return fn(app.app)
})
}
func newApi() *Api {
api := &Api{
app: gin.New(),
Logger: utils.NewLogger("Api"),
}
api.Init()
return api
}
var api *Api
var apiOnce sync.Once
func GetApi() *Api {
apiOnce.Do(func() {
api = newApi()
})
return api
}

View File

@@ -1,122 +0,0 @@
package apps
import (
"context"
"errors"
"github.com/apex/log"
"github.com/crawlab-team/crawlab/core/controllers"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/middlewares"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
"net"
"net/http"
"time"
)
func init() {
// set gin mode
if viper.GetString("gin.mode") == "" {
gin.SetMode(gin.ReleaseMode)
} else {
gin.SetMode(viper.GetString("gin.mode"))
}
}
type ApiV2 struct {
// dependencies
interfaces.WithConfigPath
// internals
app *gin.Engine
ln net.Listener
srv *http.Server
ready bool
}
func (app *ApiV2) Init() {
// initialize middlewares
_ = app.initModuleWithApp("middlewares", middlewares.InitMiddlewares)
// initialize routes
_ = app.initModuleWithApp("routes", controllers.InitRoutes)
}
func (app *ApiV2) Start() {
// address
host := viper.GetString("server.host")
port := viper.GetString("server.port")
address := net.JoinHostPort(host, port)
// http server
app.srv = &http.Server{
Handler: app.app,
Addr: address,
}
// listen
var err error
app.ln, err = net.Listen("tcp", address)
if err != nil {
panic(err)
}
app.ready = true
// serve
if err := http.Serve(app.ln, app.app); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
log.Error("run server error:" + err.Error())
} else {
log.Info("server graceful down")
}
}
}
func (app *ApiV2) Wait() {
DefaultWait()
}
func (app *ApiV2) Stop() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := app.srv.Shutdown(ctx); err != nil {
log.Error("run server error:" + err.Error())
}
}
func (app *ApiV2) GetGinEngine() *gin.Engine {
return app.app
}
func (app *ApiV2) GetHttpServer() *http.Server {
return app.srv
}
func (app *ApiV2) Ready() (ok bool) {
return app.ready
}
func (app *ApiV2) initModuleWithApp(name string, fn func(app *gin.Engine) error) (err error) {
return initModule(name, func() error {
return fn(app.app)
})
}
func NewApiV2() *ApiV2 {
api := &ApiV2{
app: gin.New(),
}
api.Init()
return api
}
var apiV2 *ApiV2
func GetApiV2() *ApiV2 {
if apiV2 != nil {
return apiV2
}
apiV2 = NewApiV2()
return apiV2
}

View File

@@ -1,199 +0,0 @@
package apps
import (
"bufio"
"fmt"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/sys_exec"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/crawlab-team/crawlab/trace"
"github.com/imroc/req"
"github.com/spf13/viper"
"os"
"os/exec"
"strings"
"time"
)
type Docker struct {
// parent
parent ServerApp
// dependencies
interfaces.WithConfigPath
// seaweedfs log
fsLogFilePath string
fsLogFile *os.File
fsReady bool
}
func (app *Docker) Init() {
var err error
app.fsLogFile, err = os.OpenFile(app.fsLogFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.FileMode(0777))
if err != nil {
trace.PrintError(err)
}
// replace paths
if err := app.replacePaths(); err != nil {
panic(err)
}
// start nginx
go app.startNginx()
// start seaweedfs
go app.startSeaweedFs()
}
func (app *Docker) Start() {
// import demo
//if utils.IsDemo() && utils.InitializedDemo() {
// go app.importDemo()
//}
}
func (app *Docker) Wait() {
DefaultWait()
}
func (app *Docker) Stop() {
}
func (app *Docker) GetParent() (parent ServerApp) {
return app.parent
}
func (app *Docker) SetParent(parent ServerApp) {
app.parent = parent
}
func (app *Docker) Ready() (ok bool) {
return app.fsReady &&
app.parent.GetApi().Ready()
}
func (app *Docker) replacePaths() (err error) {
// read
indexHtmlPath := "/app/dist/index.html"
indexHtmlBytes, err := os.ReadFile(indexHtmlPath)
if err != nil {
return trace.TraceError(err)
}
indexHtml := string(indexHtmlBytes)
// replace paths
baseUrl := viper.GetString("base.url")
if baseUrl != "" {
indexHtml = app._replacePath(indexHtml, "js", baseUrl)
indexHtml = app._replacePath(indexHtml, "css", baseUrl)
indexHtml = app._replacePath(indexHtml, "<link rel=\"stylesheet\" href=\"", baseUrl)
indexHtml = app._replacePath(indexHtml, "<link rel=\"stylesheet\" href=\"", baseUrl)
indexHtml = app._replacePath(indexHtml, "window.VUE_APP_API_BASE_URL = '", baseUrl)
}
// replace path of baidu tongji
initBaiduTongji := viper.GetString("string")
if initBaiduTongji != "" {
indexHtml = strings.ReplaceAll(indexHtml, "window.VUE_APP_INIT_BAIDU_TONGJI = ''", fmt.Sprintf("window.VUE_APP_INIT_BAIDU_TONGJI = '%s'", initBaiduTongji))
}
// replace path of umeng
initUmeng := viper.GetString("string")
if initUmeng != "" {
indexHtml = strings.ReplaceAll(indexHtml, "window.VUE_APP_INIT_UMENG = ''", fmt.Sprintf("window.VUE_APP_INIT_UMENG = '%s'", initUmeng))
}
// write
if err := os.WriteFile(indexHtmlPath, []byte(indexHtml), os.FileMode(0766)); err != nil {
return trace.TraceError(err)
}
return nil
}
func (app *Docker) _replacePath(text, path, baseUrl string) (res string) {
text = strings.ReplaceAll(text, path, fmt.Sprintf("%s/%s", baseUrl, path))
return text
}
func (app *Docker) startNginx() {
cmd := exec.Command("service", "nginx", "start")
sys_exec.ConfigureCmdLogging(cmd, func(scanner *bufio.Scanner) {
for scanner.Scan() {
line := fmt.Sprintf("[nginx] %s\n", scanner.Text())
_, _ = os.Stdout.WriteString(line)
}
})
if err := cmd.Run(); err != nil {
trace.PrintError(err)
}
}
func (app *Docker) startSeaweedFs() {
seaweedFsDataPath := "/data/seaweedfs"
if !utils.Exists(seaweedFsDataPath) {
_ = os.MkdirAll(seaweedFsDataPath, os.FileMode(0777))
}
cmd := exec.Command("weed", "server",
"-dir", "/data",
"-master.dir", seaweedFsDataPath,
"-volume.dir.idx", seaweedFsDataPath,
"-ip", "localhost",
"-volume.port", "9999",
"-volume.minFreeSpace", "1GiB",
"-filer",
)
sys_exec.ConfigureCmdLogging(cmd, func(scanner *bufio.Scanner) {
for scanner.Scan() {
line := fmt.Sprintf("[seaweedfs] %s\n", scanner.Text())
_, _ = app.fsLogFile.WriteString(line)
}
})
go func() {
if err := cmd.Run(); err != nil {
trace.PrintError(err)
}
}()
for {
_, err := req.Get("http://localhost:8888")
if err != nil {
time.Sleep(1 * time.Second)
continue
}
app.fsReady = true
return
}
}
func (app *Docker) importDemo() {
for {
if app.Ready() {
break
}
time.Sleep(1 * time.Second)
}
_ = utils.ImportDemo()
}
func NewDocker(svr ServerApp) *Docker {
dck := &Docker{
parent: svr,
fsLogFilePath: "/var/log/weed.log",
}
dck.Init()
return dck
}
var dck *Docker
func GetDocker(svr ServerApp) *Docker {
if dck != nil {
return dck
}
dck = NewDocker(svr)
return dck
}

View File

@@ -1,39 +1,8 @@
package apps
import (
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/gin-gonic/gin"
"net/http"
)
type App interface {
Init()
Start()
Wait()
Stop()
}
type ApiApp interface {
App
GetGinEngine() (engine *gin.Engine)
GetHttpServer() (svr *http.Server)
Ready() (ok bool)
}
type NodeApp interface {
App
interfaces.WithConfigPath
}
type ServerApp interface {
NodeApp
GetApi() (api ApiApp)
GetNodeService() (masterSvc interfaces.NodeService)
}
type DockerApp interface {
App
GetParent() (parent NodeApp)
SetParent(parent NodeApp)
Ready() (ok bool)
}

99
core/apps/server.go Normal file
View File

@@ -0,0 +1,99 @@
package apps
import (
"fmt"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/node/service"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/spf13/viper"
"net/http"
_ "net/http/pprof"
"sync"
)
type Server struct {
// modules
nodeSvc interfaces.NodeService
api *Api
// internals
interfaces.Logger
}
func (app *Server) Init() {
// log node info
app.logNodeInfo()
// pprof
app.initPprof()
}
func (app *Server) Start() {
if utils.IsMaster() {
// start api
go start(app.api)
}
// start node service
go app.nodeSvc.Start()
}
func (app *Server) Wait() {
utils.DefaultWait()
}
func (app *Server) Stop() {
app.api.Stop()
}
func (app *Server) GetApi() *Api {
return app.api
}
func (app *Server) GetNodeService() interfaces.NodeService {
return app.nodeSvc
}
func (app *Server) logNodeInfo() {
app.Infof("current node type: %s", utils.GetNodeType())
}
func (app *Server) initPprof() {
if viper.GetBool("pprof") {
go func() {
fmt.Println(http.ListenAndServe("0.0.0.0:6060", nil))
}()
}
}
func newServer() App {
// server
svr := &Server{
Logger: utils.NewLogger("Server"),
}
// master modules
if utils.IsMaster() {
// api
svr.api = GetApi()
}
// node service
if utils.IsMaster() {
svr.nodeSvc = service.GetMasterService()
} else {
svr.nodeSvc = service.GetWorkerService()
}
return svr
}
var server App
var serverOnce sync.Once
func GetServer() App {
serverOnce.Do(func() {
server = newServer()
})
return server
}

View File

@@ -1,126 +0,0 @@
package apps
import (
"fmt"
"github.com/apex/log"
"github.com/crawlab-team/crawlab/core/config"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/node/service"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/spf13/viper"
"net/http"
_ "net/http/pprof"
)
type ServerV2 struct {
// settings
grpcAddress interfaces.Address
// dependencies
interfaces.WithConfigPath
// modules
nodeSvc interfaces.NodeService
api *ApiV2
dck *Docker
// internals
quit chan int
}
func (app *ServerV2) Init() {
// log node info
app.logNodeInfo()
// pprof
app.initPprof()
}
func (app *ServerV2) Start() {
if utils.IsMaster() {
// start docker app
if utils.IsDocker() {
go app.dck.Start()
}
// start api
go app.api.Start()
}
// start node service
go app.nodeSvc.Start()
}
func (app *ServerV2) Wait() {
<-app.quit
}
func (app *ServerV2) Stop() {
app.api.Stop()
app.quit <- 1
}
func (app *ServerV2) GetApi() ApiApp {
return app.api
}
func (app *ServerV2) GetNodeService() interfaces.NodeService {
return app.nodeSvc
}
func (app *ServerV2) logNodeInfo() {
log.Infof("current node type: %s", utils.GetNodeType())
if utils.IsDocker() {
log.Infof("running in docker container")
}
}
func (app *ServerV2) initPprof() {
if viper.GetBool("pprof") {
go func() {
fmt.Println(http.ListenAndServe("0.0.0.0:6060", nil))
}()
}
}
func NewServerV2() (app NodeApp) {
// server
svr := &ServerV2{
WithConfigPath: config.NewConfigPathService(),
quit: make(chan int, 1),
}
// master modules
if utils.IsMaster() {
// api
svr.api = GetApiV2()
// docker
if utils.IsDocker() {
svr.dck = GetDocker(svr)
}
}
// node service
var err error
if utils.IsMaster() {
svr.nodeSvc, err = service.GetMasterServiceV2()
} else {
svr.nodeSvc, err = service.GetWorkerServiceV2()
}
if err != nil {
panic(err)
}
return svr
}
var serverV2 NodeApp
func GetServerV2() NodeApp {
if serverV2 != nil {
return serverV2
}
serverV2 = NewServerV2()
return serverV2
}

View File

@@ -1,27 +1,11 @@
package apps
import (
"fmt"
"github.com/apex/log"
"github.com/crawlab-team/crawlab/core/color"
"github.com/crawlab-team/crawlab/core/config"
"github.com/crawlab-team/crawlab/core/container"
grpcclient "github.com/crawlab-team/crawlab/core/grpc/client"
grpcserver "github.com/crawlab-team/crawlab/core/grpc/server"
modelsclient "github.com/crawlab-team/crawlab/core/models/client"
modelsservice "github.com/crawlab-team/crawlab/core/models/service"
nodeconfig "github.com/crawlab-team/crawlab/core/node/config"
"github.com/crawlab-team/crawlab/core/schedule"
"github.com/crawlab-team/crawlab/core/spider/admin"
"github.com/crawlab-team/crawlab/core/stats"
"github.com/crawlab-team/crawlab/core/task/handler"
"github.com/crawlab-team/crawlab/core/task/scheduler"
taskstats "github.com/crawlab-team/crawlab/core/task/stats"
"github.com/crawlab-team/crawlab/core/user"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/crawlab-team/crawlab/trace"
)
var logger = utils.NewLogger("Apps")
func Start(app App) {
start(app)
}
@@ -33,59 +17,11 @@ func start(app App) {
app.Stop()
}
func DefaultWait() {
utils.DefaultWait()
}
func initModule(name string, fn func() error) (err error) {
if err := fn(); err != nil {
log.Error(fmt.Sprintf("init %s error: %s", name, err.Error()))
_ = trace.TraceError(err)
logger.Errorf("init %s error: %v", name, err)
panic(err)
}
log.Info(fmt.Sprintf("initialized %s successfully", name))
logger.Infof("initialized %s successfully", name)
return nil
}
func initApp(name string, app App) {
_ = initModule(name, func() error {
app.Init()
return nil
})
}
var injectors = []interface{}{
modelsservice.GetService,
modelsclient.NewServiceDelegate,
modelsclient.NewNodeServiceDelegate,
modelsclient.NewSpiderServiceDelegate,
modelsclient.NewTaskServiceDelegate,
modelsclient.NewTaskStatServiceDelegate,
modelsclient.NewEnvironmentServiceDelegate,
grpcclient.NewClient,
grpcclient.NewPool,
grpcserver.NewModelDelegateServer,
grpcserver.NewModelBaseServiceServer,
grpcserver.NewNodeServer,
grpcserver.NewTaskServer,
grpcserver.NewMessageServer,
config.NewConfigPathService,
user.GetUserService,
schedule.GetScheduleService,
admin.GetSpiderAdminService,
stats.GetStatsService,
nodeconfig.GetNodeConfigService,
taskstats.GetTaskStatsService,
color.NewService,
scheduler.GetTaskSchedulerService,
handler.GetTaskHandlerService,
}
func injectModules() {
c := container.GetContainer()
for _, injector := range injectors {
if err := c.Provide(injector); err != nil {
panic(err)
}
}
}

View File

@@ -23,11 +23,6 @@ func Execute() error {
return rootCmd.Execute()
}
// GetRootCmd get rootCmd instance
func GetRootCmd() *cobra.Command {
return rootCmd
}
func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "c", "", "Use Custom Config File")
}

View File

@@ -2,6 +2,7 @@ package cmd
import (
"github.com/crawlab-team/crawlab/core/apps"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/spf13/cobra"
)
@@ -15,8 +16,13 @@ var serverCmd = &cobra.Command{
Short: "Start Crawlab server",
Long: `Start Crawlab node server that can serve as API, task scheduler, task runner, etc.`,
Run: func(cmd *cobra.Command, args []string) {
// print logo if not pro
if !utils.IsPro() {
utils.PrintLogoWithWelcomeInfo()
}
// app
svr := apps.GetServerV2()
svr := apps.GetServer()
// start
apps.Start(svr)

View File

@@ -1,17 +0,0 @@
package cmd
import (
"github.com/crawlab-team/crawlab/core/apps"
"os"
"testing"
)
func TestCmdServer(t *testing.T) {
_ = os.Setenv("CRAWLAB_PPROF", "true")
// app
svr := apps.GetServerV2()
// start
apps.Start(svr)
}

View File

@@ -1,82 +0,0 @@
package color
import (
"encoding/hex"
"encoding/json"
"github.com/crawlab-team/crawlab/core/data"
"github.com/crawlab-team/crawlab/core/entity"
"github.com/crawlab-team/crawlab/core/errors"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/trace"
"math/rand"
"strconv"
"strings"
)
func NewService() (svc interfaces.ColorService, err error) {
var cl []*entity.Color
cm := map[string]*entity.Color{}
if err := json.Unmarshal([]byte(data.ColorsDataText), &cl); err != nil {
return nil, trace.TraceError(err)
}
for _, c := range cl {
cm[c.Name] = c
}
return &Service{
cl: cl,
cm: cm,
}, nil
}
type Service struct {
cl []*entity.Color
cm map[string]*entity.Color
}
func (svc *Service) Inject() (err error) {
return nil
}
func (svc *Service) GetByName(name string) (res interfaces.Color, err error) {
res, ok := svc.cm[name]
if !ok {
return res, errors.ErrorModelNotFound
}
return res, err
}
func (svc *Service) GetRandom() (res interfaces.Color, err error) {
if len(svc.cl) == 0 {
hexStr, err := svc.getRandomColorHex()
if err != nil {
return res, err
}
return &entity.Color{Hex: hexStr}, nil
}
idx := rand.Intn(len(svc.cl))
return svc.cl[idx], nil
}
func (svc *Service) getRandomColorHex() (res string, err error) {
n := 6
arr := make([]string, n)
for i := 0; i < n; i++ {
arr[i], err = svc.getRandomHexChar()
if err != nil {
return res, err
}
}
return strings.Join(arr, ""), nil
}
func (svc *Service) getRandomHexChar() (res string, err error) {
n := rand.Intn(16)
b := []byte(strconv.Itoa(n))
h := make([]byte, 1)
hex.Encode(h, b)
return string(h), nil
}

View File

@@ -1,21 +0,0 @@
package config
import (
"github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
"path/filepath"
)
var HomeDirPath, _ = homedir.Dir()
const configDirName = ".crawlab"
const configName = "config.json"
func GetConfigPath() string {
if viper.GetString("metadata") != "" {
MetadataPath := viper.GetString("metadata")
return filepath.Join(MetadataPath, configName)
}
return filepath.Join(HomeDirPath, configDirName, configName)
}

View File

@@ -1,47 +1,26 @@
package config
import (
"bytes"
"errors"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/utils"
"strings"
"sync"
"github.com/apex/log"
"github.com/crawlab-team/crawlab/trace"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"strings"
)
func init() {
// config instance
c := Config{Name: ""}
// init config file
if err := c.Init(); err != nil {
log.Warn("unable to init config")
return
}
// watch config change and load responsively
c.WatchConfig()
// init log level
c.initLogLevel()
}
type Config struct {
Name string
interfaces.Logger
}
type InitConfigOptions struct {
Name string
}
func (c *Config) Init() {
// Set default values
c.setDefaults()
func (c *Config) WatchConfig() {
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
log.Infof("Config file changed: %s", e.Name)
})
}
func (c *Config) Init() (err error) {
// config
if c.Name != "" {
viper.SetConfigFile(c.Name) // if config file is set, load it accordingly
@@ -51,30 +30,44 @@ func (c *Config) Init() (err error) {
}
// config type as yaml
viper.SetConfigType("yaml") // default yaml
viper.SetConfigType("yaml")
// auto env
viper.AutomaticEnv() // load matched environment variables
viper.AutomaticEnv()
// env prefix
viper.SetEnvPrefix("CRAWLAB") // environment variable prefix as CRAWLAB
viper.SetEnvPrefix("CRAWLAB")
// replacer
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
// read default config
defaultConfBuf := bytes.NewBufferString(DefaultConfigYaml)
if err := viper.ReadConfig(defaultConfBuf); err != nil {
return trace.TraceError(err)
// read in config
if err := viper.ReadInConfig(); err != nil {
var configFileNotFoundError viper.ConfigFileNotFoundError
if errors.As(err, &configFileNotFoundError) {
c.Warn("No config file found. Using default values.")
}
}
// merge config
if err := viper.MergeInConfig(); err != nil { // viper parsing config file
return err
}
// init log level
c.initLogLevel()
}
return nil
func (c *Config) WatchConfig() {
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
c.Infof("Config file changed: %s", e.Name)
})
}
func (c *Config) setDefaults() {
viper.SetDefault("mongo.host", "localhost")
viper.SetDefault("mongo.port", 27017)
viper.SetDefault("mongo.db", "crawlab_test")
viper.SetDefault("mongo.username", "")
viper.SetDefault("mongo.password", "")
viper.SetDefault("mongo.authSource", "admin")
}
func (c *Config) initLogLevel() {
@@ -86,3 +79,28 @@ func (c *Config) initLogLevel() {
}
log.SetLevel(l)
}
func newConfig() *Config {
return &Config{
Logger: utils.NewLogger("Config"),
}
}
var _config *Config
var _configOnce sync.Once
func GetConfig() *Config {
_configOnce.Do(func() {
_config = newConfig()
_config.Init()
})
return _config
}
func InitConfig() {
// config instance
c := GetConfig()
// watch config change and load responsively
c.WatchConfig()
}

View File

@@ -1,11 +1,64 @@
package config
import (
"github.com/stretchr/testify/require"
"os"
"path/filepath"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInitConfig(t *testing.T) {
err := InitConfig()
require.Nil(t, err)
func init() {
// Set test environment variables
viper.Set("CRAWLAB_TEST_STRING", "test_string_value")
viper.Set("CRAWLAB_TEST_INT", 42)
viper.Set("CRAWLAB_TEST_BOOL", true)
viper.Set("CRAWLAB_TEST_NESTED_KEY", "nested_value")
}
func TestInitConfig(t *testing.T) {
// Create a new Config instance
InitConfig()
// Test default values
assert.Equal(t, "localhost", viper.GetString("mongo.host"), "Unexpected default value for mongo.host")
assert.Equal(t, 27017, viper.GetInt("mongo.port"), "Unexpected default value for mongo.port")
assert.Equal(t, "crawlab_test", viper.GetString("mongo.db"), "Unexpected default value for mongo.db")
// Test environment variable override
os.Setenv("CRAWLAB_MONGO_HOST", "mongodb.example.com")
defer os.Unsetenv("CRAWLAB_MONGO_HOST")
assert.Equal(t, "mongodb.example.com", viper.GetString("mongo.host"), "Environment variable should override default value")
// Test with a config file
tempDir, err := os.MkdirTemp("", "crawlab-config-test")
require.NoError(t, err, "Failed to create temp directory")
defer os.RemoveAll(tempDir)
configContent := []byte(`
edition: global.edition.pro
mongo:
host: mongodb.custom.com
port: 27018
server:
port: 8001
`)
configPath := filepath.Join(tempDir, "config.yaml")
err = os.WriteFile(configPath, configContent, 0644)
require.NoError(t, err, "Failed to write config file")
// Remove the environment variable before testing with config file
os.Unsetenv("CRAWLAB_MONGO_HOST")
// Create a new Config instance with the config file
cWithFile := Config{Name: configPath}
cWithFile.Init()
// Test values from config file
assert.Equal(t, "global.edition.pro", viper.GetString("edition"), "Unexpected value for edition from config file")
assert.Equal(t, "mongodb.custom.com", viper.GetString("mongo.host"), "Unexpected value for mongo.host from config file")
assert.Equal(t, 27018, viper.GetInt("mongo.port"), "Unexpected value for mongo.port from config file")
assert.Equal(t, 8001, viper.GetInt("server.port"), "Unexpected value for server.port from config file")
}

View File

@@ -1,39 +0,0 @@
package config
var DefaultConfigYaml = `
version: v0.6.3
edition: global.edition.community
mongo:
host: localhost
port: 27017
db: crawlab_test
username: ""
password: ""
authSource: "admin"
server:
host: 0.0.0.0
port: 8000
spider:
fs: "/spiders"
workspace: "/workspace"
repo: "/repo"
task:
workers: 16
cancelWaitSeconds: 30
grpc:
address: localhost:9666
server:
address: 0.0.0.0:9666
authKey: Crawlab2021!
fs:
filer:
proxy: http://localhost:8888
url: http://localhost:8000/filer
authKey: Crawlab2021!
node:
master: Y
api:
endpoint: http://localhost:8000
log:
path: /var/log/crawlab
`

View File

@@ -1,23 +0,0 @@
package config
import (
"github.com/crawlab-team/crawlab/core/interfaces"
)
type PathService struct {
cfgPath string
}
func (svc *PathService) GetConfigPath() (path string) {
return svc.cfgPath
}
func (svc *PathService) SetConfigPath(path string) {
svc.cfgPath = path
}
func NewConfigPathService() (svc interfaces.WithConfigPath) {
svc = &PathService{}
svc.SetConfigPath(GetConfigPath())
return svc
}

View File

@@ -1,12 +0,0 @@
package config
import "strings"
const Version = "v0.6.3"
func GetVersion() (v string) {
if strings.HasPrefix(Version, "v") {
return Version
}
return "v" + Version
}

View File

@@ -1,8 +0,0 @@
package constants
const (
ActionTypeVisit = "visit"
ActionTypeInstallDep = "install_dep"
ActionTypeInstallLang = "install_lang"
ActionTypeViewDisclaimer = "view_disclaimer"
)

View File

@@ -1,8 +0,0 @@
package constants
const (
AnchorStartStage = "START_STAGE"
AnchorStartUrl = "START_URL"
AnchorItems = "ITEMS"
AnchorParsers = "PARSERS"
)

View File

@@ -1,7 +0,0 @@
package constants
const (
OwnerTypeAll = "all"
OwnerTypeMe = "me"
OwnerTypePublic = "public"
)

View File

@@ -1,8 +0,0 @@
package constants
const (
CacheColName = "cache"
CacheColKey = "k"
CacheColValue = "v"
CacheColTime = "t"
)

View File

@@ -1,9 +0,0 @@
package constants
const (
ChannelAllNode = "nodes:public"
ChannelWorkerNode = "nodes:"
ChannelMasterNode = "nodes:master"
)

View File

@@ -1,6 +0,0 @@
package constants
const (
EngineScrapy = "scrapy"
EngineColly = "colly"
)

View File

@@ -1,5 +0,0 @@
package constants
const (
DataCollectionKey = "_col"
)

View File

@@ -1,12 +0,0 @@
package constants
const (
DataFieldTypeGeneral = "general"
DataFieldTypeNumeric = "numeric"
DataFieldTypeDate = "date"
DataFieldTypeCurrency = "currency"
DataFieldTypeUrl = "url"
DataFieldTypeImage = "image"
DataFieldTypeAudio = "audio"
DataFieldTypeVideo = "video"
)

View File

@@ -1,5 +0,0 @@
package constants
const (
ColJob = "jobs"
)

View File

@@ -1 +0,0 @@
package constants

View File

@@ -0,0 +1,29 @@
package constants
const (
DependencyTypePython = "python"
DependencyTypeNode = "node"
DependencyTypeGo = "go"
DependencyTypeJava = "java"
DependencyTypeBrowser = "browser"
)
const (
DependencyStatusInstalling = "installing"
DependencyStatusInstalled = "installed"
DependencyStatusUninstalling = "uninstalling"
DependencyStatusUninstalled = "uninstalled"
DependencyStatusError = "error"
DependencyStatusAbnormal = "abnormal"
)
const (
DependencyFileTypeRequirementsTxt = "requirements.txt"
DependencyFileTypePackageJson = "package.json"
DependencyFileTypeGoMod = "go.mod"
DependencyFileTypePomXml = "pom.xml"
)
const (
DependencyActionSync = "sync"
DependencyActionSetup = "setup"
)

View File

@@ -1,31 +0,0 @@
package constants
const (
DataSourceTypeMongo = "mongo"
DataSourceTypeMysql = "mysql"
DataSourceTypePostgresql = "postgresql"
DataSourceTypeMssql = "mssql"
DataSourceTypeSqlite = "sqlite"
DataSourceTypeCockroachdb = "cockroachdb"
DataSourceTypeElasticSearch = "elasticsearch"
DataSourceTypeKafka = "kafka"
)
const (
DefaultHost = "localhost"
)
const (
DefaultMongoPort = "27017"
DefaultMysqlPort = "3306"
DefaultPostgresqlPort = "5432"
DefaultMssqlPort = "1433"
DefaultCockroachdbPort = "26257"
DefaultElasticsearchPort = "9200"
DefaultKafkaPort = "9092"
)
const (
DataSourceStatusOnline = "on"
DataSourceStatusOffline = "off"
)

View File

@@ -5,26 +5,10 @@ import (
)
var (
//ErrorMongoError = e.NewSystemOPError(1001, "system error:[mongo]%s", http.StatusInternalServerError)
//ErrorUserNotFound = e.NewBusinessError(10001, "user not found.", http.StatusUnauthorized)
//ErrorUsernameOrPasswordInvalid = e.NewBusinessError(11001, "username or password invalid", http.StatusUnauthorized)
ErrAlreadyExists = errors.New("already exists")
ErrNotExists = errors.New("not exists")
ErrForbidden = errors.New("forbidden")
ErrInvalidOperation = errors.New("invalid operation")
ErrInvalidOptions = errors.New("invalid options")
ErrNoTasksAvailable = errors.New("no tasks available")
ErrInvalidType = errors.New("invalid type")
ErrInvalidSignal = errors.New("invalid signal")
ErrEmptyValue = errors.New("empty value")
ErrTaskError = errors.New("task error")
ErrTaskLost = errors.New("task lost")
ErrTaskCancelled = errors.New("task cancelled")
ErrUnableToCancel = errors.New("unable to cancel")
ErrUnableToDispose = errors.New("unable to dispose")
ErrAlreadyDisposed = errors.New("already disposed")
ErrStopped = errors.New("stopped")
ErrMissingCol = errors.New("missing col")
ErrInvalidValue = errors.New("invalid value")
ErrInvalidCronSpec = errors.New("invalid cron spec")
ErrNotExists = errors.New("not exists")
ErrInvalidOptions = errors.New("invalid options")
ErrInvalidSignal = errors.New("invalid signal")
ErrTaskError = errors.New("task error")
ErrTaskLost = errors.New("task lost")
ErrTaskCancelled = errors.New("task cancelled")
)

View File

@@ -1,6 +0,0 @@
package constants
const (
GrpcEventServiceTypeRegister = "register"
GrpcEventServiceTypeSend = "send"
)

View File

@@ -1,5 +0,0 @@
package constants
const EmptyFileData = " "
const FsKeepFileName = ".gitkeep"

View File

@@ -1,5 +0,0 @@
package constants
const (
DefaultFilerAuthKey = "Crawlab2021!"
)

View File

@@ -3,12 +3,7 @@ package constants
const (
FilterQueryFieldConditions = "conditions"
FilterQueryFieldAll = "all"
)
const (
FilterObjectTypeString = "string"
FilterObjectTypeNumber = "number"
FilterObjectTypeBoolean = "boolean"
FilterQueryFieldFilter = "filter"
)
const (

View File

@@ -1,16 +1 @@
package constants
const (
GitAuthTypeHttp = "http"
GitAuthTypeSsh = "ssh"
)
const (
GitRemoteNameUpstream = "upstream"
GitRemoteNameOrigin = "origin"
)
const (
GitBranchMaster = "master"
GitBranchMain = "main"
)

View File

@@ -1,17 +0,0 @@
package constants
const (
DefaultGrpcServerHost = ""
DefaultGrpcServerPort = "9666"
DefaultGrpcClientRemoteHost = "localhost"
DefaultGrpcClientRemotePort = DefaultGrpcServerPort
DefaultGrpcAuthKey = "Crawlab2021!"
)
const (
GrpcHeaderAuthorization = "authorization"
)
const (
GrpcSubscribeTypeNode = "node"
)

View File

@@ -5,7 +5,3 @@ const (
HttpResponseMessageSuccess = "success"
HttpResponseMessageError = "error"
)
const (
HttpContentTypeApplicationJson = "application/json"
)

6
core/constants/ipc.go Normal file
View File

@@ -0,0 +1,6 @@
package constants
const (
IPCMessageData = "data" // IPCMessageData is the message type identifier for data messages
IPCMessageLog = "log" // IPCMessageLog is the message type identifier for log messages
)

View File

@@ -1,5 +0,0 @@
package constants
const (
ErrorRegexPattern = "(?:[ :,.]|^)((?:error|exception|traceback)s?)(?:[ :,.]|$)"
)

View File

@@ -1,9 +0,0 @@
package constants
const (
MsgTypeGetLog = "get-log"
MsgTypeGetSystemInfo = "get-sys-info"
MsgTypeCancelTask = "cancel-task"
MsgTypeRemoveLog = "remove-log"
MsgTypeRemoveSpider = "remove-spider"
)

View File

@@ -1,8 +1,6 @@
package constants
const (
NodeStatusUnregistered = "u"
NodeStatusRegistered = "r"
NodeStatusOnline = "on"
NodeStatusOffline = "off"
NodeStatusOnline = "on"
NodeStatusOffline = "off"
)

View File

@@ -1,8 +1,21 @@
package constants
const (
NotificationTriggerPatternTask = "^task"
NotificationTriggerPatternNode = "^node"
)
const (
NotificationTriggerTaskFinish = "task_finish"
NotificationTriggerTaskError = "task_error"
NotificationTriggerTaskEmptyResults = "task_empty_results"
NotificationTriggerTaskNever = "task_never"
NotificationTriggerNodeStatusChange = "node_status_change"
NotificationTriggerNodeOnline = "node_online"
NotificationTriggerNodeOffline = "node_offline"
NotificationTriggerAlert = "alert"
)
const (
NotificationTemplateModeRichText = "rich-text"
NotificationTemplateModeMarkdown = "markdown"
)

View File

@@ -1,8 +0,0 @@
package constants
const (
RegisterTypeMac = "mac"
RegisterTypeIp = "ip"
RegisterTypeHostname = "hostname"
RegisterTypeCustomName = "customName"
)

View File

@@ -1,10 +0,0 @@
package constants
const (
HashKey = "_h"
)
const (
DedupTypeIgnore = "ignore"
DedupTypeOverwrite = "overwrite"
)

View File

@@ -1,12 +0,0 @@
package constants
const (
RpcInstallLang = "install_lang"
RpcInstallDep = "install_dep"
RpcUninstallDep = "uninstall_dep"
RpcGetInstalledDepList = "get_installed_dep_list"
RpcGetLang = "get_lang"
RpcCancelTask = "cancel_task"
RpcGetSystemInfoService = "get_system_info"
RpcRemoveSpider = "remove_spider"
)

View File

@@ -1,10 +0,0 @@
package constants
const (
ScheduleStatusStop = "stopped"
ScheduleStatusRunning = "running"
ScheduleStatusError = "error"
ScheduleStatusErrorNotFoundNode = "Not Found Node"
ScheduleStatusErrorNotFoundSpider = "Not Found Spider"
)

View File

@@ -1,5 +0,0 @@
package constants
const ScrapyProtectedStageNames = ""
const ScrapyProtectedFieldNames = "_id,task_id,ts"

View File

@@ -1,5 +0,0 @@
package constants
const (
SignalQuit = iota
)

View File

@@ -1,25 +0,0 @@
package constants
const (
Windows = "windows"
Linux = "linux"
Darwin = "darwin"
)
const (
Python = "python"
Nodejs = "node"
Java = "java"
)
const (
InstallStatusNotInstalled = "not-installed"
InstallStatusInstalling = "installing"
InstallStatusInstallingOther = "installing-other"
InstallStatusInstalled = "installed"
)
const (
LangTypeLang = "lang"
LangTypeWebDriver = "webdriver"
)

View File

@@ -2,6 +2,7 @@ package constants
const (
TaskStatusPending = "pending"
TaskStatusAssigned = "assigned"
TaskStatusRunning = "running"
TaskStatusFinished = "finished"
TaskStatusError = "error"
@@ -15,11 +16,6 @@ const (
RunTypeSelectedNodes = "selected-nodes"
)
const (
TaskTypeSpider = "spider"
TaskTypeSystem = "system"
)
type TaskSignal int
const (
@@ -30,10 +26,6 @@ const (
)
const (
TaskListQueuePrefixPublic = "tasks:public"
TaskListQueuePrefixNodes = "tasks:nodes"
)
const (
TaskKey = "_tid"
TaskKey = "_tid"
SpiderKey = "_sid"
)

View File

@@ -1,9 +0,0 @@
package constants
const (
String = "string"
Number = "number"
Boolean = "boolean"
Array = "array"
Object = "object"
)

View File

@@ -1,11 +0,0 @@
package container
import (
"go.uber.org/dig"
)
var c = dig.New()
func GetContainer() *dig.Container {
return c
}

View File

@@ -1,69 +1,246 @@
package controllers
import "github.com/gin-gonic/gin"
const (
ControllerIdNode = iota << 1
ControllerIdProject
ControllerIdSpider
ControllerIdTask
ControllerIdJob
ControllerIdSchedule
ControllerIdUser
ControllerIdSetting
ControllerIdToken
ControllerIdVariable
ControllerIdTag
ControllerIdLogin
ControllerIdColor
ControllerIdDataSource
ControllerIdDataCollection
ControllerIdResult
ControllerIdStats
ControllerIdFiler
ControllerIdGit
ControllerIdRole
ControllerIdPermission
ControllerIdExport
ControllerIdNotification
ControllerIdFilter
ControllerIdEnvironment
ControllerIdSync
ControllerIdVersion
ControllerIdI18n
ControllerIdSystemInfo
ControllerIdDemo
import (
"errors"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/models/service"
"github.com/crawlab-team/crawlab/core/mongo"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
mongo2 "go.mongodb.org/mongo-driver/mongo"
)
type ControllerId int
type BasicController interface {
Get(c *gin.Context)
Post(c *gin.Context)
Put(c *gin.Context)
Delete(c *gin.Context)
}
type ListController interface {
BasicController
GetList(c *gin.Context)
PutList(c *gin.Context)
PostList(c *gin.Context)
DeleteList(c *gin.Context)
}
type Action struct {
Method string
Path string
HandlerFunc gin.HandlerFunc
}
type ActionController interface {
Actions() (actions []Action)
type BaseController[T any] struct {
modelSvc *service.ModelService[T]
actions []Action
}
type ListActionController interface {
ListController
ActionController
func (ctr *BaseController[T]) GetById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
model, err := ctr.modelSvc.GetById(id)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, model)
}
func (ctr *BaseController[T]) GetList(c *gin.Context) {
// get all if query field "all" is set true
all := MustGetFilterAll(c)
if all {
ctr.getAll(c)
return
}
// get list
ctr.getList(c)
}
func (ctr *BaseController[T]) Post(c *gin.Context) {
var model T
if err := c.ShouldBindJSON(&model); err != nil {
HandleErrorBadRequest(c, err)
return
}
u := GetUserFromContext(c)
m := any(&model).(interfaces.Model)
m.SetId(primitive.NewObjectID())
m.SetCreated(u.Id)
m.SetUpdated(u.Id)
col := ctr.modelSvc.GetCol()
res, err := col.GetCollection().InsertOne(col.GetContext(), m)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
result, err := ctr.modelSvc.GetById(res.InsertedID.(primitive.ObjectID))
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, result)
}
func (ctr *BaseController[T]) PutById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
var model T
if err := c.ShouldBindJSON(&model); err != nil {
HandleErrorBadRequest(c, err)
return
}
u := GetUserFromContext(c)
m := any(&model).(interfaces.Model)
m.SetUpdated(u.Id)
if err := ctr.modelSvc.ReplaceById(id, model); err != nil {
HandleErrorInternalServerError(c, err)
return
}
result, err := ctr.modelSvc.GetById(id)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, result)
}
func (ctr *BaseController[T]) PatchList(c *gin.Context) {
type Payload struct {
Ids []primitive.ObjectID `json:"ids"`
Update bson.M `json:"update"`
}
var payload Payload
if err := c.ShouldBindJSON(&payload); err != nil {
HandleErrorBadRequest(c, err)
return
}
// query
query := bson.M{
"_id": bson.M{
"$in": payload.Ids,
},
}
// update
if err := ctr.modelSvc.UpdateMany(query, bson.M{"$set": payload.Update}); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (ctr *BaseController[T]) DeleteById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
if err := ctr.modelSvc.DeleteById(id); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (ctr *BaseController[T]) DeleteList(c *gin.Context) {
type Payload struct {
Ids []string `json:"ids"`
}
var payload Payload
if err := c.ShouldBindJSON(&payload); err != nil {
HandleErrorBadRequest(c, err)
return
}
var ids []primitive.ObjectID
for _, id := range payload.Ids {
objectId, err := primitive.ObjectIDFromHex(id)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
ids = append(ids, objectId)
}
if err := ctr.modelSvc.DeleteMany(bson.M{
"_id": bson.M{
"$in": ids,
},
}); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (ctr *BaseController[T]) getAll(c *gin.Context) {
query := MustGetFilterQuery(c)
sort := MustGetSortOption(c)
if sort == nil {
sort = bson.D{{"_id", -1}}
}
models, err := ctr.modelSvc.GetMany(query, &mongo.FindOptions{
Sort: sort,
})
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
total, err := ctr.modelSvc.Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithListData(c, models, total)
}
func (ctr *BaseController[T]) getList(c *gin.Context) {
// params
pagination := MustGetPagination(c)
query := MustGetFilterQuery(c)
sort := MustGetSortOption(c)
// get list
models, err := ctr.modelSvc.GetMany(query, &mongo.FindOptions{
Sort: sort,
Skip: pagination.Size * (pagination.Page - 1),
Limit: pagination.Size,
})
if err != nil {
if errors.Is(err, mongo2.ErrNoDocuments) {
HandleSuccessWithListData(c, nil, 0)
} else {
HandleErrorInternalServerError(c, err)
}
return
}
// total count
total, err := ctr.modelSvc.Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// response
HandleSuccessWithListData(c, models, total)
}
func NewController[T any](actions ...Action) *BaseController[T] {
ctr := &BaseController[T]{
modelSvc: service.NewModelService[T](),
actions: actions,
}
return ctr
}

View File

@@ -3,21 +3,17 @@ package controllers
import (
"errors"
"fmt"
log2 "github.com/apex/log"
"github.com/crawlab-team/crawlab/core/fs"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
"io"
"os"
"path/filepath"
"sync"
)
func GetBaseFileListDir(rootPath string, c *gin.Context) {
path := c.Query("path")
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -37,7 +33,7 @@ func GetBaseFileListDir(rootPath string, c *gin.Context) {
func GetBaseFileFile(rootPath string, c *gin.Context) {
path := c.Query("path")
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -55,7 +51,7 @@ func GetBaseFileFile(rootPath string, c *gin.Context) {
func GetBaseFileFileInfo(rootPath string, c *gin.Context) {
path := c.Query("path")
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -71,7 +67,7 @@ func GetBaseFileFileInfo(rootPath string, c *gin.Context) {
}
func PostBaseFileSaveFile(rootPath string, c *gin.Context) {
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorInternalServerError(c, err)
return
@@ -121,7 +117,7 @@ func PostBaseFileSaveFile(rootPath string, c *gin.Context) {
}
func PostBaseFileSaveFiles(rootPath string, c *gin.Context) {
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorInternalServerError(c, err)
return
@@ -138,28 +134,28 @@ func PostBaseFileSaveFiles(rootPath string, c *gin.Context) {
go func(path string) {
file, err := c.FormFile(path)
if err != nil {
log2.Warnf("invalid file header: %s", path)
log2.Error(err.Error())
logger.Warnf("invalid file header: %s", path)
logger.Error(err.Error())
wg.Done()
return
}
f, err := file.Open()
if err != nil {
log2.Warnf("unable to open file: %s", path)
log2.Error(err.Error())
logger.Warnf("unable to open file: %s", path)
logger.Error(err.Error())
wg.Done()
return
}
fileData, err := io.ReadAll(f)
if err != nil {
log2.Warnf("unable to read file: %s", path)
log2.Error(err.Error())
logger.Warnf("unable to read file: %s", path)
logger.Error(err.Error())
wg.Done()
return
}
if err := fsSvc.Save(path, fileData); err != nil {
log2.Warnf("unable to save file: %s", path)
log2.Error(err.Error())
logger.Warnf("unable to save file: %s", path)
logger.Error(err.Error())
wg.Done()
return
}
@@ -182,7 +178,7 @@ func PostBaseFileSaveDir(rootPath string, c *gin.Context) {
return
}
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -206,7 +202,7 @@ func PostBaseFileRenameFile(rootPath string, c *gin.Context) {
return
}
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -230,7 +226,7 @@ func DeleteBaseFileFile(rootPath string, c *gin.Context) {
payload.Path = "."
}
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -258,7 +254,7 @@ func PostBaseFileCopyFile(rootPath string, c *gin.Context) {
return
}
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -273,7 +269,7 @@ func PostBaseFileCopyFile(rootPath string, c *gin.Context) {
}
func PostBaseFileExport(rootPath string, c *gin.Context) {
fsSvc, err := getBaseFileFsSvc(rootPath)
fsSvc, err := fs.GetBaseFileFsSvc(rootPath)
if err != nil {
HandleErrorBadRequest(c, err)
return
@@ -290,14 +286,3 @@ func PostBaseFileExport(rootPath string, c *gin.Context) {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", zipFilePath))
c.File(zipFilePath)
}
func GetBaseFileFsSvc(rootPath string) (svc interfaces.FsServiceV2, err error) {
return getBaseFileFsSvc(rootPath)
}
func getBaseFileFsSvc(rootPath string) (svc interfaces.FsServiceV2, err error) {
workspacePath := viper.GetString("workspace")
fsSvc := fs.NewFsServiceV2(filepath.Join(workspacePath, rootPath))
return fsSvc, nil
}

View File

@@ -8,13 +8,13 @@ import (
"github.com/crawlab-team/crawlab/core/middlewares"
"github.com/crawlab-team/crawlab/core/models/models"
"github.com/crawlab-team/crawlab/core/models/service"
"github.com/crawlab-team/crawlab/core/mongo"
"github.com/crawlab-team/crawlab/core/user"
"github.com/spf13/viper"
"net/http"
"net/http/httptest"
"testing"
"github.com/crawlab-team/crawlab/db/mongo"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
@@ -31,8 +31,8 @@ var TestToken string
// SetupTestDB sets up the test database
func SetupTestDB() {
viper.Set("mongo.db", "testdb")
modelSvc := service.NewModelServiceV2[models.UserV2]()
u := models.UserV2{
modelSvc := service.NewModelService[models.User]()
u := models.User{
Username: "admin",
}
id, err := modelSvc.InsertOne(u)
@@ -41,7 +41,7 @@ func SetupTestDB() {
}
u.SetId(id)
userSvc, err := user.GetUserServiceV2()
userSvc, err := user.GetUserService()
if err != nil {
panic(err)
}
@@ -63,20 +63,20 @@ func CleanupTestDB() {
mongo.GetMongoDb("testdb").Drop(context.Background())
}
func TestBaseControllerV2_GetById(t *testing.T) {
func TestBaseController_GetById(t *testing.T) {
SetupTestDB()
defer CleanupTestDB()
// Insert a test document
id, err := service.NewModelServiceV2[TestModel]().InsertOne(TestModel{Name: "test"})
id, err := service.NewModelService[TestModel]().InsertOne(TestModel{Name: "test"})
assert.NoError(t, err)
// Initialize the controller
ctr := controllers.NewControllerV2[TestModel]()
ctr := controllers.NewController[TestModel]()
// Set up the router
router := SetupRouter()
router.Use(middlewares.AuthorizationMiddlewareV2())
router.Use(middlewares.AuthorizationMiddleware())
router.GET("/testmodels/:id", ctr.GetById)
// Create a test request
@@ -96,16 +96,16 @@ func TestBaseControllerV2_GetById(t *testing.T) {
assert.Equal(t, "test", response.Data.Name)
}
func TestBaseControllerV2_Post(t *testing.T) {
func TestBaseController_Post(t *testing.T) {
SetupTestDB()
defer CleanupTestDB()
// Initialize the controller
ctr := controllers.NewControllerV2[TestModel]()
ctr := controllers.NewController[TestModel]()
// Set up the router
router := SetupRouter()
router.Use(middlewares.AuthorizationMiddlewareV2())
router.Use(middlewares.AuthorizationMiddleware())
router.POST("/testmodels", ctr.Post)
// Create a test request
@@ -127,25 +127,25 @@ func TestBaseControllerV2_Post(t *testing.T) {
assert.Equal(t, "test", response.Data.Name)
// Check if the document was inserted into the database
result, err := service.NewModelServiceV2[TestModel]().GetById(response.Data.Id)
result, err := service.NewModelService[TestModel]().GetById(response.Data.Id)
assert.NoError(t, err)
assert.Equal(t, "test", result.Name)
}
func TestBaseControllerV2_DeleteById(t *testing.T) {
func TestBaseController_DeleteById(t *testing.T) {
SetupTestDB()
defer CleanupTestDB()
// Insert a test document
id, err := service.NewModelServiceV2[TestModel]().InsertOne(TestModel{Name: "test"})
id, err := service.NewModelService[TestModel]().InsertOne(TestModel{Name: "test"})
assert.NoError(t, err)
// Initialize the controller
ctr := controllers.NewControllerV2[TestModel]()
ctr := controllers.NewController[TestModel]()
// Set up the router
router := SetupRouter()
router.Use(middlewares.AuthorizationMiddlewareV2())
router.Use(middlewares.AuthorizationMiddleware())
router.DELETE("/testmodels/:id", ctr.DeleteById)
// Create a test request
@@ -160,6 +160,6 @@ func TestBaseControllerV2_DeleteById(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code)
// Check if the document was deleted from the database
_, err = service.NewModelServiceV2[TestModel]().GetById(id)
_, err = service.NewModelService[TestModel]().GetById(id)
assert.Error(t, err)
}

View File

@@ -1,230 +0,0 @@
package controllers
import (
"errors"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/models/service"
"github.com/crawlab-team/crawlab/db/mongo"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
mongo2 "go.mongodb.org/mongo-driver/mongo"
)
type BaseControllerV2[T any] struct {
modelSvc *service.ModelServiceV2[T]
actions []Action
}
func (ctr *BaseControllerV2[T]) GetById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
model, err := ctr.modelSvc.GetById(id)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, model)
}
func (ctr *BaseControllerV2[T]) GetList(c *gin.Context) {
// get all if query field "all" is set true
all := MustGetFilterAll(c)
if all {
ctr.getAll(c)
return
}
// get list
ctr.getList(c)
}
func (ctr *BaseControllerV2[T]) Post(c *gin.Context) {
var model T
if err := c.ShouldBindJSON(&model); err != nil {
HandleErrorBadRequest(c, err)
return
}
u := GetUserFromContextV2(c)
m := any(&model).(interfaces.ModelV2)
m.SetId(primitive.NewObjectID())
m.SetCreated(u.Id)
m.SetUpdated(u.Id)
col := ctr.modelSvc.GetCol()
res, err := col.GetCollection().InsertOne(col.GetContext(), m)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
result, err := ctr.modelSvc.GetById(res.InsertedID.(primitive.ObjectID))
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, result)
}
func (ctr *BaseControllerV2[T]) PutById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
var model T
if err := c.ShouldBindJSON(&model); err != nil {
HandleErrorBadRequest(c, err)
return
}
u := GetUserFromContextV2(c)
m := any(&model).(interfaces.ModelV2)
m.SetUpdated(u.Id)
if err := ctr.modelSvc.ReplaceById(id, model); err != nil {
HandleErrorInternalServerError(c, err)
return
}
result, err := ctr.modelSvc.GetById(id)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, result)
}
func (ctr *BaseControllerV2[T]) PatchList(c *gin.Context) {
type Payload struct {
Ids []primitive.ObjectID `json:"ids"`
Update bson.M `json:"update"`
}
var payload Payload
if err := c.ShouldBindJSON(&payload); err != nil {
HandleErrorBadRequest(c, err)
return
}
// query
query := bson.M{
"_id": bson.M{
"$in": payload.Ids,
},
}
// update
if err := ctr.modelSvc.UpdateMany(query, bson.M{"$set": payload.Update}); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (ctr *BaseControllerV2[T]) DeleteById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
if err := ctr.modelSvc.DeleteById(id); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (ctr *BaseControllerV2[T]) DeleteList(c *gin.Context) {
type Payload struct {
Ids []primitive.ObjectID `json:"ids"`
}
var payload Payload
if err := c.ShouldBindJSON(&payload); err != nil {
HandleErrorBadRequest(c, err)
return
}
if err := ctr.modelSvc.DeleteMany(bson.M{
"_id": bson.M{
"$in": payload.Ids,
},
}); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (ctr *BaseControllerV2[T]) getAll(c *gin.Context) {
query := MustGetFilterQuery(c)
sort := MustGetSortOption(c)
if sort == nil {
sort = bson.D{{"_id", -1}}
}
models, err := ctr.modelSvc.GetMany(query, &mongo.FindOptions{
Sort: sort,
})
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
total, err := ctr.modelSvc.Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithListData(c, models, total)
}
func (ctr *BaseControllerV2[T]) getList(c *gin.Context) {
// params
pagination := MustGetPagination(c)
query := MustGetFilterQuery(c)
sort := MustGetSortOption(c)
// get list
models, err := ctr.modelSvc.GetMany(query, &mongo.FindOptions{
Sort: sort,
Skip: pagination.Size * (pagination.Page - 1),
Limit: pagination.Size,
})
if err != nil {
if errors.Is(err, mongo2.ErrNoDocuments) {
HandleSuccessWithListData(c, nil, 0)
} else {
HandleErrorInternalServerError(c, err)
}
return
}
// total count
total, err := ctr.modelSvc.Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// response
HandleSuccessWithListData(c, models, total)
}
func NewControllerV2[T any](actions ...Action) *BaseControllerV2[T] {
ctr := &BaseControllerV2[T]{
modelSvc: service.NewModelServiceV2[T](),
actions: actions,
}
return ctr
}

View File

@@ -1,14 +0,0 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/entity"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/gin-gonic/gin"
)
type BinderInterface interface {
Bind(c *gin.Context) (res interfaces.Model, err error)
BindList(c *gin.Context) (res []interfaces.Model, err error)
BindBatchRequestPayload(c *gin.Context) (payload entity.BatchRequestPayload, err error)
BindBatchRequestPayloadWithStringData(c *gin.Context) (payload entity.BatchRequestPayloadWithStringData, res interfaces.Model, err error)
}

View File

@@ -1,208 +0,0 @@
package controllers
import (
"encoding/json"
"github.com/crawlab-team/crawlab/core/entity"
"github.com/crawlab-team/crawlab/core/errors"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/models/models"
"github.com/gin-gonic/gin"
)
func NewJsonBinder(id ControllerId) (b *JsonBinder) {
return &JsonBinder{
id: id,
}
}
type JsonBinder struct {
id ControllerId
}
func (b *JsonBinder) Bind(c *gin.Context) (res interfaces.Model, err error) {
// declare
m := models.NewModelMap()
switch b.id {
case ControllerIdNode:
err = c.ShouldBindJSON(&m.Node)
return &m.Node, err
case ControllerIdProject:
err = c.ShouldBindJSON(&m.Project)
return &m.Project, err
case ControllerIdSpider:
err = c.ShouldBindJSON(&m.Spider)
return &m.Spider, err
case ControllerIdTask:
err = c.ShouldBindJSON(&m.Task)
return &m.Task, err
case ControllerIdJob:
err = c.ShouldBindJSON(&m.Job)
return &m.Job, err
case ControllerIdSchedule:
err = c.ShouldBindJSON(&m.Schedule)
return &m.Schedule, err
case ControllerIdUser:
err = c.ShouldBindJSON(&m.User)
return &m.User, nil
case ControllerIdSetting:
err = c.ShouldBindJSON(&m.Setting)
return &m.Setting, nil
case ControllerIdToken:
err = c.ShouldBindJSON(&m.Token)
return &m.Token, nil
case ControllerIdVariable:
err = c.ShouldBindJSON(&m.Variable)
return &m.Variable, nil
case ControllerIdTag:
err = c.ShouldBindJSON(&m.Tag)
return &m.Tag, nil
case ControllerIdDataSource:
err = c.ShouldBindJSON(&m.DataSource)
return &m.DataSource, nil
case ControllerIdDataCollection:
err = c.ShouldBindJSON(&m.DataCollection)
return &m.DataCollection, nil
case ControllerIdGit:
err = c.ShouldBindJSON(&m.Git)
return &m.Git, nil
case ControllerIdRole:
err = c.ShouldBindJSON(&m.Role)
return &m.Role, nil
case ControllerIdPermission:
err = c.ShouldBindJSON(&m.Permission)
return &m.Permission, nil
case ControllerIdEnvironment:
err = c.ShouldBindJSON(&m.Environment)
return &m.Environment, nil
default:
return nil, errors.ErrorControllerInvalidControllerId
}
}
func (b *JsonBinder) BindList(c *gin.Context) (res interface{}, err error) {
// declare
m := models.NewModelListMap()
// bind
switch b.id {
case ControllerIdNode:
err = c.ShouldBindJSON(&m.Nodes)
return m.Nodes, err
case ControllerIdProject:
err = c.ShouldBindJSON(&m.Projects)
return m.Projects, err
case ControllerIdSpider:
err = c.ShouldBindJSON(&m.Spiders)
return m.Spiders, err
case ControllerIdTask:
err = c.ShouldBindJSON(&m.Tasks)
return m.Tasks, err
case ControllerIdJob:
err = c.ShouldBindJSON(&m.Jobs)
return m.Jobs, err
case ControllerIdSchedule:
err = c.ShouldBindJSON(&m.Schedules)
return m.Schedules, err
case ControllerIdUser:
err = c.ShouldBindJSON(&m.Users)
return m.Users, nil
case ControllerIdSetting:
err = c.ShouldBindJSON(&m.Settings)
return m.Settings, nil
case ControllerIdToken:
err = c.ShouldBindJSON(&m.Tokens)
return m.Tokens, nil
case ControllerIdVariable:
err = c.ShouldBindJSON(&m.Variables)
return m.Variables, nil
case ControllerIdTag:
err = c.ShouldBindJSON(&m.Tags)
return m.Tags, nil
case ControllerIdDataSource:
err = c.ShouldBindJSON(&m.DataSources)
return m.DataSources, nil
case ControllerIdDataCollection:
err = c.ShouldBindJSON(&m.DataCollections)
return m.DataCollections, nil
case ControllerIdGit:
err = c.ShouldBindJSON(&m.Gits)
return m.Gits, nil
case ControllerIdRole:
err = c.ShouldBindJSON(&m.Roles)
return m.Roles, nil
case ControllerIdEnvironment:
err = c.ShouldBindJSON(&m.Environments)
return m.Environments, nil
default:
return nil, errors.ErrorControllerInvalidControllerId
}
}
func (b *JsonBinder) BindBatchRequestPayload(c *gin.Context) (payload entity.BatchRequestPayload, err error) {
if err := c.ShouldBindJSON(&payload); err != nil {
return payload, err
}
return payload, nil
}
func (b *JsonBinder) BindBatchRequestPayloadWithStringData(c *gin.Context) (payload entity.BatchRequestPayloadWithStringData, res interfaces.Model, err error) {
// declare
m := models.NewModelMap()
// bind
if err := c.ShouldBindJSON(&payload); err != nil {
return payload, nil, err
}
// validate
if len(payload.Ids) == 0 ||
len(payload.Fields) == 0 {
return payload, nil, errors.ErrorControllerRequestPayloadInvalid
}
// unmarshall
switch b.id {
case ControllerIdNode:
err = json.Unmarshal([]byte(payload.Data), &m.Node)
return payload, &m.Node, err
case ControllerIdProject:
err = json.Unmarshal([]byte(payload.Data), &m.Project)
return payload, &m.Project, err
case ControllerIdSpider:
err = json.Unmarshal([]byte(payload.Data), &m.Spider)
return payload, &m.Spider, err
case ControllerIdTask:
err = json.Unmarshal([]byte(payload.Data), &m.Task)
return payload, &m.Task, err
case ControllerIdJob:
err = json.Unmarshal([]byte(payload.Data), &m.Job)
return payload, &m.Job, err
case ControllerIdSchedule:
err = json.Unmarshal([]byte(payload.Data), &m.Schedule)
return payload, &m.Schedule, err
case ControllerIdUser:
err = json.Unmarshal([]byte(payload.Data), &m.User)
return payload, &m.User, err
case ControllerIdSetting:
err = json.Unmarshal([]byte(payload.Data), &m.Setting)
return payload, &m.Setting, err
case ControllerIdToken:
err = json.Unmarshal([]byte(payload.Data), &m.Token)
return payload, &m.Token, err
case ControllerIdVariable:
err = json.Unmarshal([]byte(payload.Data), &m.Variable)
return payload, &m.Variable, err
case ControllerIdDataSource:
err = json.Unmarshal([]byte(payload.Data), &m.DataSource)
return payload, &m.DataSource, err
case ControllerIdDataCollection:
err = json.Unmarshal([]byte(payload.Data), &m.DataCollection)
return payload, &m.DataCollection, err
case ControllerIdEnvironment:
err = json.Unmarshal([]byte(payload.Data), &m.Environment)
return payload, &m.Environment, err
default:
return payload, nil, errors.ErrorControllerInvalidControllerId
}
}

View File

@@ -1,120 +0,0 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/ds"
"github.com/crawlab-team/crawlab/core/errors"
"github.com/crawlab-team/crawlab/core/models/models"
"github.com/crawlab-team/crawlab/core/models/service"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func PostDataSource(c *gin.Context) {
// data source
var payload struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
Host string `json:"host"`
Port string `json:"port"`
Url string `json:"url"`
Hosts []string `json:"hosts"`
Database string `json:"database"`
Username string `json:"username"`
Password string `json:"-,omitempty"`
ConnectType string `json:"connect_type"`
Status string `json:"status"`
Error string `json:"error"`
Extra map[string]string `json:"extra,omitempty"`
}
if err := c.ShouldBindJSON(&payload); err != nil {
HandleErrorBadRequest(c, err)
return
}
u := GetUserFromContextV2(c)
// add data source to db
dataSource := models.DataSourceV2{
Name: payload.Name,
Type: payload.Type,
Description: payload.Description,
Host: payload.Host,
Port: payload.Port,
Url: payload.Url,
Hosts: payload.Hosts,
Database: payload.Database,
Username: payload.Username,
Password: payload.Password,
ConnectType: payload.ConnectType,
Status: payload.Status,
Error: payload.Error,
Extra: payload.Extra,
}
dataSource.SetCreated(u.Id)
dataSource.SetUpdated(u.Id)
id, err := service.NewModelServiceV2[models.DataSourceV2]().InsertOne(dataSource)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
dataSource.Id = id
// check data source status
go func() {
_ = ds.GetDataSourceServiceV2().CheckStatus(id)
}()
HandleSuccessWithData(c, dataSource)
}
func PutDataSourceById(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// data source
var dataSource models.DataSourceV2
if err := c.ShouldBindJSON(&dataSource); err != nil {
HandleErrorBadRequest(c, err)
return
}
err = service.NewModelServiceV2[models.DataSourceV2]().ReplaceById(id, dataSource)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// check data source status
go func() {
_ = ds.GetDataSourceServiceV2().CheckStatus(id)
}()
}
func PostDataSourceChangePassword(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
var payload struct {
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&payload); err != nil {
HandleErrorBadRequest(c, err)
return
}
if payload.Password == "" {
HandleErrorBadRequest(c, errors.ErrorDataSourceMissingRequiredFields)
return
}
u := GetUserFromContextV2(c)
if err := ds.GetDataSourceServiceV2().ChangePassword(id, payload.Password, u.Id); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}

View File

@@ -1,17 +0,0 @@
package controllers
func NewActionControllerDelegate(id ControllerId, actions []Action) (d *ActionControllerDelegate) {
return &ActionControllerDelegate{
id: id,
actions: actions,
}
}
type ActionControllerDelegate struct {
id ControllerId
actions []Action
}
func (ctr *ActionControllerDelegate) Actions() (actions []Action) {
return ctr.actions
}

View File

@@ -1,99 +0,0 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/errors"
"github.com/crawlab-team/crawlab/core/interfaces"
delegate2 "github.com/crawlab-team/crawlab/core/models/delegate"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
mongo2 "go.mongodb.org/mongo-driver/mongo"
)
func NewBasicControllerDelegate(id ControllerId, svc interfaces.ModelBaseService) (d *BasicControllerDelegate) {
return &BasicControllerDelegate{
id: id,
svc: svc,
}
}
type BasicControllerDelegate struct {
id ControllerId
svc interfaces.ModelBaseService
}
func (d *BasicControllerDelegate) Get(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
doc, err := d.svc.GetById(id)
if err == mongo2.ErrNoDocuments {
HandleErrorNotFound(c, err)
return
}
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, doc)
}
func (d *BasicControllerDelegate) Post(c *gin.Context) {
doc, err := NewJsonBinder(d.id).Bind(c)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
if err := delegate2.NewModelDelegate(doc, GetUserFromContext(c)).Add(); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, doc)
}
func (d *BasicControllerDelegate) Put(c *gin.Context) {
id, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
doc, err := NewJsonBinder(d.id).Bind(c)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
if doc.GetId() != id {
HandleErrorBadRequest(c, errors.ErrorHttpBadRequest)
return
}
_, err = d.svc.GetById(id)
if err != nil {
HandleErrorNotFound(c, err)
return
}
if err := delegate2.NewModelDelegate(doc, GetUserFromContext(c)).Save(); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccessWithData(c, doc)
}
func (d *BasicControllerDelegate) Delete(c *gin.Context) {
id := c.Param("id")
oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
doc, err := d.svc.GetById(oid)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
if err := delegate2.NewModelDelegate(doc, GetUserFromContext(c)).Delete(); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}

View File

@@ -1,222 +0,0 @@
package controllers
import (
"github.com/apex/log"
"github.com/crawlab-team/crawlab/core/errors"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/models/delegate"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/crawlab-team/crawlab/db/mongo"
"github.com/crawlab-team/crawlab/trace"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
mongo2 "go.mongodb.org/mongo-driver/mongo"
"reflect"
"time"
)
func NewListControllerDelegate(id ControllerId, svc interfaces.ModelBaseService) (d *ListControllerDelegate) {
if svc == nil {
panic(errors.ErrorControllerNoModelService)
}
return &ListControllerDelegate{
id: id,
svc: svc,
bc: NewBasicControllerDelegate(id, svc),
}
}
type ListControllerDelegate struct {
id ControllerId
svc interfaces.ModelBaseService
bc BasicController
}
func (d *ListControllerDelegate) Get(c *gin.Context) {
d.bc.Get(c)
}
func (d *ListControllerDelegate) Post(c *gin.Context) {
d.bc.Post(c)
}
func (d *ListControllerDelegate) Put(c *gin.Context) {
d.bc.Put(c)
}
func (d *ListControllerDelegate) Delete(c *gin.Context) {
d.bc.Delete(c)
}
func (d *ListControllerDelegate) GetList(c *gin.Context) {
// get all if query field "all" is set true
all := MustGetFilterAll(c)
if all {
d.getAll(c)
return
}
// get list and total
l, total, err := d.getList(c)
if err != nil {
return
}
// response
HandleSuccessWithListData(c, l, total)
}
func (d *ListControllerDelegate) PostList(c *gin.Context) {
// bind
docs, err := NewJsonBinder(d.id).BindList(c)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
// success ids
var ids []primitive.ObjectID
// reflect
switch reflect.TypeOf(docs).Kind() {
case reflect.Slice, reflect.Array:
s := reflect.ValueOf(docs)
for i := 0; i < s.Len(); i++ {
item := s.Index(i)
if !item.CanAddr() {
HandleErrorInternalServerError(c, errors.ErrorModelInvalidType)
return
}
ptr := item.Addr()
doc, ok := ptr.Interface().(interfaces.Model)
if !ok {
HandleErrorInternalServerError(c, errors.ErrorModelInvalidType)
return
}
if err := delegate.NewModelDelegate(doc, GetUserFromContext(c)).Add(); err != nil {
_ = trace.TraceError(err)
continue
}
ids = append(ids, doc.GetId())
}
}
// check
items, err := utils.GetArrayItems(docs)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
if len(ids) < len(items) {
HandleErrorInternalServerError(c, errors.ErrorControllerAddError)
return
}
// success
HandleSuccessWithData(c, docs)
}
func (d *ListControllerDelegate) PutList(c *gin.Context) {
payload, doc, err := NewJsonBinder(d.id).BindBatchRequestPayloadWithStringData(c)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
// query
query := bson.M{
"_id": bson.M{
"$in": payload.Ids,
},
}
// update
if err := d.svc.UpdateDoc(query, doc, payload.Fields); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (d *ListControllerDelegate) DeleteList(c *gin.Context) {
payload, err := NewJsonBinder(d.id).BindBatchRequestPayload(c)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
if err := d.svc.DeleteList(bson.M{
"_id": bson.M{
"$in": payload.Ids,
},
}); err != nil {
HandleErrorInternalServerError(c, err)
return
}
HandleSuccess(c)
}
func (d *ListControllerDelegate) getAll(c *gin.Context) {
// get list
tic := time.Now()
log.Debugf("getAll -> d.svc.GetMany:start")
list, err := d.svc.GetList(nil, &mongo.FindOptions{
Sort: bson.D{{"_id", -1}},
})
if err != nil {
if err == mongo2.ErrNoDocuments {
HandleErrorNotFound(c, err)
} else {
HandleErrorInternalServerError(c, err)
}
return
}
log.Debugf("getAll -> d.svc.GetMany:end. elapsed: %d ms", time.Now().Sub(tic).Milliseconds())
tic = time.Now()
// total count
tic = time.Now()
log.Debugf("getAll -> d.svc.Count:start")
total, err := d.svc.Count(nil)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
log.Debugf("getAll -> d.svc.Count:end. elapsed: %d ms", time.Now().Sub(tic).Milliseconds())
// response
HandleSuccessWithListData(c, list, total)
}
func (d *ListControllerDelegate) getList(c *gin.Context) (l interfaces.List, total int, err error) {
// params
pagination := MustGetPagination(c)
query := MustGetFilterQuery(c)
sort := MustGetSortOption(c)
// get list
l, err = d.svc.GetList(query, &mongo.FindOptions{
Sort: sort,
Skip: pagination.Size * (pagination.Page - 1),
Limit: pagination.Size,
})
if err != nil {
if err.Error() == mongo2.ErrNoDocuments.Error() {
HandleSuccessWithListData(c, nil, 0)
} else {
HandleErrorInternalServerError(c, err)
}
return
}
// total count
total, err = d.svc.Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
return l, total, nil
}

View File

@@ -1,17 +0,0 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/interfaces"
)
func NewListPostActionControllerDelegate(id ControllerId, svc interfaces.ModelBaseService, actions []Action) (d *ListActionControllerDelegate) {
return &ListActionControllerDelegate{
NewListControllerDelegate(id, svc),
NewActionControllerDelegate(id, actions),
}
}
type ListActionControllerDelegate struct {
ListController
ActionController
}

View File

@@ -1,57 +0,0 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/container"
"github.com/crawlab-team/crawlab/core/interfaces"
"github.com/crawlab-team/crawlab/core/models/service"
)
var EnvironmentController *environmentController
var EnvironmentActions []Action
type environmentController struct {
ListActionControllerDelegate
d ListActionControllerDelegate
ctx *environmentContext
}
type environmentContext struct {
modelSvc service.ModelService
userSvc interfaces.UserService
}
func newEnvironmentContext() *environmentContext {
// context
ctx := &environmentContext{}
// dependency injection
if err := container.GetContainer().Invoke(func(
modelSvc service.ModelService,
userSvc interfaces.UserService,
) {
ctx.modelSvc = modelSvc
ctx.userSvc = userSvc
}); err != nil {
panic(err)
}
return ctx
}
func newEnvironmentController() *environmentController {
modelSvc, err := service.GetService()
if err != nil {
panic(err)
}
ctr := NewListPostActionControllerDelegate(ControllerIdEnvironment, modelSvc.GetBaseService(interfaces.ModelIdEnvironment), EnvironmentActions)
d := NewListPostActionControllerDelegate(ControllerIdEnvironment, modelSvc.GetBaseService(interfaces.ModelIdEnvironment), EnvironmentActions)
ctx := newEnvironmentContext()
return &environmentController{
ListActionControllerDelegate: *ctr,
d: *d,
ctx: ctx,
}
}

View File

@@ -2,7 +2,7 @@ package controllers
import (
"github.com/crawlab-team/crawlab/core/entity"
"github.com/crawlab-team/crawlab/db/mongo"
"github.com/crawlab-team/crawlab/core/mongo"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
mongo2 "go.mongodb.org/mongo-driver/mongo"

View File

@@ -0,0 +1,18 @@
package controllers
import (
"github.com/gin-gonic/gin"
"net/http"
)
func GetHealthFn(healthFn func() bool) func(c *gin.Context) {
return func(c *gin.Context) {
if healthFn() {
c.Writer.Write([]byte("ok"))
c.AbortWithStatus(http.StatusOK)
return
}
c.Writer.Write([]byte("not ready"))
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -16,7 +16,7 @@ func PostLogin(c *gin.Context) {
HandleErrorBadRequest(c, err)
return
}
userSvc, err := user.GetUserServiceV2()
userSvc, err := user.GetUserService()
if err != nil {
HandleErrorInternalServerError(c, err)
return

View File

@@ -1,10 +1,10 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/errors"
"errors"
"github.com/crawlab-team/crawlab/core/models/models"
"github.com/crawlab-team/crawlab/core/models/service"
"github.com/crawlab-team/crawlab/db/mongo"
"github.com/crawlab-team/crawlab/core/mongo"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
@@ -15,7 +15,7 @@ func GetProjectList(c *gin.Context) {
// get all list
all := MustGetFilterAll(c)
if all {
NewControllerV2[models.ProjectV2]().getAll(c)
NewController[models.Project]().getAll(c)
return
}
@@ -25,7 +25,7 @@ func GetProjectList(c *gin.Context) {
sort := MustGetSortOption(c)
// get list
projects, err := service.NewModelServiceV2[models.ProjectV2]().GetMany(query, &mongo.FindOptions{
projects, err := service.NewModelService[models.Project]().GetMany(query, &mongo.FindOptions{
Sort: sort,
Skip: pagination.Size * (pagination.Page - 1),
Limit: pagination.Size,
@@ -37,12 +37,12 @@ func GetProjectList(c *gin.Context) {
return
}
if len(projects) == 0 {
HandleSuccessWithListData(c, []models.ProjectV2{}, 0)
HandleSuccessWithListData(c, []models.Project{}, 0)
return
}
// total count
total, err := service.NewModelServiceV2[models.ProjectV2]().Count(query)
total, err := service.NewModelService[models.Project]().Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
@@ -53,15 +53,13 @@ func GetProjectList(c *gin.Context) {
// count cache
cache := map[primitive.ObjectID]int{}
// iterate
for _, p := range projects {
ids = append(ids, p.Id)
cache[p.Id] = 0
}
// spiders
spiders, err := service.NewModelServiceV2[models.SpiderV2]().GetMany(bson.M{
spiders, err := service.NewModelService[models.Spider]().GetMany(bson.M{
"project_id": bson.M{
"$in": ids,
},
@@ -73,18 +71,16 @@ func GetProjectList(c *gin.Context) {
for _, s := range spiders {
_, ok := cache[s.ProjectId]
if !ok {
HandleErrorInternalServerError(c, errors.ErrorControllerMissingInCache)
HandleErrorInternalServerError(c, errors.New("project id not found"))
return
}
cache[s.ProjectId]++
}
// assign
var data []models.ProjectV2
for _, p := range projects {
p.Spiders = cache[p.Id]
data = append(data, p)
for i, p := range projects {
projects[i].Spiders = cache[p.Id]
}
HandleSuccessWithListData(c, data, total)
HandleSuccessWithListData(c, projects, total)
}

View File

@@ -1,119 +0,0 @@
package controllers
import (
"github.com/crawlab-team/crawlab/core/models/models"
"github.com/crawlab-team/crawlab/core/models/service"
"github.com/crawlab-team/crawlab/core/result"
"github.com/crawlab-team/crawlab/core/utils"
"github.com/crawlab-team/crawlab/db/generic"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
mongo2 "go.mongodb.org/mongo-driver/mongo"
)
func GetResultList(c *gin.Context) {
// data collection id
dcId, err := primitive.ObjectIDFromHex(c.Param("id"))
if err != nil {
HandleErrorBadRequest(c, err)
return
}
// data source id
var dsId primitive.ObjectID
dsIdStr := c.Query("data_source_id")
if dsIdStr != "" {
dsId, err = primitive.ObjectIDFromHex(dsIdStr)
if err != nil {
HandleErrorBadRequest(c, err)
return
}
}
// data collection
dc, err := service.NewModelServiceV2[models.DataCollectionV2]().GetById(dcId)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// data source
ds, err := service.NewModelServiceV2[models.DataSourceV2]().GetById(dsId)
if err != nil {
if err.Error() == mongo2.ErrNoDocuments.Error() {
ds = &models.DataSourceV2{}
} else {
HandleErrorInternalServerError(c, err)
return
}
}
// spider
sq := bson.M{
"col_id": dc.Id,
"data_source_id": ds.Id,
}
s, err := service.NewModelServiceV2[models.SpiderV2]().GetOne(sq, nil)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// service
svc, err := result.GetResultService(s.Id)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// params
pagination := MustGetPagination(c)
query := getResultListQuery(c)
// get results
data, err := svc.List(query, &generic.ListOptions{
Sort: []generic.ListSort{{"_id", generic.SortDirectionDesc}},
Skip: pagination.Size * (pagination.Page - 1),
Limit: pagination.Size,
})
if err != nil {
if err.Error() == mongo2.ErrNoDocuments.Error() {
HandleSuccessWithListData(c, nil, 0)
return
}
HandleErrorInternalServerError(c, err)
return
}
// validate results
if len(data) == 0 {
HandleSuccessWithListData(c, nil, 0)
return
}
// total count
total, err := svc.Count(query)
if err != nil {
HandleErrorInternalServerError(c, err)
return
}
// response
HandleSuccessWithListData(c, data, total)
}
func getResultListQuery(c *gin.Context) (q generic.ListQuery) {
f, err := GetFilter(c)
if err != nil {
return q
}
for _, cond := range f.Conditions {
q = append(q, generic.ListQueryCondition{
Key: cond.Key,
Op: cond.Op,
Value: utils.NormalizeObjectId(cond.Value),
})
}
return q
}

View File

@@ -1,25 +1,33 @@
package controllers
import (
"net/http"
"github.com/crawlab-team/crawlab/core/middlewares"
"github.com/crawlab-team/crawlab/core/models/models"
"github.com/gin-gonic/gin"
"net/http"
)
// RouterGroups defines the different authentication levels for API routes
type RouterGroups struct {
AuthGroup *gin.RouterGroup
AnonymousGroup *gin.RouterGroup
AuthGroup *gin.RouterGroup // Routes requiring full authentication
SyncAuthGroup *gin.RouterGroup // Routes for sync operations with special auth
AnonymousGroup *gin.RouterGroup // Public routes that don't require auth
}
// NewRouterGroups initializes the router groups with their respective middleware
func NewRouterGroups(app *gin.Engine) (groups *RouterGroups) {
return &RouterGroups{
AuthGroup: app.Group("/", middlewares.AuthorizationMiddlewareV2()),
AuthGroup: app.Group("/", middlewares.AuthorizationMiddleware()),
SyncAuthGroup: app.Group("/", middlewares.SyncAuthorizationMiddleware()),
AnonymousGroup: app.Group("/"),
}
}
func RegisterController[T any](group *gin.RouterGroup, basePath string, ctr *BaseControllerV2[T]) {
// RegisterController registers a generic controller with standard CRUD endpoints
// and any additional custom actions
func RegisterController[T any](group *gin.RouterGroup, basePath string, ctr *BaseController[T]) {
// Track registered paths to avoid duplicates
actionPaths := make(map[string]bool)
for _, action := range ctr.actions {
group.Handle(action.Method, basePath+action.Path, action.HandlerFunc)
@@ -36,12 +44,15 @@ func RegisterController[T any](group *gin.RouterGroup, basePath string, ctr *Bas
registerBuiltinHandler(group, http.MethodDelete, basePath+"", ctr.DeleteList, actionPaths)
}
// RegisterActions registers a list of custom action handlers to a route group
func RegisterActions(group *gin.RouterGroup, basePath string, actions []Action) {
for _, action := range actions {
group.Handle(action.Method, basePath+action.Path, action.HandlerFunc)
}
}
// registerBuiltinHandler registers a standard handler if it hasn't been overridden
// by a custom action
func registerBuiltinHandler(group *gin.RouterGroup, method, path string, handlerFunc gin.HandlerFunc, existingActionPaths map[string]bool) {
key := method + " - " + path
_, ok := existingActionPaths[key]
@@ -51,38 +62,25 @@ func registerBuiltinHandler(group *gin.RouterGroup, method, path string, handler
group.Handle(method, path, handlerFunc)
}
// InitRoutes configures all API routes for the application
func InitRoutes(app *gin.Engine) (err error) {
// routes groups
// Initialize route groups with different auth levels
groups := NewRouterGroups(app)
RegisterController(groups.AuthGroup, "/data/collections", NewControllerV2[models.DataCollectionV2]())
RegisterController(groups.AuthGroup, "/data-sources", NewControllerV2[models.DataSourceV2]([]Action{
{
Method: http.MethodPost,
Path: "",
HandlerFunc: PostDataSource,
},
{
Method: http.MethodPut,
Path: "/:id",
HandlerFunc: PutDataSourceById,
},
{
Method: http.MethodPost,
Path: "/:id/change-password",
HandlerFunc: PostDataSourceChangePassword,
},
}...))
RegisterController(groups.AuthGroup, "/environments", NewControllerV2[models.EnvironmentV2]())
RegisterController(groups.AuthGroup, "/nodes", NewControllerV2[models.NodeV2]())
RegisterController(groups.AuthGroup, "/projects", NewControllerV2[models.ProjectV2]([]Action{
// Register resource controllers with their respective endpoints
// Each RegisterController call sets up standard CRUD operations
// Additional custom actions can be specified in the controller initialization
RegisterController(groups.AuthGroup, "/data/collections", NewController[models.DataCollection]())
RegisterController(groups.AuthGroup, "/environments", NewController[models.Environment]())
RegisterController(groups.AuthGroup, "/nodes", NewController[models.Node]())
RegisterController(groups.AuthGroup, "/projects", NewController[models.Project]([]Action{
{
Method: http.MethodGet,
Path: "",
HandlerFunc: GetProjectList,
},
}...))
RegisterController(groups.AuthGroup, "/schedules", NewControllerV2[models.ScheduleV2]([]Action{
RegisterController(groups.AuthGroup, "/schedules", NewController[models.Schedule]([]Action{
{
Method: http.MethodPost,
Path: "",
@@ -103,8 +101,13 @@ func InitRoutes(app *gin.Engine) (err error) {
Path: "/:id/disable",
HandlerFunc: PostScheduleDisable,
},
{
Method: http.MethodPost,
Path: "/:id/run",
HandlerFunc: PostScheduleRun,
},
}...))
RegisterController(groups.AuthGroup, "/spiders", NewControllerV2[models.SpiderV2]([]Action{
RegisterController(groups.AuthGroup, "/spiders", NewController[models.Spider]([]Action{
{
Method: http.MethodGet,
Path: "/:id",
@@ -190,19 +193,13 @@ func InitRoutes(app *gin.Engine) (err error) {
Path: "/:id/run",
HandlerFunc: PostSpiderRun,
},
{
Method: http.MethodGet,
Path: "/:id/data-source",
HandlerFunc: GetSpiderDataSource,
},
{
Method: http.MethodPost,
Path: "/:id/data-source/:ds_id",
HandlerFunc: PostSpiderDataSource,
Path: "/:id/results",
HandlerFunc: GetSpiderResults,
},
}...))
RegisterController(groups.AuthGroup, "/tasks", NewControllerV2[models.TaskV2]([]Action{
RegisterController(groups.AuthGroup, "/tasks", NewController[models.Task]([]Action{
{
Method: http.MethodGet,
Path: "/:id",
@@ -243,30 +240,50 @@ func InitRoutes(app *gin.Engine) (err error) {
Path: "/:id/logs",
HandlerFunc: GetTaskLogs,
},
{
Method: http.MethodGet,
Path: "/:id/data",
HandlerFunc: GetTaskData,
},
}...))
RegisterController(groups.AuthGroup, "/tokens", NewControllerV2[models.TokenV2]([]Action{
RegisterController(groups.AuthGroup, "/tokens", NewController[models.Token]([]Action{
{
Method: http.MethodPost,
Path: "",
HandlerFunc: PostToken,
},
}...))
RegisterController(groups.AuthGroup, "/users", NewControllerV2[models.UserV2]([]Action{
RegisterController(groups.AuthGroup, "/users", NewController[models.User]([]Action{
{
Method: http.MethodGet,
Path: "/:id",
HandlerFunc: GetUserById,
},
{
Method: http.MethodGet,
Path: "",
HandlerFunc: GetUserList,
},
{
Method: http.MethodPost,
Path: "",
HandlerFunc: PostUser,
},
{
Method: http.MethodPut,
Path: "/:id",
HandlerFunc: PutUserById,
},
{
Method: http.MethodPost,
Path: "/:id/change-password",
HandlerFunc: PostUserChangePassword,
},
{
Method: http.MethodDelete,
Path: "/:id",
HandlerFunc: DeleteUserById,
},
{
Method: http.MethodDelete,
Path: "",
HandlerFunc: DeleteUserList,
},
{
Method: http.MethodGet,
Path: "/me",
@@ -275,17 +292,16 @@ func InitRoutes(app *gin.Engine) (err error) {
{
Method: http.MethodPut,
Path: "/me",
HandlerFunc: PutUserById,
HandlerFunc: PutUserMe,
},
{
Method: http.MethodPost,
Path: "/me/change-password",
HandlerFunc: PostUserMeChangePassword,
},
}...))
RegisterActions(groups.AuthGroup, "/results", []Action{
{
Method: http.MethodGet,
Path: "/:id",
HandlerFunc: GetResultList,
},
})
// Register standalone action routes that don't fit the standard CRUD pattern
RegisterActions(groups.AuthGroup, "/export", []Action{
{
Method: http.MethodPost,
@@ -323,12 +339,17 @@ func InitRoutes(app *gin.Engine) (err error) {
RegisterActions(groups.AuthGroup, "/settings", []Action{
{
Method: http.MethodGet,
Path: "/:id",
Path: "/:key",
HandlerFunc: GetSetting,
},
{
Method: http.MethodPost,
Path: "/:key",
HandlerFunc: PostSetting,
},
{
Method: http.MethodPut,
Path: "/:id",
Path: "/:key",
HandlerFunc: PutSetting,
},
})
@@ -350,6 +371,28 @@ func InitRoutes(app *gin.Engine) (err error) {
},
})
// Register sync routes that require special authentication
RegisterActions(groups.SyncAuthGroup, "/sync", []Action{
{
Method: http.MethodGet,
Path: "/:id/scan",
HandlerFunc: GetSyncScan,
},
{
Method: http.MethodGet,
Path: "/:id/download",
HandlerFunc: GetSyncDownload,
},
})
// Register public routes that don't require authentication
RegisterActions(groups.AnonymousGroup, "/health", []Action{
{
Path: "",
Method: http.MethodGet,
HandlerFunc: GetHealthFn(func() bool { return true }),
},
})
RegisterActions(groups.AnonymousGroup, "/system-info", []Action{
{
Path: "",
@@ -369,18 +412,6 @@ func InitRoutes(app *gin.Engine) (err error) {
HandlerFunc: PostLogout,
},
})
RegisterActions(groups.AnonymousGroup, "/sync", []Action{
{
Method: http.MethodGet,
Path: "/:id/scan",
HandlerFunc: GetSyncScan,
},
{
Method: http.MethodGet,
Path: "/:id/download",
HandlerFunc: GetSyncDownload,
},
})
return nil
}

View File

@@ -28,7 +28,7 @@ func TestRouterGroups(t *testing.T) {
func TestRegisterController_Routes(t *testing.T) {
router := gin.Default()
groups := controllers.NewRouterGroups(router)
ctr := controllers.NewControllerV2[models.TestModel]()
ctr := controllers.NewController[models.TestModel]()
basePath := "/testmodels"
controllers.RegisterController(groups.AuthGroup, basePath, ctr)

Some files were not shown because too many files have changed in this diff Show More