Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rxdn committed Nov 9, 2024
0 parents commit 9126d43
Show file tree
Hide file tree
Showing 17 changed files with 950 additions and 0 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/build-and-publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Build and Publish

env:
REGISTRY: ghcr.io
PACKAGE_NAME: ${{ github.repository }}
GITHUB_SHA: ${{ github.sha }}

on:
push:
branches: [ "main" ]

jobs:
publish-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Print Go version
run: |
go version
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set image name
run: |
echo "IMAGE_NAME=${REGISTRY}/${PACKAGE_NAME,,}:${GITHUB_SHA}" >> ${GITHUB_ENV}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ env.IMAGE_NAME }}
labels: ${{ steps.meta.outputs.labels }}

- name: Log image name
run: |
echo "Image URI: ${IMAGE_NAME}" >> $GITHUB_STEP_SUMMARY
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
.env
main
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Build container
FROM golang:1.22 AS builder

RUN go version

RUN apt-get update && apt-get upgrade -y && apt-get install -y ca-certificates git zlib1g-dev

COPY . /go/src/github.com/TicketsBot/misconduct-detector
WORKDIR /go/src/github.com/TicketsBot/misconduct-detector

RUN git submodule update --init --recursive --remote

RUN set -Eeux && \
go mod download && \
go mod verify

RUN GOOS=linux GOARCH=amd64 \
go build \
-trimpath \
-o main cmd/misconduct-detector/main.go

# Prod container
FROM ubuntu:latest

RUN apt-get update && apt-get upgrade -y && apt-get install -y ca-certificates curl

COPY --from=builder /go/src/github.com/TicketsBot/misconduct-detector/main /srv/misconduct-detector/main

RUN chmod +x /srv/misconduct-detector/main

RUN useradd -m container
USER container
WORKDIR /srv/misconduct-detector

CMD ["/srv/misconduct-detector/main"]
161 changes: 161 additions & 0 deletions cmd/misconduct-detector/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package main

import (
"context"
"fmt"
"github.com/TicketsBot/common/observability"
"github.com/TicketsBot/common/rpc"
"github.com/TicketsBot/misconduct-detector/internal/config"
"github.com/TicketsBot/misconduct-detector/internal/processor"
"github.com/TicketsBot/misconduct-detector/internal/processor/rules"
"github.com/TicketsBot/misconduct-detector/internal/queue"
"github.com/getsentry/sentry-go"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/rxdn/gdl/cache"
"github.com/rxdn/gdl/objects/guild"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"os/signal"
"sync"
"syscall"
"time"
)

func main() {
config := must(config.LoadFromEnv())

// Build logger
if config.SentryDsn != nil {
if err := sentry.Init(sentry.ClientOptions{
Dsn: *config.SentryDsn,
}); err != nil {
panic(fmt.Errorf("sentry.Init: %w", err))
}
}

var logger *zap.Logger
var err error
if config.JsonLogs {
loggerConfig := zap.NewProductionConfig()
loggerConfig.Level.SetLevel(config.LogLevel)

logger, err = loggerConfig.Build(
zap.AddCaller(),
zap.AddStacktrace(zap.ErrorLevel),
zap.WrapCore(observability.ZapSentryAdapter(observability.EnvironmentProduction)),
)
} else {
loggerConfig := zap.NewDevelopmentConfig()
loggerConfig.Level.SetLevel(config.LogLevel)
loggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder

logger, err = loggerConfig.Build(zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))
}

if err != nil {
panic(fmt.Errorf("failed to initialise zap logger: %w", err))
}

// Build app context
appContext := must(buildAppContext(config, logger))

// Connect to Kafka
guildCh := make(chan guild.Guild, 10)
consumer := queue.NewConsumer(config, logger.With(zap.String("module", "consumer")), guildCh)

logger.Info("Starting RPC client")
rpcClient, err := rpc.NewClient(
logger.With(zap.String("service", "rpc-client")),
rpc.Config{
Brokers: config.Kafka.Brokers,
ConsumerConcurrency: 1,
},
map[string]rpc.Listener{
config.Kafka.EventsTopic: consumer,
},
)
if err != nil {
logger.Fatal("Failed to start RPC client", zap.Error(err))
return
}

logger.Info("RPC client started")

wg := &sync.WaitGroup{}
delegators := make([]*processor.Delegator, config.ConcurrentTasks)
for i := 0; i < config.ConcurrentTasks; i++ {
wg.Add(1)

delegator := processor.NewDelegator(
config,
logger.With(zap.String("module", "delegator")),
appContext,
rules.Ruleset,
queue.NewKafkaProducer(config, rpcClient),
guildCh,
)

go func() {
defer wg.Done()
delegator.Run()
}()

delegators[i] = delegator
}

awaitShutdown(logger, wg, delegators)
}

func awaitShutdown(logger *zap.Logger, wg *sync.WaitGroup, delegators []*processor.Delegator) {
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
<-done

logger.Info("Shutting down")
for _, delegator := range delegators {
delegator.Shutdown()
}

wgCh := make(chan struct{})
go func() {
wg.Wait()
close(wgCh)
}()

select {
case <-wgCh:
logger.Info("All delegators have shut down")
case <-time.After(10 * time.Second):
logger.Warn("Some delegators have not shut down, but timeout has expired")
}
}

func buildAppContext(config config.Config, logger *zap.Logger) (*rules.AppContext, error) {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

logger.Info("Connecting to cache")
pool, err := pgxpool.Connect(ctx, config.Cache.Uri)
if err != nil {
return nil, err
}

cache := cache.NewPgCache(pool, cache.CacheOptions{
Guilds: true,
Users: true,
Members: true,
Channels: true,
})
logger.Info("Connected to cache")

return rules.NewAppContext(config, &cache), nil
}

func must[T any](t T, err error) T {
if err != nil {
panic(err)
}

return t
}
43 changes: 43 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module github.com/TicketsBot/misconduct-detector

go 1.22

require (
github.com/TicketsBot/common v0.0.0-20241104184641-e39c64bdcf3e
github.com/caarlos0/env/v11 v11.2.2
github.com/getsentry/sentry-go v0.21.0
github.com/prometheus/client_golang v1.20.5
github.com/rxdn/gdl v0.0.0-20241027214923-02dff700595b
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
golang.org/x/sync v0.8.0
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-redis/redis/v8 v8.11.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/panjf2000/ants/v2 v2.10.0 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/twmb/franz-go v1.18.0 // indirect
github.com/twmb/franz-go/pkg/kmsg v1.9.0 // indirect
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/TicketsBot/common => ../common
Loading

0 comments on commit 9126d43

Please sign in to comment.