Compare commits
29 Commits
frontend
...
ce73e915ca
| Author | SHA1 | Date | |
|---|---|---|---|
| ce73e915ca | |||
| baaa27005e | |||
| 84807b9ba9 | |||
| b99f60c7e5 | |||
| 6740dbb1b7 | |||
| 5c67c0287e | |||
| 8ab7fbc6b2 | |||
| d917a9e465 | |||
| 82c6e1bb15 | |||
| 68f3174f08 | |||
| 94be9799f4 | |||
| 3541fbdaae | |||
| 81f3ba52cc | |||
| 8dee5ac823 | |||
| 980526c630 | |||
| eb193b1b95 | |||
| 514e3e30b6 | |||
| 94ff261c9a | |||
| a44630cfea | |||
| b69f2e4c9a | |||
| d96f952d73 | |||
| 27e82f80f1 | |||
| 83427193bc | |||
| 28ef2dc1fd | |||
| 2ebf374413 | |||
| 3293915062 | |||
| 8913353e64 | |||
| 9992e254d5 | |||
| b75d95f9a7 |
@@ -0,0 +1 @@
|
||||
go.work.sum
|
||||
@@ -0,0 +1,26 @@
|
||||
FROM golang:1.26.1 as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
go mod download
|
||||
|
||||
COPY . .
|
||||
ENV CGO_ENABLED=0
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
go build -ldflags "-s -w" -o agent ./main.go
|
||||
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
systemd \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /app/agent .
|
||||
|
||||
CMD ["./agent"]
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
module gitea.d3m0k1d.ru/d3m0k1d/HellreigN/agent
|
||||
|
||||
go 1.26.1
|
||||
|
||||
require (
|
||||
gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto v0.0.0-20260403214837-94be9799f47d
|
||||
golang.org/x/sync v0.20.0
|
||||
google.golang.org/grpc v1.80.0
|
||||
)
|
||||
|
||||
require (
|
||||
go.opentelemetry.io/otel/metric v1.41.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.41.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
@@ -0,0 +1,42 @@
|
||||
gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto v0.0.0-20260403214837-94be9799f47d h1:oBBLU8/nhXgOr0Z/M/t4pYj3KjuRj8AI15J0RJCiRt8=
|
||||
gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto v0.0.0-20260403214837-94be9799f47d/go.mod h1:FEPB3qn+wXkes/eArIMdq1/3CbHnSDUxsUtXhC8mgOg=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
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=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
|
||||
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
|
||||
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
|
||||
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
|
||||
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
@@ -0,0 +1,79 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/agent/internal/commander"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/proto"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
type CommanderClient struct {
|
||||
cmder *commander.Commander
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
func New(
|
||||
cmder *commander.Commander,
|
||||
wg *sync.WaitGroup,
|
||||
) CommanderClient {
|
||||
return CommanderClient{cmder, wg}
|
||||
}
|
||||
func (self *CommanderClient) HandleCommands(ctx context.Context, srvAddr string, tc credentials.TransportCredentials) error {
|
||||
cli, err := grpc.NewClient(srvAddr, grpc.WithTransportCredentials(tc))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to connect to gRPC: %w", err)
|
||||
}
|
||||
ccli := proto.NewCommanderClient(cli)
|
||||
bidi, err := ccli.Stream(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wg := new(errgroup.Group)
|
||||
wg.Go(self.recv(bidi))
|
||||
// wg.Go(self.send(bidi))
|
||||
err = wg.Wait()
|
||||
self.wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *CommanderClient) recv(bidi grpc.BidiStreamingClient[proto.FinishedCommand, proto.Command]) func() error {
|
||||
return func() error {
|
||||
for {
|
||||
msg, err := bidi.Recv()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
self.wg.Go(func() {
|
||||
func() error {
|
||||
|
||||
fc, err := self.cmder.Execute(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bidi.Send(fc)
|
||||
}()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func (self *God) send(bidi grpc.BidiStreamingClient[proto.FinishedCommand, proto.Command]) func() error {
|
||||
// return func() error {
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,65 @@
|
||||
package commander
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os/exec"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/proto"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type Commander struct {
|
||||
}
|
||||
|
||||
func (*Commander) Execute(command *proto.Command) (*proto.FinishedCommand, error) {
|
||||
cmd := exec.Command(command.Command[0], command.Command[1:]...)
|
||||
var (
|
||||
stdin io.WriteCloser
|
||||
err error
|
||||
)
|
||||
if command.Stdin != nil {
|
||||
stdin, err = cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
stdout, err1 := cmd.StdoutPipe()
|
||||
stderr, err2 := cmd.StderrPipe()
|
||||
if err := errors.Join(err1, err2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if command.Stdin != nil {
|
||||
io.WriteString(stdin, *command.Stdin)
|
||||
if err := stdin.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
eg := new(errgroup.Group)
|
||||
stdoutbuf := new(bytes.Buffer)
|
||||
stderrbuf := new(bytes.Buffer)
|
||||
eg.Go(func() error {
|
||||
_, err := io.Copy(stdoutbuf, stdout)
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
_, err := io.Copy(stderrbuf, stderr)
|
||||
return err
|
||||
})
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &proto.FinishedCommand{
|
||||
Id: command.Id,
|
||||
Status: int32(cmd.ProcessState.ExitCode()),
|
||||
Stdout: stdoutbuf.String(),
|
||||
Stderr: stderrbuf.String(),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package main
|
||||
@@ -0,0 +1,21 @@
|
||||
version: "2"
|
||||
run:
|
||||
timeout: 5m
|
||||
tests: false
|
||||
build-tags:
|
||||
- integration
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- errcheck
|
||||
- errname
|
||||
- govet
|
||||
- staticcheck
|
||||
- gosec
|
||||
- nilerr
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
- golines
|
||||
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/docs"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/config"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/handlers"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage"
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
)
|
||||
|
||||
// @securityDefinitions.apikey Bearer
|
||||
// @in header
|
||||
// @name Authorization
|
||||
// @description Type "Bearer" followed by a space and the JWT token.
|
||||
|
||||
func main() {
|
||||
cfg_path, ok := os.LookupEnv("CONFIG_FILE")
|
||||
if !ok {
|
||||
cfg_path = "/etc/hellreign/config.yml"
|
||||
}
|
||||
cfg, err := config.ImportSettings(cfg_path)
|
||||
if err != nil {
|
||||
log.Fatalf("Err loading config: %v", err)
|
||||
}
|
||||
|
||||
db, err := storage.Open(cfg.Database.Token_db)
|
||||
if err != nil {
|
||||
log.Fatalf("Err opening database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
h := handlers.New(db)
|
||||
agents := handlers.AgentsGroup{Handlers: h}
|
||||
auth := handlers.AuthGroup{Handlers: h}
|
||||
|
||||
// Create admin user from config if not exists
|
||||
if cfg.Admin.Admin_login != "" && cfg.Admin.Admin_password != "" {
|
||||
if !h.Repo.ExistsByLogin(cfg.Admin.Admin_login) {
|
||||
_, err := h.Repo.CreateToken(repository.TokenCreate{
|
||||
Name: cfg.Admin.Admin_name,
|
||||
LastName: cfg.Admin.Admin_last_name,
|
||||
Login: cfg.Admin.Admin_login,
|
||||
Password: cfg.Admin.Admin_password,
|
||||
PermissionView: true,
|
||||
PermissionAdmin: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Warning: failed to create admin user: %v", err)
|
||||
} else {
|
||||
log.Println("Admin user created from config")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
router := gin.Default()
|
||||
docs.SwaggerInfo.BasePath = "/api/v1"
|
||||
docs.SwaggerInfo.Title = "HellreigN"
|
||||
docs.SwaggerInfo.Version = "1.0"
|
||||
docs.SwaggerInfo.Description = "API for HellreigN"
|
||||
docs.SwaggerInfo.Schemes = []string{"http"}
|
||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
v1 := router.Group("/api/v1")
|
||||
{
|
||||
// Auth routes (public)
|
||||
authGroup := v1.Group("/auth")
|
||||
{
|
||||
authGroup.POST("/login", auth.Login)
|
||||
}
|
||||
|
||||
// Auth token management (requires auth)
|
||||
authTokenGroup := v1.Group("/auth")
|
||||
authTokenGroup.Use(auth.AuthMiddleware())
|
||||
{
|
||||
authTokenGroup.POST("/token", handlers.RequireAdmin(), auth.CreateToken)
|
||||
authTokenGroup.GET("/validate", auth.ValidateToken)
|
||||
authTokenGroup.GET("/tokens", handlers.RequireAdmin(), auth.ListTokens)
|
||||
authTokenGroup.DELETE("/token", auth.DeleteMyToken)
|
||||
authTokenGroup.DELETE("/tokens/:login", handlers.RequireAdmin(), auth.DeleteToken)
|
||||
}
|
||||
|
||||
// Agents (requires manage_agent permission)
|
||||
agentsGroup := v1.Group("/agents")
|
||||
agentsGroup.Use(auth.AuthMiddleware(), handlers.RequireManageAgent())
|
||||
{
|
||||
agentsGroup.GET("", agents.List)
|
||||
}
|
||||
|
||||
// Logs (requires view permission)
|
||||
logsGroup := v1.Group("/logs")
|
||||
logsGroup.Use(auth.AuthMiddleware(), handlers.RequireView())
|
||||
{
|
||||
if cfg.Database.Clickhouse_host != "" {
|
||||
chConn, err := storage.OpenClickHouse(storage.ClickHouseConfig{
|
||||
Host: cfg.Database.Clickhouse_host,
|
||||
User: cfg.Database.Clickhouse_user,
|
||||
Password: cfg.Database.Clickhouse_password,
|
||||
Database: cfg.Database.Clickhouse_database,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Warning: ClickHouse connection failed: %v", err)
|
||||
} else {
|
||||
defer chConn.Close()
|
||||
|
||||
logRepo := repository.NewLogRepository(chConn)
|
||||
if err := logRepo.Init(context.Background()); err != nil {
|
||||
log.Printf("Warning: Failed to initialize logs table: %v", err)
|
||||
}
|
||||
|
||||
logHandlers := handlers.NewLogHandlers(logRepo)
|
||||
logsGroup.POST("", logHandlers.Insert)
|
||||
logsGroup.POST("/batch", logHandlers.InsertBatch)
|
||||
logsGroup.GET("", logHandlers.Search)
|
||||
logsGroup.GET("/services", logHandlers.GetServices)
|
||||
logsGroup.GET("/agents", logHandlers.GetAgents)
|
||||
logsGroup.GET("/levels", logHandlers.GetLevels)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Fatal(router.Run(":8080"))
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
FROM golang:1.26.1 as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GIN_MODE=release
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
go mod download && \
|
||||
go build -ldflags "-s -w" -o backend ./cmd/main.go
|
||||
|
||||
FROM alpine:3.23.0
|
||||
|
||||
RUN apk add --no-cache curl openssl bash
|
||||
|
||||
COPY --from=builder /app/backend .
|
||||
#COPY --from=builder /app/scripts /etc/mnemosyne/scripts
|
||||
#RUN chmod +x /etc/mnemosyne/scripts/generate-certs.sh
|
||||
|
||||
EXPOSE 8080
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl --fail http://localhost:8080/health" ]
|
||||
|
||||
CMD ["./backend"]
|
||||
|
||||
@@ -0,0 +1,713 @@
|
||||
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplate = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/agents": {
|
||||
"get": {
|
||||
"description": "Returns a list of all agents currently connected via gRPC streaming",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"agents"
|
||||
],
|
||||
"summary": "Get connected agents",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_handlers.AgentInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"description": "Authenticate with login and password, returns a token and permissions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Login",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Login credentials",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/token": {
|
||||
"post": {
|
||||
"description": "Creates a new user with permissions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Create user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "User data",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Deletes the current authenticated user",
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Delete my account",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/tokens": {
|
||||
"get": {
|
||||
"description": "Returns list of all users with their permissions",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "List users",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/tokens/:login": {
|
||||
"delete": {
|
||||
"description": "Deletes a user by their login",
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Delete user",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Login of the user to delete",
|
||||
"name": "login",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/validate": {
|
||||
"get": {
|
||||
"description": "Check if the provided Bearer token is valid and return its permissions",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Validate token",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs": {
|
||||
"get": {
|
||||
"description": "Searches logs with various filters",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Search logs",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Log level (INFO, WARNING, ERROR, FATAL)",
|
||||
"name": "level",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Service name",
|
||||
"name": "service",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Agent name",
|
||||
"name": "agent",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Date from (RFC3339)",
|
||||
"name": "date_from",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Date to (RFC3339)",
|
||||
"name": "date_to",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 100,
|
||||
"description": "Limit results",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "Offset results",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Inserts a single log entry into ClickHouse",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Insert log entry",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Log entry",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/agents": {
|
||||
"get": {
|
||||
"description": "Returns list of all unique agent names in logs",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Get distinct agents",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/batch": {
|
||||
"post": {
|
||||
"description": "Inserts multiple log entries into ClickHouse",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Insert log entries (batch)",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Log entries",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_handlers.InsertLogsRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/levels": {
|
||||
"get": {
|
||||
"description": "Returns list of all unique log levels in logs",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Get distinct log levels",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/services": {
|
||||
"get": {
|
||||
"description": "Returns list of all unique service names in logs",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Get distinct services",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"login",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission_admin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_manage_agent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_view": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"last_name",
|
||||
"login",
|
||||
"name",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission_admin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_manage_agent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_view": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission_admin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_manage_agent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_view": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"service": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.AgentInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.InsertLogRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"agent",
|
||||
"level",
|
||||
"message",
|
||||
"service"
|
||||
],
|
||||
"properties": {
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"service": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.InsertLogsRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"logs"
|
||||
],
|
||||
"properties": {
|
||||
"logs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"Bearer": {
|
||||
"description": "Type \"Bearer\" followed by a space and the JWT token.",
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "",
|
||||
Host: "",
|
||||
BasePath: "",
|
||||
Schemes: []string{},
|
||||
Title: "",
|
||||
Description: "",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
LeftDelim: "{{",
|
||||
RightDelim: "}}",
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
||||
@@ -0,0 +1,684 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"contact": {}
|
||||
},
|
||||
"paths": {
|
||||
"/agents": {
|
||||
"get": {
|
||||
"description": "Returns a list of all agents currently connected via gRPC streaming",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"agents"
|
||||
],
|
||||
"summary": "Get connected agents",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_handlers.AgentInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"description": "Authenticate with login and password, returns a token and permissions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Login",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Login credentials",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/token": {
|
||||
"post": {
|
||||
"description": "Creates a new user with permissions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Create user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "User data",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Deletes the current authenticated user",
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Delete my account",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/tokens": {
|
||||
"get": {
|
||||
"description": "Returns list of all users with their permissions",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "List users",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/tokens/:login": {
|
||||
"delete": {
|
||||
"description": "Deletes a user by their login",
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Delete user",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Login of the user to delete",
|
||||
"name": "login",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/validate": {
|
||||
"get": {
|
||||
"description": "Check if the provided Bearer token is valid and return its permissions",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Validate token",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs": {
|
||||
"get": {
|
||||
"description": "Searches logs with various filters",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Search logs",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Log level (INFO, WARNING, ERROR, FATAL)",
|
||||
"name": "level",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Service name",
|
||||
"name": "service",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Agent name",
|
||||
"name": "agent",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Date from (RFC3339)",
|
||||
"name": "date_from",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Date to (RFC3339)",
|
||||
"name": "date_to",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 100,
|
||||
"description": "Limit results",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "Offset results",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Inserts a single log entry into ClickHouse",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Insert log entry",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Log entry",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/agents": {
|
||||
"get": {
|
||||
"description": "Returns list of all unique agent names in logs",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Get distinct agents",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/batch": {
|
||||
"post": {
|
||||
"description": "Inserts multiple log entries into ClickHouse",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Insert log entries (batch)",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Log entries",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_handlers.InsertLogsRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/levels": {
|
||||
"get": {
|
||||
"description": "Returns list of all unique log levels in logs",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Get distinct log levels",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/services": {
|
||||
"get": {
|
||||
"description": "Returns list of all unique service names in logs",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"logs"
|
||||
],
|
||||
"summary": "Get distinct services",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"login",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission_admin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_manage_agent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_view": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"last_name",
|
||||
"login",
|
||||
"name",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission_admin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_manage_agent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_view": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"permission_admin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_manage_agent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"permission_view": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"service": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.AgentInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.InsertLogRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"agent",
|
||||
"level",
|
||||
"message",
|
||||
"service"
|
||||
],
|
||||
"properties": {
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"service": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.InsertLogsRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"logs"
|
||||
],
|
||||
"properties": {
|
||||
"logs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"Bearer": {
|
||||
"description": "Type \"Bearer\" followed by a space and the JWT token.",
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,450 @@
|
||||
definitions:
|
||||
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest:
|
||||
properties:
|
||||
login:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
required:
|
||||
- login
|
||||
- password
|
||||
type: object
|
||||
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse:
|
||||
properties:
|
||||
last_name:
|
||||
type: string
|
||||
login:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
permission_admin:
|
||||
type: boolean
|
||||
permission_manage_agent:
|
||||
type: boolean
|
||||
permission_view:
|
||||
type: boolean
|
||||
token:
|
||||
type: string
|
||||
type: object
|
||||
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate:
|
||||
properties:
|
||||
last_name:
|
||||
type: string
|
||||
login:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
permission_admin:
|
||||
type: boolean
|
||||
permission_manage_agent:
|
||||
type: boolean
|
||||
permission_view:
|
||||
type: boolean
|
||||
required:
|
||||
- last_name
|
||||
- login
|
||||
- name
|
||||
- password
|
||||
type: object
|
||||
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens:
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
last_name:
|
||||
type: string
|
||||
login:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
permission_admin:
|
||||
type: boolean
|
||||
permission_manage_agent:
|
||||
type: boolean
|
||||
permission_view:
|
||||
type: boolean
|
||||
token:
|
||||
type: string
|
||||
type: object
|
||||
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry:
|
||||
properties:
|
||||
agent:
|
||||
type: string
|
||||
level:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
service:
|
||||
type: string
|
||||
timestamp:
|
||||
type: string
|
||||
type: object
|
||||
internal_handlers.AgentInfo:
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
services:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
token:
|
||||
type: string
|
||||
type: object
|
||||
internal_handlers.InsertLogRequest:
|
||||
properties:
|
||||
agent:
|
||||
type: string
|
||||
level:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
service:
|
||||
type: string
|
||||
timestamp:
|
||||
type: string
|
||||
required:
|
||||
- agent
|
||||
- level
|
||||
- message
|
||||
- service
|
||||
type: object
|
||||
internal_handlers.InsertLogsRequest:
|
||||
properties:
|
||||
logs:
|
||||
items:
|
||||
$ref: '#/definitions/internal_handlers.InsertLogRequest'
|
||||
type: array
|
||||
required:
|
||||
- logs
|
||||
type: object
|
||||
info:
|
||||
contact: {}
|
||||
paths:
|
||||
/agents:
|
||||
get:
|
||||
description: Returns a list of all agents currently connected via gRPC streaming
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/internal_handlers.AgentInfo'
|
||||
type: array
|
||||
summary: Get connected agents
|
||||
tags:
|
||||
- agents
|
||||
/auth/login:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Authenticate with login and password, returns a token and permissions
|
||||
parameters:
|
||||
- description: Login credentials
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Login
|
||||
tags:
|
||||
- auth
|
||||
/auth/token:
|
||||
delete:
|
||||
description: Deletes the current authenticated user
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Delete my account
|
||||
tags:
|
||||
- auth
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Creates a new user with permissions
|
||||
parameters:
|
||||
- description: User data
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Create user
|
||||
tags:
|
||||
- auth
|
||||
/auth/tokens:
|
||||
get:
|
||||
description: Returns list of all users with their permissions
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: List users
|
||||
tags:
|
||||
- auth
|
||||
/auth/tokens/:login:
|
||||
delete:
|
||||
description: Deletes a user by their login
|
||||
parameters:
|
||||
- description: Login of the user to delete
|
||||
in: path
|
||||
name: login
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Delete user
|
||||
tags:
|
||||
- auth
|
||||
/auth/validate:
|
||||
get:
|
||||
description: Check if the provided Bearer token is valid and return its permissions
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Validate token
|
||||
tags:
|
||||
- auth
|
||||
/logs:
|
||||
get:
|
||||
description: Searches logs with various filters
|
||||
parameters:
|
||||
- description: Log level (INFO, WARNING, ERROR, FATAL)
|
||||
in: query
|
||||
name: level
|
||||
type: string
|
||||
- description: Service name
|
||||
in: query
|
||||
name: service
|
||||
type: string
|
||||
- description: Agent name
|
||||
in: query
|
||||
name: agent
|
||||
type: string
|
||||
- description: Date from (RFC3339)
|
||||
in: query
|
||||
name: date_from
|
||||
type: string
|
||||
- description: Date to (RFC3339)
|
||||
in: query
|
||||
name: date_to
|
||||
type: string
|
||||
- default: 100
|
||||
description: Limit results
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- default: 0
|
||||
description: Offset results
|
||||
in: query
|
||||
name: offset
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry'
|
||||
type: array
|
||||
summary: Search logs
|
||||
tags:
|
||||
- logs
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Inserts a single log entry into ClickHouse
|
||||
parameters:
|
||||
- description: Log entry
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_handlers.InsertLogRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Insert log entry
|
||||
tags:
|
||||
- logs
|
||||
/logs/agents:
|
||||
get:
|
||||
description: Returns list of all unique agent names in logs
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
summary: Get distinct agents
|
||||
tags:
|
||||
- logs
|
||||
/logs/batch:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Inserts multiple log entries into ClickHouse
|
||||
parameters:
|
||||
- description: Log entries
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_handlers.InsertLogsRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Insert log entries (batch)
|
||||
tags:
|
||||
- logs
|
||||
/logs/levels:
|
||||
get:
|
||||
description: Returns list of all unique log levels in logs
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
summary: Get distinct log levels
|
||||
tags:
|
||||
- logs
|
||||
/logs/services:
|
||||
get:
|
||||
description: Returns list of all unique service names in logs
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
summary: Get distinct services
|
||||
tags:
|
||||
- logs
|
||||
securityDefinitions:
|
||||
Bearer:
|
||||
description: Type "Bearer" followed by a space and the JWT token.
|
||||
in: header
|
||||
name: Authorization
|
||||
type: apiKey
|
||||
swagger: "2.0"
|
||||
@@ -0,0 +1,82 @@
|
||||
module gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend
|
||||
|
||||
go 1.26.1
|
||||
|
||||
require (
|
||||
gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto v0.0.0-20260403210401-a6212c89fc0e
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.44.0
|
||||
github.com/gin-gonic/gin v1.12.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.1
|
||||
github.com/swaggo/swag v1.16.6
|
||||
golang.org/x/sync v0.20.0
|
||||
google.golang.org/grpc v1.80.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.48.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ClickHouse/ch-go v0.71.0 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/bytedance/gopkg v0.1.4 // indirect
|
||||
github.com/bytedance/sonic v1.15.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.5.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||
github.com/gin-contrib/sse v1.1.1 // indirect
|
||||
github.com/go-faster/city v1.0.1 // indirect
|
||||
github.com/go-faster/errors v0.7.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.22.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.5 // indirect
|
||||
github.com/go-openapi/spec v0.22.4 // indirect
|
||||
github.com/go-openapi/swag/conv v0.25.5 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
|
||||
github.com/go-openapi/swag/loading v0.25.5 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.25.5 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.25.5 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.25.5 // 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.30.2 // indirect
|
||||
github.com/goccy/go-json v0.10.6 // indirect
|
||||
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.18.3 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/paulmach/orb v0.12.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.3.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.25 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/segmentio/asm v1.2.1 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||
go.opentelemetry.io/otel v1.41.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.41.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/arch v0.25.0 // indirect
|
||||
golang.org/x/crypto v0.49.0 // indirect
|
||||
golang.org/x/mod v0.34.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
modernc.org/libc v1.70.0 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
)
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto v0.0.0-20260403210401-a6212c89fc0e h1:Z/2Mjc9NU0CWIduj8Wd9ClnZt4dqmQUUXl1VlyGQe6U=
|
||||
gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto v0.0.0-20260403210401-a6212c89fc0e/go.mod h1:1DByetpOnW2+AjM8ZWbJ1Xfzprus8fBie2AMUP/YHHA=
|
||||
github.com/ClickHouse/ch-go v0.71.0 h1:bUdZ/EZj/LcVHsMqaRUP2holqygrPWQKeMjc6nZoyRM=
|
||||
github.com/ClickHouse/ch-go v0.71.0/go.mod h1:NwbNc+7jaqfY58dmdDUbG4Jl22vThgx1cYjBw0vtgXw=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.44.0 h1:9pxs5pRwIvhni5BDRPn/n5A8DeUod5TnBaeulFBX8EQ=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.44.0/go.mod h1:giJfUVlMkcfUEPVfRpt51zZaGEx9i17gCos8gBl392c=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
|
||||
github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
|
||||
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
||||
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
|
||||
github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
|
||||
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
||||
github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko=
|
||||
github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s=
|
||||
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
|
||||
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
|
||||
github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
|
||||
github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
|
||||
github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
|
||||
github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
|
||||
github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
|
||||
github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
|
||||
github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
|
||||
github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
|
||||
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
|
||||
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=
|
||||
github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
|
||||
github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
|
||||
github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
|
||||
github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
|
||||
github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
|
||||
github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM=
|
||||
github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM=
|
||||
github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
|
||||
github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
|
||||
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
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/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
|
||||
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/paulmach/orb v0.12.0 h1:z+zOwjmG3MyEEqzv92UN49Lg1JFYx0L9GpGKNVDKk1s=
|
||||
github.com/paulmach/orb v0.12.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM=
|
||||
github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
|
||||
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
|
||||
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||
github.com/swaggo/gin-swagger v1.6.1 h1:Ri06G4gc9N4t4k8hekMigJ9zKTFSlqj/9paAQCQs7cY=
|
||||
github.com/swaggo/gin-swagger v1.6.1/go.mod h1:LQ+hJStHakCWRiK/YNYtJOu4mR2FP+pxLnILT/qNiTw=
|
||||
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
|
||||
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
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.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
|
||||
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
|
||||
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
|
||||
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
|
||||
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE=
|
||||
golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-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.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220722155257-8c9f86f7a55f/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.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
||||
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=
|
||||
modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
|
||||
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.48.1 h1:S85iToyU6cgeojybE2XJlSbcsvcWkQ6qqNXJHtW5hWA=
|
||||
modernc.org/sqlite v1.48.1/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
@@ -0,0 +1,22 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func ImportSettings(path string) (*HellreigN, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
var cfg HellreigN
|
||||
|
||||
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package config
|
||||
|
||||
type HellreigN struct {
|
||||
Database Databases `yaml:"database"`
|
||||
Admin Admin `yaml:"admin"`
|
||||
}
|
||||
|
||||
type Databases struct {
|
||||
Token_db string `yaml:"token_db"`
|
||||
Clickhouse_host string `yaml:"clickhouse_host"`
|
||||
Clickhouse_user string `yaml:"clickhouse_user"`
|
||||
Clickhouse_password string `yaml:"clickhouse_password"`
|
||||
Clickhouse_database string `yaml:"clickhouse_database"`
|
||||
}
|
||||
type Admin struct {
|
||||
Admin_name string `yaml:"admin_name"`
|
||||
Admin_last_name string `yaml:"admin_last_name"`
|
||||
Admin_login string `yaml:"admin_login"`
|
||||
Admin_password string `yaml:"admin_password"`
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package commander
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/models"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/proto"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
type Commander struct {
|
||||
proto.UnimplementedCommanderServer
|
||||
agents map[string]Agent
|
||||
}
|
||||
|
||||
type Agent struct {
|
||||
bidi grpc.BidiStreamingServer[proto.FinishedCommand, proto.Command]
|
||||
in chan *proto.Command
|
||||
jobs map[int64]Job
|
||||
jobber interface {
|
||||
InitJob(ctx context.Context) (int64, error)
|
||||
UpdateJobInDB(ctx context.Context, jid int64, msg models.JobForUpdate) (models.Job, error)
|
||||
}
|
||||
ctx context.Context
|
||||
}
|
||||
type JobOut struct {
|
||||
fc models.Job
|
||||
err error
|
||||
}
|
||||
|
||||
type Job struct {
|
||||
out chan JobOut
|
||||
}
|
||||
|
||||
func (self *Commander) GetAgent(aid string) (agent Agent, ok bool) {
|
||||
agent, ok = self.agents[aid]
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Agent) AddJob(job models.JobForInsert) (int64, error) {
|
||||
jid, err := self.jobber.InitJob(self.ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
self.in <- &proto.Command{
|
||||
Id: 0,
|
||||
Command: []string{},
|
||||
Stdin: new(string),
|
||||
}
|
||||
return jid, err
|
||||
}
|
||||
|
||||
func (self *Agent) WaitJob(jid int64) (*models.Job, error) {
|
||||
result := <-self.jobs[jid].out
|
||||
return &result.fc, result.err
|
||||
}
|
||||
|
||||
func (self *Commander) Stream(bidi grpc.BidiStreamingServer[proto.FinishedCommand, proto.Command]) error {
|
||||
md, ok := metadata.FromIncomingContext(bidi.Context())
|
||||
if !ok {
|
||||
return fmt.Errorf("no metadata in context")
|
||||
}
|
||||
aidVals := md["agentid"]
|
||||
if len(aidVals) == 0 {
|
||||
return fmt.Errorf("agentid metadata missing")
|
||||
}
|
||||
aid := aidVals[0]
|
||||
agent := newAgent(bidi)
|
||||
self.agents[aid] = agent
|
||||
return agent.run()
|
||||
}
|
||||
|
||||
func (self *Agent) run() error {
|
||||
wg := new(errgroup.Group)
|
||||
wg.Go(self.recv)
|
||||
wg.Go(self.send)
|
||||
return wg.Wait()
|
||||
}
|
||||
|
||||
func (self *Agent) recv() error {
|
||||
for {
|
||||
job, err := func() (job models.Job, err error) {
|
||||
msg, err := self.bidi.Recv()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return self.jobber.UpdateJobInDB(self.ctx, msg.Id, models.JobForUpdate{
|
||||
Stdout: msg.Stdout,
|
||||
Stderr: msg.Stderr,
|
||||
Status: msg.Status,
|
||||
})
|
||||
}()
|
||||
// TODO: that would blow up at some point
|
||||
out := self.jobs[job.ID].out
|
||||
out <- JobOut{
|
||||
fc: job,
|
||||
err: err,
|
||||
}
|
||||
close(out)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Agent) send() error {
|
||||
for job := range self.in {
|
||||
self.jobs[job.Id] = newJob()
|
||||
if err := self.bidi.Send(job); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return io.EOF
|
||||
// self.jobs[]
|
||||
}
|
||||
|
||||
func newAgent(bidi grpc.BidiStreamingServer[proto.FinishedCommand, proto.Command]) Agent {
|
||||
return Agent{
|
||||
bidi,
|
||||
make(chan *proto.Command),
|
||||
make(map[int64]Job),
|
||||
nil,
|
||||
bidi.Context(),
|
||||
}
|
||||
}
|
||||
|
||||
func newJob() Job {
|
||||
return Job{make(chan JobOut, 1)}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type AgentsGroup struct {
|
||||
*Handlers
|
||||
}
|
||||
|
||||
type AgentInfo struct {
|
||||
Token string `json:"token"`
|
||||
Label string `json:"label"`
|
||||
Services []string `json:"services"`
|
||||
}
|
||||
|
||||
// @Summary Get connected agents
|
||||
// @Description Returns a list of all agents currently connected via gRPC streaming
|
||||
// @Tags agents
|
||||
// @Produce json
|
||||
// @Success 200 {array} AgentInfo
|
||||
// @Router /agents [get]
|
||||
func (ag *AgentsGroup) List(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Agents list"})
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AuthGroup handles authentication routes.
|
||||
type AuthGroup struct {
|
||||
*Handlers
|
||||
}
|
||||
|
||||
// Login authenticates a user by login and password, returns a token.
|
||||
// @Summary Login
|
||||
// @Description Authenticate with login and password, returns a token and permissions
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Param request body repository.LoginRequest true "Login credentials"
|
||||
// @Success 200 {object} repository.LoginResponse
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 401 {object} map[string]string
|
||||
// @Router /auth/login [post]
|
||||
func (ag *AuthGroup) Login(c *gin.Context) {
|
||||
var req repository.LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := ag.Repo.Login(req.Login, req.Password)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrNotFound) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to authenticate"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// CreateToken creates a new user.
|
||||
// @Summary Create user
|
||||
// @Description Creates a new user with permissions
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Param request body repository.TokenCreate true "User data"
|
||||
// @Success 200 {object} map[string]string
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 401 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /auth/token [post]
|
||||
func (ag *AuthGroup) CreateToken(c *gin.Context) {
|
||||
var tc repository.TokenCreate
|
||||
if err := c.ShouldBindJSON(&tc); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := ag.Repo.CreateToken(tc); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "user created"})
|
||||
}
|
||||
|
||||
// ValidateToken validates the current Bearer token and returns user info.
|
||||
// @Summary Validate token
|
||||
// @Description Check if the provided Bearer token is valid and return its permissions
|
||||
// @Tags auth
|
||||
// @Produce json
|
||||
// @Success 200 {object} repository.Tokens
|
||||
// @Failure 401 {object} map[string]string
|
||||
// @Router /auth/validate [get]
|
||||
func (ag *AuthGroup) ValidateToken(c *gin.Context) {
|
||||
tokenVal, exists := c.Get(string(tokenContextKey))
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
token, ok := tokenVal.(*repository.Tokens)
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token context"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, token)
|
||||
}
|
||||
|
||||
// ListTokens returns all users.
|
||||
// @Summary List users
|
||||
// @Description Returns list of all users with their permissions
|
||||
// @Tags auth
|
||||
// @Produce json
|
||||
// @Success 200 {array} repository.Tokens
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /auth/tokens [get]
|
||||
func (ag *AuthGroup) ListTokens(c *gin.Context) {
|
||||
tokens, err := ag.Repo.ListTokens()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list users"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, tokens)
|
||||
}
|
||||
|
||||
// DeleteToken deletes a user by login from URL path.
|
||||
// @Summary Delete user
|
||||
// @Description Deletes a user by their login
|
||||
// @Tags auth
|
||||
// @Param login path string true "Login of the user to delete"
|
||||
// @Success 200 {object} map[string]string
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /auth/tokens/:login [delete]
|
||||
func (ag *AuthGroup) DeleteToken(c *gin.Context) {
|
||||
login := c.Param("login")
|
||||
if login == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "login required"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := ag.Repo.DeleteTokenByLogin(login); err != nil {
|
||||
if errors.Is(err, repository.ErrNotFound) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "user deleted"})
|
||||
}
|
||||
|
||||
// DeleteMyToken deletes the current user's account.
|
||||
// @Summary Delete my account
|
||||
// @Description Deletes the current authenticated user
|
||||
// @Tags auth
|
||||
// @Success 200 {object} map[string]string
|
||||
// @Failure 401 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /auth/token [delete]
|
||||
func (ag *AuthGroup) DeleteMyToken(c *gin.Context) {
|
||||
tokenVal, exists := c.Get(string(tokenContextKey))
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
token, ok := tokenVal.(*repository.Tokens)
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token context"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := ag.Repo.DeleteToken(token.Token); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete account"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "account deleted"})
|
||||
}
|
||||
|
||||
// getTokenFromHeader extracts the Bearer token from the Authorization header.
|
||||
func getTokenFromHeader(c *gin.Context) string {
|
||||
auth := c.GetHeader("Authorization")
|
||||
if auth == "" {
|
||||
return ""
|
||||
}
|
||||
parts := strings.SplitN(auth, " ", 2)
|
||||
if len(parts) != 2 || !strings.EqualFold(parts[0], "bearer") {
|
||||
return ""
|
||||
}
|
||||
return parts[1]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
||||
)
|
||||
|
||||
type Handlers struct {
|
||||
DB *sql.DB
|
||||
Repo *repository.Repository
|
||||
}
|
||||
|
||||
func New(db *sql.DB) *Handlers {
|
||||
return &Handlers{
|
||||
DB: db,
|
||||
Repo: repository.New(db),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/commander"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type JobsHandlers struct {
|
||||
cmder *commander.Commander
|
||||
}
|
||||
|
||||
func NewJobsHandlers(cmder *commander.Commander) JobsHandlers {
|
||||
return JobsHandlers{cmder}
|
||||
}
|
||||
|
||||
func (self *JobsHandlers) AddJob(c *gin.Context) {
|
||||
err := func() error {
|
||||
type In struct {
|
||||
Command []string `json:"command"`
|
||||
Stdin *string `json:"stdin"`
|
||||
AID string `json:"agent_id"`
|
||||
}
|
||||
var in In
|
||||
if err := c.Bind(&in); err != nil {
|
||||
return err
|
||||
}
|
||||
agent, ok := self.cmder.GetAgent(in.AID)
|
||||
if !ok {
|
||||
c.Status(404)
|
||||
return fmt.Errorf("Agent not found")
|
||||
}
|
||||
jid, err := agent.AddJob(models.JobForInsert{
|
||||
Command: in.Command,
|
||||
Stdin: in.Stdin,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
job, err := agent.WaitJob(jid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
type Out struct {
|
||||
ID int64 `json:"id"`
|
||||
Command []string `json:"command"`
|
||||
Stdin *string `json:"stdin"`
|
||||
Stdout string `json:"stdout"`
|
||||
Stderr string `json:"stderr"`
|
||||
Status int32 `json:"status"`
|
||||
}
|
||||
c.JSON(201, Out{
|
||||
ID: job.ID,
|
||||
Command: job.Command,
|
||||
Stdin: job.Stdin,
|
||||
Stdout: job.Stdout,
|
||||
Stderr: job.Stderr,
|
||||
Status: job.Status,
|
||||
})
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
c.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type LogHandlers struct {
|
||||
LogRepo *repository.LogRepository
|
||||
}
|
||||
|
||||
func NewLogHandlers(logRepo *repository.LogRepository) *LogHandlers {
|
||||
return &LogHandlers{LogRepo: logRepo}
|
||||
}
|
||||
|
||||
type InsertLogRequest struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Level string `json:"level" binding:"required"`
|
||||
Service string `json:"service" binding:"required"`
|
||||
Agent string `json:"agent" binding:"required"`
|
||||
Message string `json:"message" binding:"required"`
|
||||
}
|
||||
|
||||
// @Summary Insert log entry
|
||||
// @Description Inserts a single log entry into ClickHouse
|
||||
// @Tags logs
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body InsertLogRequest true "Log entry"
|
||||
// @Success 201 {object} map[string]string
|
||||
// @Router /logs [post]
|
||||
func (lh *LogHandlers) Insert(c *gin.Context) {
|
||||
var req InsertLogRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Timestamp.IsZero() {
|
||||
req.Timestamp = time.Now()
|
||||
}
|
||||
|
||||
log := storage.LogEntry{
|
||||
Timestamp: req.Timestamp,
|
||||
Level: req.Level,
|
||||
Service: req.Service,
|
||||
Agent: req.Agent,
|
||||
Message: req.Message,
|
||||
}
|
||||
|
||||
if err := lh.LogRepo.Insert(c.Request.Context(), log); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to insert log"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"status": "ok"})
|
||||
}
|
||||
|
||||
type InsertLogsRequest struct {
|
||||
Logs []InsertLogRequest `json:"logs" binding:"required"`
|
||||
}
|
||||
|
||||
// @Summary Insert log entries (batch)
|
||||
// @Description Inserts multiple log entries into ClickHouse
|
||||
// @Tags logs
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body InsertLogsRequest true "Log entries"
|
||||
// @Success 201 {object} map[string]string
|
||||
// @Router /logs/batch [post]
|
||||
func (lh *LogHandlers) InsertBatch(c *gin.Context) {
|
||||
var req InsertLogsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
logs := make([]storage.LogEntry, len(req.Logs))
|
||||
for i, l := range req.Logs {
|
||||
if l.Timestamp.IsZero() {
|
||||
l.Timestamp = time.Now()
|
||||
}
|
||||
logs[i] = storage.LogEntry{
|
||||
Timestamp: l.Timestamp,
|
||||
Level: l.Level,
|
||||
Service: l.Service,
|
||||
Agent: l.Agent,
|
||||
Message: l.Message,
|
||||
}
|
||||
}
|
||||
|
||||
if err := lh.LogRepo.InsertBatch(c.Request.Context(), logs); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to insert logs"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"status": "ok", "count": len(logs)})
|
||||
}
|
||||
|
||||
type SearchLogsRequest struct {
|
||||
Level string `form:"level"`
|
||||
Service string `form:"service"`
|
||||
Agent string `form:"agent"`
|
||||
DateFrom string `form:"date_from"`
|
||||
DateTo string `form:"date_to"`
|
||||
Limit int `form:"limit"`
|
||||
Offset int `form:"offset"`
|
||||
}
|
||||
|
||||
// @Summary Search logs
|
||||
// @Description Searches logs with various filters
|
||||
// @Tags logs
|
||||
// @Produce json
|
||||
// @Param level query string false "Log level (INFO, WARNING, ERROR, FATAL)"
|
||||
// @Param service query string false "Service name"
|
||||
// @Param agent query string false "Agent name"
|
||||
// @Param date_from query string false "Date from (RFC3339)"
|
||||
// @Param date_to query string false "Date to (RFC3339)"
|
||||
// @Param limit query int false "Limit results" default(100)
|
||||
// @Param offset query int false "Offset results" default(0)
|
||||
// @Success 200 {array} storage.LogEntry
|
||||
// @Router /logs [get]
|
||||
func (lh *LogHandlers) Search(c *gin.Context) {
|
||||
var req SearchLogsRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
filter := repository.LogFilter{
|
||||
Level: req.Level,
|
||||
Service: req.Service,
|
||||
Agent: req.Agent,
|
||||
Limit: req.Limit,
|
||||
Offset: req.Offset,
|
||||
}
|
||||
|
||||
if req.DateFrom != "" {
|
||||
if t, err := time.Parse(time.RFC3339, req.DateFrom); err == nil {
|
||||
filter.DateFrom = t
|
||||
}
|
||||
}
|
||||
|
||||
if req.DateTo != "" {
|
||||
if t, err := time.Parse(time.RFC3339, req.DateTo); err == nil {
|
||||
filter.DateTo = t
|
||||
}
|
||||
}
|
||||
|
||||
if filter.Limit <= 0 {
|
||||
filter.Limit = 100
|
||||
}
|
||||
|
||||
logs, err := lh.LogRepo.Search(c.Request.Context(), filter)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search logs"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, logs)
|
||||
}
|
||||
|
||||
// @Summary Get distinct services
|
||||
// @Description Returns list of all unique service names in logs
|
||||
// @Tags logs
|
||||
// @Produce json
|
||||
// @Success 200 {array} string
|
||||
// @Router /logs/services [get]
|
||||
func (lh *LogHandlers) GetServices(c *gin.Context) {
|
||||
services, err := lh.LogRepo.GetDistinctServices(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get services"})
|
||||
return
|
||||
}
|
||||
|
||||
if services == nil {
|
||||
services = []string{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, services)
|
||||
}
|
||||
|
||||
// @Summary Get distinct agents
|
||||
// @Description Returns list of all unique agent names in logs
|
||||
// @Tags logs
|
||||
// @Produce json
|
||||
// @Success 200 {array} string
|
||||
// @Router /logs/agents [get]
|
||||
func (lh *LogHandlers) GetAgents(c *gin.Context) {
|
||||
agents, err := lh.LogRepo.GetDistinctAgents(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get agents"})
|
||||
return
|
||||
}
|
||||
|
||||
if agents == nil {
|
||||
agents = []string{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, agents)
|
||||
}
|
||||
|
||||
// @Summary Get distinct log levels
|
||||
// @Description Returns list of all unique log levels in logs
|
||||
// @Tags logs
|
||||
// @Produce json
|
||||
// @Success 200 {array} string
|
||||
// @Router /logs/levels [get]
|
||||
func (lh *LogHandlers) GetLevels(c *gin.Context) {
|
||||
levels, err := lh.LogRepo.GetDistinctLevels(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get levels"})
|
||||
return
|
||||
}
|
||||
|
||||
if levels == nil {
|
||||
levels = []string{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, levels)
|
||||
}
|
||||
|
||||
// Ensure context is used
|
||||
var _ = context.Background
|
||||
@@ -0,0 +1,86 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// TokenContextKey is the context key for storing authenticated token info.
|
||||
type TokenContextKey string
|
||||
|
||||
const tokenContextKey TokenContextKey = "token"
|
||||
|
||||
// AuthMiddleware validates that a Bearer token exists and is valid.
|
||||
// It stores the token info in the context for later use.
|
||||
// Returns 401 if token is missing or invalid.
|
||||
func (ag *AuthGroup) AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := getTokenFromHeader(c)
|
||||
if token == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Look up user by token value
|
||||
tokens, err := ag.Repo.GetToken(token)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set(string(tokenContextKey), tokens)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RequirePermission is a generic permission checker.
|
||||
func RequirePermission(check func(*repository.Tokens) bool) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
tokenVal, exists := c.Get(string(tokenContextKey))
|
||||
if !exists {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "authentication required"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
token, ok := tokenVal.(*repository.Tokens)
|
||||
if !ok {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "invalid token context"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if !check(token) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RequireView requires permission_view.
|
||||
func RequireView() gin.HandlerFunc {
|
||||
return RequirePermission(func(t *repository.Tokens) bool {
|
||||
return t.PermissionView
|
||||
})
|
||||
}
|
||||
|
||||
// RequireManageAgent requires permission_manage_agent.
|
||||
func RequireManageAgent() gin.HandlerFunc {
|
||||
return RequirePermission(func(t *repository.Tokens) bool {
|
||||
return t.PermissionManage
|
||||
})
|
||||
}
|
||||
|
||||
// RequireAdmin requires permission_admin.
|
||||
func RequireAdmin() gin.HandlerFunc {
|
||||
return RequirePermission(func(t *repository.Tokens) bool {
|
||||
return t.PermissionAdmin
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package models
|
||||
|
||||
type Job struct {
|
||||
ID int64
|
||||
|
||||
JobForInsert
|
||||
JobForUpdate
|
||||
}
|
||||
type JobForInsert struct {
|
||||
Command []string
|
||||
Stdin *string
|
||||
}
|
||||
type JobForUpdate struct {
|
||||
Stdout string
|
||||
Stderr string
|
||||
Status int32
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage"
|
||||
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
|
||||
)
|
||||
|
||||
type LogRepository struct {
|
||||
Conn driver.Conn
|
||||
}
|
||||
|
||||
func NewLogRepository(conn driver.Conn) *LogRepository {
|
||||
return &LogRepository{Conn: conn}
|
||||
}
|
||||
|
||||
func (r *LogRepository) Init(ctx context.Context) error {
|
||||
return r.Conn.Exec(ctx, storage.CreateLogsTable)
|
||||
}
|
||||
|
||||
func (r *LogRepository) Insert(ctx context.Context, log storage.LogEntry) error {
|
||||
return r.Conn.Exec(ctx, `
|
||||
INSERT INTO logs (timestamp, level, service, agent, message)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
`, log.Timestamp, log.Level, log.Service, log.Agent, log.Message)
|
||||
}
|
||||
|
||||
func (r *LogRepository) InsertBatch(ctx context.Context, logs []storage.LogEntry) error {
|
||||
batch, err := r.Conn.PrepareBatch(ctx, "INSERT INTO logs (timestamp, level, service, agent, message)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
if err := batch.Append(log.Timestamp, log.Level, log.Service, log.Agent, log.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return batch.Send()
|
||||
}
|
||||
|
||||
type LogFilter struct {
|
||||
Level string
|
||||
Service string
|
||||
Agent string
|
||||
DateFrom time.Time
|
||||
DateTo time.Time
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
func (r *LogRepository) Search(ctx context.Context, filter LogFilter) ([]storage.LogEntry, error) {
|
||||
query := "SELECT timestamp, level, service, agent, message FROM logs WHERE 1=1"
|
||||
args := make([]interface{}, 0)
|
||||
argIdx := 1
|
||||
|
||||
if filter.Level != "" {
|
||||
query += " AND level = $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.Level)
|
||||
argIdx++
|
||||
}
|
||||
|
||||
if filter.Service != "" {
|
||||
query += " AND service = $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.Service)
|
||||
argIdx++
|
||||
}
|
||||
|
||||
if filter.Agent != "" {
|
||||
query += " AND agent = $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.Agent)
|
||||
argIdx++
|
||||
}
|
||||
|
||||
if !filter.DateFrom.IsZero() {
|
||||
query += " AND timestamp >= $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.DateFrom)
|
||||
argIdx++
|
||||
}
|
||||
|
||||
if !filter.DateTo.IsZero() {
|
||||
query += " AND timestamp <= $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.DateTo)
|
||||
argIdx++
|
||||
}
|
||||
|
||||
query += " ORDER BY timestamp DESC"
|
||||
|
||||
if filter.Limit > 0 {
|
||||
query += " LIMIT $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.Limit)
|
||||
argIdx++
|
||||
} else {
|
||||
query += " LIMIT 100"
|
||||
}
|
||||
|
||||
if filter.Offset > 0 {
|
||||
query += " OFFSET $" + string(rune('0'+argIdx))
|
||||
args = append(args, filter.Offset)
|
||||
}
|
||||
|
||||
rows, err := r.Conn.Query(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var logs []storage.LogEntry
|
||||
for rows.Next() {
|
||||
var log storage.LogEntry
|
||||
if err := rows.Scan(&log.Timestamp, &log.Level, &log.Service, &log.Agent, &log.Message); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logs = append(logs, log)
|
||||
}
|
||||
|
||||
return logs, rows.Err()
|
||||
}
|
||||
|
||||
func (r *LogRepository) GetDistinctServices(ctx context.Context) ([]string, error) {
|
||||
rows, err := r.Conn.Query(ctx, "SELECT DISTINCT service FROM logs ORDER BY service")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var services []string
|
||||
for rows.Next() {
|
||||
var service string
|
||||
if err := rows.Scan(&service); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services = append(services, service)
|
||||
}
|
||||
|
||||
return services, rows.Err()
|
||||
}
|
||||
|
||||
func (r *LogRepository) GetDistinctAgents(ctx context.Context) ([]string, error) {
|
||||
rows, err := r.Conn.Query(ctx, "SELECT DISTINCT agent FROM logs ORDER BY agent")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var agents []string
|
||||
for rows.Next() {
|
||||
var agent string
|
||||
if err := rows.Scan(&agent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agents = append(agents, agent)
|
||||
}
|
||||
|
||||
return agents, rows.Err()
|
||||
}
|
||||
|
||||
func (r *LogRepository) GetDistinctLevels(ctx context.Context) ([]string, error) {
|
||||
rows, err := r.Conn.Query(ctx, "SELECT DISTINCT level FROM logs ORDER BY level")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var levels []string
|
||||
for rows.Next() {
|
||||
var level string
|
||||
if err := rows.Scan(&level); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
levels = append(levels, level)
|
||||
}
|
||||
|
||||
return levels, rows.Err()
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package repository
|
||||
|
||||
// Tokens represents a user record with info and permissions.
|
||||
type Tokens struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
LastName string `json:"last_name"`
|
||||
Login string `json:"login"`
|
||||
Token string `json:"token"`
|
||||
PermissionView bool `json:"permission_view"`
|
||||
PermissionManage bool `json:"permission_manage_agent"`
|
||||
PermissionAdmin bool `json:"permission_admin"`
|
||||
}
|
||||
|
||||
// TokenCreate is the request body for creating a new user.
|
||||
type TokenCreate struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
LastName string `json:"last_name" binding:"required"`
|
||||
Login string `json:"login" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
PermissionView bool `json:"permission_view"`
|
||||
PermissionManage bool `json:"permission_manage_agent"`
|
||||
PermissionAdmin bool `json:"permission_admin"`
|
||||
}
|
||||
|
||||
// LoginRequest is the request body for login.
|
||||
type LoginRequest struct {
|
||||
Login string `json:"login" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
// LoginResponse is returned after successful login.
|
||||
type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
Name string `json:"name"`
|
||||
LastName string `json:"last_name"`
|
||||
Login string `json:"login"`
|
||||
PermissionView bool `json:"permission_view"`
|
||||
PermissionManage bool `json:"permission_manage_agent"`
|
||||
PermissionAdmin bool `json:"permission_admin"`
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/utils"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// Repository wraps a SQLite database connection.
|
||||
type Repository struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// New creates a new Repository.
|
||||
func New(db *sql.DB) *Repository {
|
||||
return &Repository{DB: db}
|
||||
}
|
||||
|
||||
var ErrNotFound = errors.New("not found")
|
||||
|
||||
// Init creates the tokens table if it does not exist.
|
||||
func (r *Repository) Init() error {
|
||||
_, err := r.DB.Exec(storage.CreateSqlite)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateToken inserts a new user record with hashed password and generated token.
|
||||
func (r *Repository) CreateToken(tc TokenCreate) (string, error) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(tc.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
token, err := utils.RandomToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
result, err := r.DB.Exec(
|
||||
`INSERT INTO tokens (name, last_name, login, password, token, permission_view, permission_manage_agent, permission_admin)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
tc.Name, tc.LastName, tc.Login, string(hashed), token,
|
||||
tc.PermissionView, tc.PermissionManage, tc.PermissionAdmin,
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strconv.FormatInt(id, 10), nil
|
||||
}
|
||||
|
||||
// Login authenticates by login/password, generates a new token, and returns LoginResponse.
|
||||
func (r *Repository) Login(login, password string) (*LoginResponse, error) {
|
||||
var t Tokens
|
||||
var hashedPassword string
|
||||
|
||||
err := r.DB.QueryRow(
|
||||
`SELECT id, name, last_name, login, password, token, permission_view, permission_manage_agent, permission_admin
|
||||
FROM tokens WHERE login = ?`,
|
||||
login,
|
||||
).Scan(&t.ID, &t.Name, &t.LastName, &t.Login, &hashedPassword, &t.Token,
|
||||
&t.PermissionView, &t.PermissionManage, &t.PermissionAdmin)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)); err != nil {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
// Generate new token on each login
|
||||
newToken, err := utils.RandomToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = r.DB.Exec(`UPDATE tokens SET token = ? WHERE id = ?`, newToken, t.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LoginResponse{
|
||||
Token: newToken,
|
||||
Name: t.Name,
|
||||
LastName: t.LastName,
|
||||
Login: t.Login,
|
||||
PermissionView: t.PermissionView,
|
||||
PermissionManage: t.PermissionManage,
|
||||
PermissionAdmin: t.PermissionAdmin,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetTokenByToken retrieves a user record by token value.
|
||||
func (r *Repository) GetToken(token string) (*Tokens, error) {
|
||||
var t Tokens
|
||||
err := r.DB.QueryRow(
|
||||
`SELECT id, name, last_name, login, token, permission_view, permission_manage_agent, permission_admin
|
||||
FROM tokens WHERE token = ?`,
|
||||
token,
|
||||
).Scan(&t.ID, &t.Name, &t.LastName, &t.Login, &t.Token,
|
||||
&t.PermissionView, &t.PermissionManage, &t.PermissionAdmin)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// ListTokens returns all users without password and token.
|
||||
func (r *Repository) ListTokens() ([]Tokens, error) {
|
||||
rows, err := r.DB.Query(
|
||||
`SELECT id, name, last_name, login, permission_view, permission_manage_agent, permission_admin
|
||||
FROM tokens`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var tokens []Tokens
|
||||
for rows.Next() {
|
||||
var t Tokens
|
||||
if err := rows.Scan(&t.ID, &t.Name, &t.LastName, &t.Login,
|
||||
&t.PermissionView, &t.PermissionManage, &t.PermissionAdmin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokens = append(tokens, t)
|
||||
}
|
||||
return tokens, rows.Err()
|
||||
}
|
||||
|
||||
// DeleteToken deletes a user by token value.
|
||||
func (r *Repository) DeleteToken(token string) error {
|
||||
result, err := r.DB.Exec(`DELETE FROM tokens WHERE token = ?`, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if affected == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteTokenByLogin deletes a user by login.
|
||||
func (r *Repository) DeleteTokenByLogin(login string) error {
|
||||
result, err := r.DB.Exec(`DELETE FROM tokens WHERE login = ?`, login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if affected == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistsByLogin checks if a user with given login exists.
|
||||
func (r *Repository) ExistsByLogin(login string) bool {
|
||||
var count int
|
||||
err := r.DB.QueryRow(`SELECT COUNT(*) FROM tokens WHERE login = ?`, login).Scan(&count)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return count > 0
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/v2"
|
||||
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
|
||||
)
|
||||
|
||||
type ClickHouseConfig struct {
|
||||
Host string
|
||||
User string
|
||||
Password string
|
||||
Database string
|
||||
}
|
||||
|
||||
func OpenClickHouse(cfg ClickHouseConfig) (driver.Conn, error) {
|
||||
conn, err := clickhouse.Open(&clickhouse.Options{
|
||||
Addr: []string{cfg.Host},
|
||||
Auth: clickhouse.Auth{
|
||||
Database: cfg.Database,
|
||||
Username: cfg.User,
|
||||
Password: cfg.Password,
|
||||
},
|
||||
Settings: clickhouse.Settings{
|
||||
"max_execution_time": 60,
|
||||
},
|
||||
Compression: &clickhouse.Compression{
|
||||
Method: clickhouse.CompressionLZ4,
|
||||
},
|
||||
DialTimeout: 30,
|
||||
MaxOpenConns: 10,
|
||||
MaxIdleConns: 5,
|
||||
ConnMaxLifetime: 3600,
|
||||
ConnOpenStrategy: clickhouse.ConnOpenInOrder,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("clickhouse connect: %w", err)
|
||||
}
|
||||
|
||||
if err := conn.Ping(context.Background()); err != nil {
|
||||
return nil, fmt.Errorf("clickhouse ping: %w", err)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package storage
|
||||
|
||||
import "time"
|
||||
|
||||
type LogEntry struct {
|
||||
Timestamp time.Time `ch:"timestamp"`
|
||||
Level string `ch:"level"`
|
||||
Service string `ch:"service"`
|
||||
Agent string `ch:"agent"`
|
||||
Message string `ch:"message"`
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package storage
|
||||
|
||||
const CreateSqlite = `
|
||||
CREATE TABLE IF NOT EXISTS tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
last_name TEXT NOT NULL,
|
||||
login TEXT NOT NULL UNIQUE,
|
||||
password TEXT NOT NULL,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
permission_view BOOL NOT NULL,
|
||||
permission_manage_agent BOOL NOT NULL,
|
||||
permission_admin BOOL NOT NULL
|
||||
);
|
||||
`
|
||||
|
||||
const CreateLogsTable = `
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
timestamp DateTime64(3) DEFAULT now(),
|
||||
level LowCardinality(String),
|
||||
service LowCardinality(String),
|
||||
agent LowCardinality(String),
|
||||
message String
|
||||
) ENGINE = MergeTree()
|
||||
ORDER BY (timestamp, level, service, agent)
|
||||
TTL timestamp + INTERVAL 30 DAY
|
||||
SETTINGS index_granularity = 8192
|
||||
`
|
||||
@@ -0,0 +1,40 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
var pragmas = map[string]string{
|
||||
`journal_mode`: `wal`,
|
||||
`synchronous`: `normal`,
|
||||
`busy_timeout`: `30000`,
|
||||
}
|
||||
|
||||
func buildSqliteDsn(path string, pragmas map[string]string) string {
|
||||
pragmastrs := make([]string, len(pragmas))
|
||||
i := 0
|
||||
for k, v := range pragmas {
|
||||
pragmastrs[i] = (fmt.Sprintf(`pragma=%s(%s)`, k, v))
|
||||
i++
|
||||
}
|
||||
return path + "?" + "mode=rwc&" + strings.Join(pragmastrs, "&")
|
||||
}
|
||||
|
||||
func Open(path string) (*sql.DB, error) {
|
||||
dsn := buildSqliteDsn(path, pragmas)
|
||||
db, err := sql.Open("sqlite", dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Run migrations
|
||||
if _, err := db.Exec(CreateSqlite); err != nil {
|
||||
return nil, fmt.Errorf("migrate: %w", err)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func RandomToken() (string, error) {
|
||||
token := make([]byte, 32)
|
||||
if _, err := rand.Read(token); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(token), nil
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
.PHONY: docs lint
|
||||
docs:
|
||||
swag init -g ./cmd/main.go --parseDependency --parseInternal
|
||||
|
||||
lint:
|
||||
golangci-lint run --fix
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
# Скрипт генерации SSL сертификатов для mTLS gRPC
|
||||
|
||||
set -e
|
||||
|
||||
CERT_DIR="${1:-/etc/mnemosyne/ssl}"
|
||||
DAYS_VALID=365
|
||||
|
||||
echo "Generating CA and server certificates in ${CERT_DIR}..."
|
||||
|
||||
# Создаём директорию
|
||||
mkdir -p "${CERT_DIR}"
|
||||
|
||||
# Если сертификаты уже есть и не пустые - не перегенерируем
|
||||
if [ -s "${CERT_DIR}/ca.crt" ] && [ -s "${CERT_DIR}/server.crt" ] && [ -s "${CERT_DIR}/server.key" ]; then
|
||||
echo "Certificates already exist, skipping generation."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Если файлы существуют но пустые - удаляем их для перегенерации
|
||||
rm -f "${CERT_DIR}/ca.crt" "${CERT_DIR}/ca.key" "${CERT_DIR}/server.crt" "${CERT_DIR}/server.key" "${CERT_DIR}/server.csr"
|
||||
|
||||
# Генерация CA
|
||||
echo "Generating CA..."
|
||||
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out "${CERT_DIR}/ca.key"
|
||||
openssl req -x509 -new -nodes -sha256 -days ${DAYS_VALID} \
|
||||
-key "${CERT_DIR}/ca.key" \
|
||||
-out "${CERT_DIR}/ca.crt" \
|
||||
-subj "/CN=Mnemosyne Root CA"
|
||||
|
||||
# Генерация серверного сертификата
|
||||
echo "Generating server certificate..."
|
||||
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out "${CERT_DIR}/server.key"
|
||||
openssl req -new -sha256 \
|
||||
-key "${CERT_DIR}/server.key" \
|
||||
-out "${CERT_DIR}/server.csr" \
|
||||
-subj "/CN=${SERVER_CN:-localhost}"
|
||||
|
||||
# Создаём конфиг для server SAN
|
||||
# Поддержка переменных окружения:
|
||||
# SERVER_SAN_DNS - список DNS имен через запятую (например: localhost,backend,myserver.example.com)
|
||||
# SERVER_SAN_IP - список IP адресов через запятую (например: 127.0.0.1,192.168.1.100)
|
||||
cat > "${CERT_DIR}/server.ext" <<EOF
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
EOF
|
||||
|
||||
# Добавляем DNS SAN
|
||||
dns_idx=1
|
||||
IFS=',' read -ra DNS_NAMES <<< "${SERVER_SAN_DNS:-localhost,backend}"
|
||||
for dns_name in "${DNS_NAMES[@]}"; do
|
||||
dns_name=$(echo "$dns_name" | xargs) # trim whitespace
|
||||
if [ -n "$dns_name" ]; then
|
||||
echo "DNS.${dns_idx} = ${dns_name}" >> "${CERT_DIR}/server.ext"
|
||||
((dns_idx++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Добавляем wildcard для localhost если есть
|
||||
echo "DNS.${dns_idx} = *.localhost" >> "${CERT_DIR}/server.ext"
|
||||
((dns_idx++))
|
||||
|
||||
# Добавляем IP SAN
|
||||
ip_idx=1
|
||||
IFS=',' read -ra IP_ADDRS <<< "${SERVER_SAN_IP:-127.0.0.1}"
|
||||
for ip_addr in "${IP_ADDRS[@]}"; do
|
||||
ip_addr=$(echo "$ip_addr" | xargs) # trim whitespace
|
||||
if [ -n "$ip_addr" ]; then
|
||||
echo "IP.${ip_idx} = ${ip_addr}" >> "${CERT_DIR}/server.ext"
|
||||
((ip_idx++))
|
||||
fi
|
||||
done
|
||||
|
||||
openssl x509 -req -sha256 -days ${DAYS_VALID} \
|
||||
-in "${CERT_DIR}/server.csr" \
|
||||
-CA "${CERT_DIR}/ca.crt" \
|
||||
-CAkey "${CERT_DIR}/ca.key" \
|
||||
-CAcreateserial \
|
||||
-out "${CERT_DIR}/server.crt" \
|
||||
-extfile "${CERT_DIR}/server.ext"
|
||||
|
||||
# Очистка лишних файлов
|
||||
rm -f "${CERT_DIR}/server.ext"
|
||||
|
||||
# Установка прав
|
||||
chmod 600 "${CERT_DIR}"/*.key
|
||||
chmod 644 "${CERT_DIR}"/*.crt
|
||||
|
||||
echo "Certificates generated successfully!"
|
||||
echo " CA: ${CERT_DIR}/ca.crt"
|
||||
echo " Server: ${CERT_DIR}/server.crt + ${CERT_DIR}/server.key"
|
||||
echo " SAN DNS: ${SERVER_SAN_DNS:-localhost,backend}"
|
||||
echo " SAN IP: ${SERVER_SAN_IP:-127.0.0.1}"
|
||||
@@ -0,0 +1,16 @@
|
||||
FROM node:25-alpine3.23 AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json yarn.lock ./
|
||||
|
||||
RUN yarn install --frozen-lockfile
|
||||
COPY . .
|
||||
RUN yarn build
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
location /api/ {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Gzip сжатие
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
backend_url: http://backend:8080
|
||||
label: test-agent-1
|
||||
services:
|
||||
- service1
|
||||
- service2
|
||||
@@ -0,0 +1,5 @@
|
||||
database:
|
||||
token_db: /var/lib/hellreign/tokens.db
|
||||
clickhouse_host: clickhouse:9000
|
||||
clickhouse_user: default
|
||||
clickhouse_password: testpassword
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
clickhouse-client --query "CREATE DATABASE IF NOT EXISTS hellreign;"
|
||||
|
||||
clickhouse-client --query "
|
||||
CREATE TABLE IF NOT EXISTS hellreign.logs (
|
||||
timestamp DateTime64(3) DEFAULT now(),
|
||||
level String,
|
||||
service String,
|
||||
message String,
|
||||
host String,
|
||||
trace_id String
|
||||
) ENGINE = MergeTree()
|
||||
ORDER BY (timestamp, service, level);
|
||||
"
|
||||
@@ -0,0 +1,70 @@
|
||||
services:
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:24.8
|
||||
container_name: hellreign-clickhouse
|
||||
environment:
|
||||
CLICKHOUSE_DB: hellreign
|
||||
CLICKHOUSE_USER: default
|
||||
CLICKHOUSE_PASSWORD: testpassword
|
||||
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- clickhouse_data:/var/lib/clickhouse
|
||||
- ./clickhouse/init:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- hellreign
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ../backend
|
||||
dockerfile: dockerfile
|
||||
container_name: hellreign-backend
|
||||
environment:
|
||||
CONFIG_FILE: /etc/hellreign/config.yml
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./backend/config.yml:/etc/hellreign/config.yml:ro
|
||||
- backend_data:/var/lib/hellreign
|
||||
depends_on:
|
||||
- clickhouse
|
||||
networks:
|
||||
- hellreign
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ../frontend
|
||||
dockerfile: dockerfile
|
||||
container_name: hellreign-frontend
|
||||
ports:
|
||||
- "3000:80"
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- hellreign
|
||||
|
||||
agent:
|
||||
build:
|
||||
context: ../agent
|
||||
dockerfile: dockerfile
|
||||
container_name: hellreign-agent
|
||||
environment:
|
||||
CONFIG_FILE: /etc/hellreign-agent/config.yml
|
||||
volumes:
|
||||
- ./agent/config.yml:/etc/hellreign-agent/config.yml:ro
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- hellreign
|
||||
|
||||
volumes:
|
||||
clickhouse_data:
|
||||
driver: local
|
||||
backend_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
hellreign:
|
||||
driver: bridge
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -exuo pipefail
|
||||
|
||||
protogen() {
|
||||
in=./hellreign.proto
|
||||
protoc --go_out="." --go_opt=module="gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto" \
|
||||
--go-grpc_out="." --go-grpc_opt=module="gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto" "$in"
|
||||
}
|
||||
|
||||
"$@"
|
||||
@@ -0,0 +1,16 @@
|
||||
module gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
google.golang.org/grpc v1.80.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
require (
|
||||
go.opentelemetry.io/otel v1.41.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
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=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
|
||||
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
|
||||
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
|
||||
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
|
||||
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
@@ -0,0 +1,33 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package chat;
|
||||
|
||||
option go_package="gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/proto";
|
||||
|
||||
service Collector {
|
||||
rpc Stream(stream CollectorRequest) returns (CollectorResponse);
|
||||
}
|
||||
|
||||
message CollectorRequest {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message CollectorResponse {
|
||||
}
|
||||
|
||||
service Commander {
|
||||
rpc Stream(stream FinishedCommand) returns (stream Command);
|
||||
}
|
||||
|
||||
message Command {
|
||||
int64 id = 1;
|
||||
repeated string command = 2;
|
||||
optional string stdin = 3;
|
||||
}
|
||||
|
||||
message FinishedCommand {
|
||||
int64 id = 1;
|
||||
int32 status = 2;
|
||||
string stdout = 3;
|
||||
string stderr = 4;
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v3.21.9
|
||||
// source: hellreign.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type CollectorRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CollectorRequest) Reset() {
|
||||
*x = CollectorRequest{}
|
||||
mi := &file_hellreign_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *CollectorRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CollectorRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CollectorRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hellreign_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CollectorRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CollectorRequest) Descriptor() ([]byte, []int) {
|
||||
return file_hellreign_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *CollectorRequest) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CollectorResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CollectorResponse) Reset() {
|
||||
*x = CollectorResponse{}
|
||||
mi := &file_hellreign_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *CollectorResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CollectorResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CollectorResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hellreign_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CollectorResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CollectorResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hellreign_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Command []string `protobuf:"bytes,2,rep,name=command,proto3" json:"command,omitempty"`
|
||||
Stdin *string `protobuf:"bytes,3,opt,name=stdin,proto3,oneof" json:"stdin,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Command) Reset() {
|
||||
*x = Command{}
|
||||
mi := &file_hellreign_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Command) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Command) ProtoMessage() {}
|
||||
|
||||
func (x *Command) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hellreign_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Command.ProtoReflect.Descriptor instead.
|
||||
func (*Command) Descriptor() ([]byte, []int) {
|
||||
return file_hellreign_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Command) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Command) GetCommand() []string {
|
||||
if x != nil {
|
||||
return x.Command
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Command) GetStdin() string {
|
||||
if x != nil && x.Stdin != nil {
|
||||
return *x.Stdin
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type FinishedCommand struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Stdout string `protobuf:"bytes,3,opt,name=stdout,proto3" json:"stdout,omitempty"`
|
||||
Stderr string `protobuf:"bytes,4,opt,name=stderr,proto3" json:"stderr,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *FinishedCommand) Reset() {
|
||||
*x = FinishedCommand{}
|
||||
mi := &file_hellreign_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *FinishedCommand) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*FinishedCommand) ProtoMessage() {}
|
||||
|
||||
func (x *FinishedCommand) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hellreign_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FinishedCommand.ProtoReflect.Descriptor instead.
|
||||
func (*FinishedCommand) Descriptor() ([]byte, []int) {
|
||||
return file_hellreign_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *FinishedCommand) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *FinishedCommand) GetStatus() int32 {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *FinishedCommand) GetStdout() string {
|
||||
if x != nil {
|
||||
return x.Stdout
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *FinishedCommand) GetStderr() string {
|
||||
if x != nil {
|
||||
return x.Stderr
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_hellreign_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_hellreign_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x0fhellreign.proto\x12\x04chat\",\n" +
|
||||
"\x10CollectorRequest\x12\x18\n" +
|
||||
"\amessage\x18\x01 \x01(\tR\amessage\"\x13\n" +
|
||||
"\x11CollectorResponse\"X\n" +
|
||||
"\aCommand\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x18\n" +
|
||||
"\acommand\x18\x02 \x03(\tR\acommand\x12\x19\n" +
|
||||
"\x05stdin\x18\x03 \x01(\tH\x00R\x05stdin\x88\x01\x01B\b\n" +
|
||||
"\x06_stdin\"i\n" +
|
||||
"\x0fFinishedCommand\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" +
|
||||
"\x06status\x18\x02 \x01(\x05R\x06status\x12\x16\n" +
|
||||
"\x06stdout\x18\x03 \x01(\tR\x06stdout\x12\x16\n" +
|
||||
"\x06stderr\x18\x04 \x01(\tR\x06stderr2H\n" +
|
||||
"\tCollector\x12;\n" +
|
||||
"\x06Stream\x12\x16.chat.CollectorRequest\x1a\x17.chat.CollectorResponse(\x012?\n" +
|
||||
"\tCommander\x122\n" +
|
||||
"\x06Stream\x12\x15.chat.FinishedCommand\x1a\r.chat.Command(\x010\x01B0Z.gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/protob\x06proto3"
|
||||
|
||||
var (
|
||||
file_hellreign_proto_rawDescOnce sync.Once
|
||||
file_hellreign_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_hellreign_proto_rawDescGZIP() []byte {
|
||||
file_hellreign_proto_rawDescOnce.Do(func() {
|
||||
file_hellreign_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_hellreign_proto_rawDesc), len(file_hellreign_proto_rawDesc)))
|
||||
})
|
||||
return file_hellreign_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_hellreign_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_hellreign_proto_goTypes = []any{
|
||||
(*CollectorRequest)(nil), // 0: chat.CollectorRequest
|
||||
(*CollectorResponse)(nil), // 1: chat.CollectorResponse
|
||||
(*Command)(nil), // 2: chat.Command
|
||||
(*FinishedCommand)(nil), // 3: chat.FinishedCommand
|
||||
}
|
||||
var file_hellreign_proto_depIdxs = []int32{
|
||||
0, // 0: chat.Collector.Stream:input_type -> chat.CollectorRequest
|
||||
3, // 1: chat.Commander.Stream:input_type -> chat.FinishedCommand
|
||||
1, // 2: chat.Collector.Stream:output_type -> chat.CollectorResponse
|
||||
2, // 3: chat.Commander.Stream:output_type -> chat.Command
|
||||
2, // [2:4] is the sub-list for method output_type
|
||||
0, // [0:2] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_hellreign_proto_init() }
|
||||
func file_hellreign_proto_init() {
|
||||
if File_hellreign_proto != nil {
|
||||
return
|
||||
}
|
||||
file_hellreign_proto_msgTypes[2].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_hellreign_proto_rawDesc), len(file_hellreign_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 2,
|
||||
},
|
||||
GoTypes: file_hellreign_proto_goTypes,
|
||||
DependencyIndexes: file_hellreign_proto_depIdxs,
|
||||
MessageInfos: file_hellreign_proto_msgTypes,
|
||||
}.Build()
|
||||
File_hellreign_proto = out.File
|
||||
file_hellreign_proto_goTypes = nil
|
||||
file_hellreign_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v3.21.9
|
||||
// source: hellreign.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Collector_Stream_FullMethodName = "/chat.Collector/Stream"
|
||||
)
|
||||
|
||||
// CollectorClient is the client API for Collector service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type CollectorClient interface {
|
||||
Stream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[CollectorRequest, CollectorResponse], error)
|
||||
}
|
||||
|
||||
type collectorClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCollectorClient(cc grpc.ClientConnInterface) CollectorClient {
|
||||
return &collectorClient{cc}
|
||||
}
|
||||
|
||||
func (c *collectorClient) Stream(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[CollectorRequest, CollectorResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &Collector_ServiceDesc.Streams[0], Collector_Stream_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[CollectorRequest, CollectorResponse]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Collector_StreamClient = grpc.ClientStreamingClient[CollectorRequest, CollectorResponse]
|
||||
|
||||
// CollectorServer is the server API for Collector service.
|
||||
// All implementations must embed UnimplementedCollectorServer
|
||||
// for forward compatibility.
|
||||
type CollectorServer interface {
|
||||
Stream(grpc.ClientStreamingServer[CollectorRequest, CollectorResponse]) error
|
||||
mustEmbedUnimplementedCollectorServer()
|
||||
}
|
||||
|
||||
// UnimplementedCollectorServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedCollectorServer struct{}
|
||||
|
||||
func (UnimplementedCollectorServer) Stream(grpc.ClientStreamingServer[CollectorRequest, CollectorResponse]) error {
|
||||
return status.Error(codes.Unimplemented, "method Stream not implemented")
|
||||
}
|
||||
func (UnimplementedCollectorServer) mustEmbedUnimplementedCollectorServer() {}
|
||||
func (UnimplementedCollectorServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeCollectorServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CollectorServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCollectorServer interface {
|
||||
mustEmbedUnimplementedCollectorServer()
|
||||
}
|
||||
|
||||
func RegisterCollectorServer(s grpc.ServiceRegistrar, srv CollectorServer) {
|
||||
// If the following call panics, it indicates UnimplementedCollectorServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Collector_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Collector_Stream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(CollectorServer).Stream(&grpc.GenericServerStream[CollectorRequest, CollectorResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Collector_StreamServer = grpc.ClientStreamingServer[CollectorRequest, CollectorResponse]
|
||||
|
||||
// Collector_ServiceDesc is the grpc.ServiceDesc for Collector service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Collector_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "chat.Collector",
|
||||
HandlerType: (*CollectorServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Stream",
|
||||
Handler: _Collector_Stream_Handler,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "hellreign.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
Commander_Stream_FullMethodName = "/chat.Commander/Stream"
|
||||
)
|
||||
|
||||
// CommanderClient is the client API for Commander service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type CommanderClient interface {
|
||||
Stream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[FinishedCommand, Command], error)
|
||||
}
|
||||
|
||||
type commanderClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCommanderClient(cc grpc.ClientConnInterface) CommanderClient {
|
||||
return &commanderClient{cc}
|
||||
}
|
||||
|
||||
func (c *commanderClient) Stream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[FinishedCommand, Command], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &Commander_ServiceDesc.Streams[0], Commander_Stream_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[FinishedCommand, Command]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Commander_StreamClient = grpc.BidiStreamingClient[FinishedCommand, Command]
|
||||
|
||||
// CommanderServer is the server API for Commander service.
|
||||
// All implementations must embed UnimplementedCommanderServer
|
||||
// for forward compatibility.
|
||||
type CommanderServer interface {
|
||||
Stream(grpc.BidiStreamingServer[FinishedCommand, Command]) error
|
||||
mustEmbedUnimplementedCommanderServer()
|
||||
}
|
||||
|
||||
// UnimplementedCommanderServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedCommanderServer struct{}
|
||||
|
||||
func (UnimplementedCommanderServer) Stream(grpc.BidiStreamingServer[FinishedCommand, Command]) error {
|
||||
return status.Error(codes.Unimplemented, "method Stream not implemented")
|
||||
}
|
||||
func (UnimplementedCommanderServer) mustEmbedUnimplementedCommanderServer() {}
|
||||
func (UnimplementedCommanderServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeCommanderServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CommanderServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCommanderServer interface {
|
||||
mustEmbedUnimplementedCommanderServer()
|
||||
}
|
||||
|
||||
func RegisterCommanderServer(s grpc.ServiceRegistrar, srv CommanderServer) {
|
||||
// If the following call panics, it indicates UnimplementedCommanderServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Commander_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Commander_Stream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(CommanderServer).Stream(&grpc.GenericServerStream[FinishedCommand, Command]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Commander_StreamServer = grpc.BidiStreamingServer[FinishedCommand, Command]
|
||||
|
||||
// Commander_ServiceDesc is the grpc.ServiceDesc for Commander service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Commander_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "chat.Commander",
|
||||
HandlerType: (*CommanderServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Stream",
|
||||
Handler: _Commander_Stream_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "hellreign.proto",
|
||||
}
|
||||
Reference in New Issue
Block a user