Skip to content

Commit

Permalink
Added GORM for database and DiscordGo, simple bot connects and does n…
Browse files Browse the repository at this point in the history
…othing useful
  • Loading branch information
Scott Bragg committed Dec 26, 2024
1 parent 18870c2 commit 4b0dfb8
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 28 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/go-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Lint Go Project

on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev

jobs:
lint:
name: Run Go Lint
runs-on: ubuntu-latest

steps:
# Checkout the repository
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0

- uses: actions/setup-go@v4
with:
go-version: '1.21'
cache: false

# Cache Go modules
- name: Cache Go Modules
uses: actions/cache@v3
with:
path: /go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
# Install golangci-lint
- name: Install golangci-lint
run: |
go install github.com/golangci/golangci-lint/cmd/[email protected]
# Run make lint
- name: Run Linting
run: make lint
40 changes: 40 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Use the official Golang image as the build environment
FROM golang:1.23-alpine AS builder

# Install dependencies required to run the Makefile
RUN apk add --no-cache make

# Set the working directory
WORKDIR /app

# Copy the source code and Makefile into the container
COPY . .

# Run the Makefile target to build the bot binary
RUN make build

# Use a minimal base image for the final container
FROM alpine:latest

# Set the working directory
WORKDIR /app

# Install required runtime dependencies
RUN apk add --no-cache ca-certificates

# Copy the binary from the builder
COPY --from=builder /app/bin/bot /app/bin/bot

# Set environment variables for database connection
ENV DB_HOST=postgres
ENV DB_PORT=5432
ENV DB_USER=napandgo
ENV DB_PASSWORD=napandgo
ENV DB_NAME=napandgo
ENV DB_SSLMODE=disable

# Expose any required ports (optional)
EXPOSE 8080

# Run the bot binary
CMD ["/app/bin/bot"]
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ DOCKER_COMPOSE_FILE=docker-compose.yaml
# Go build parameters
GO_BUILD_CMD=go build
GO_FILES=./...
CGO_ENABLED=0

# Targets
.PHONY: all build bot web run lint test clean docker docker-compose up down info
Expand All @@ -18,7 +19,7 @@ build: bot

# Build the Discord bot binary
bot:
$(GO_BUILD_CMD) -o bin/bot ./cmd/bot
CGO_ENABLED=$(CGO_ENABLED) $(GO_BUILD_CMD) -o bin/bot ./cmd/bot

# Build the web interface binary
web:
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# nap-and-go
# nap-and-go

My way to learn Go by creating a Discord bot with a bunch of features

## Features

- Connects to its own database
- Connects to discord
- Replies to a message when it is sent a message in a channel

Features will be added as they get completed
84 changes: 67 additions & 17 deletions cmd/bot/bot.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,82 @@
// Initializes and runs the Discord bot
// Initializes and runs the Discord bot and connects to the database.
package main

import (
"fmt"
"log"
"github.com/faulteh/nap-and-go/pkg/greetings"
"rsc.io/quote"
"os"
"os/signal"
"syscall"

"github.com/bwmarrin/discordgo"

"github.com/faulteh/nap-and-go/db"
"github.com/faulteh/nap-and-go/models"
)

func main() {
// Set properties of the predefined Logger, including
// the log entry prefix and a flag to disable printing
// the time, source file, and line number.
log.SetPrefix("bot: ")
log.SetFlags(0)
// Initialize the database connection
db.Connect()
// Get the database connection
conn := db.GetDB()

// AutoMigrate the models
log.Println("Auto-migrating models")
err := conn.AutoMigrate(&models.Server{}, &models.User{})
if err != nil {
log.Fatalf("failed to auto-migrate models: %v", err)
return
}

fmt.Println(quote.Go())
// Load the bot token from an environment variable
token := os.Getenv("DISCORD_BOT_TOKEN")
if token == "" {
log.Println("Please set the DISCORD_BOT_TOKEN environment variable")
return
}

// A slice of names.
names := []string{"Ardenne", "Sam", "Liz"}
// Create a new Discord session
dg, err := discordgo.New("Bot " + token)
if err != nil {
log.Println("Error creating Discord session:", err)
return
}

// Request greeting messages for the names.
messages, err := greetings.Hellos(names)
// Register the message handler
dg.AddHandler(messageCreate)

// If an error was returned, print it to the console and exit the program.
// Open a connection to Discord
err = dg.Open()
if err != nil {
log.Println("Error opening connection:", err)
return
}
log.Println("Bot is now running. Press CTRL+C to exit.")

// Wait for a signal to exit
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
<-stop

// Cleanly close the Discord session
err = dg.Close()
if err != nil {
log.Fatal(err)
log.Println("Error closing Discord session:", err)
}
log.Println("Bot has been stopped.")
}

// messageCreate is called whenever a new message is created in a channel the bot has access to
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages from the bot itself
if m.Author.ID == s.State.User.ID {
return
}

fmt.Println(messages)
// Respond to "!ping"
if m.Content == "!ping" {
_, err := s.ChannelMessageSend(m.ChannelID, "Pong!")
if err != nil {
log.Println("Error sending message:", err)
}
}
}
44 changes: 44 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Package config provides the configuration for the application.
package config

import (
"fmt"
"os"
)

// DBConfig holds the database configuration.
type DBConfig struct {
Host string
Port string
User string
Password string
DBName string
SSLMode string
}

// LoadDBConfig loads the database configuration from environment variables.
func LoadDBConfig() *DBConfig {
return &DBConfig{
Host: getEnv("DB_HOST", "postgres"),
Port: getEnv("DB_PORT", "5432"),
User: getEnv("DB_USER", "napandgo"),
Password: getEnv("DB_PASSWORD", "napandgo"),
DBName: getEnv("DB_NAME", "napandgo"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
}
}

// getEnv gets an environment variable with a default fallback.
func getEnv(key, defaultValue string) string {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value
}

// DSN returns the PostgreSQL Data Source Name.
func (c *DBConfig) DSN() string {
return fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
c.Host, c.Port, c.User, c.Password, c.DBName, c.SSLMode)
}
50 changes: 50 additions & 0 deletions db/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Package db provides a database connection and helper functions to interact with the database.
package db

import (
"log"
"time"

"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"

"github.com/faulteh/nap-and-go/config"
)

// DB holds the global database connection.
var DB *gorm.DB

// Connect initializes the database connection.
func Connect() {
cfg := config.LoadDBConfig()

// Custom logger for GORM
newLogger := logger.New(
log.New(log.Writer(), "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second, // Slow SQL threshold
LogLevel: logger.Info, // Log level
IgnoreRecordNotFoundError: true, // Ignore record not found errors
Colorful: true, // Enable color in logs
},
)

var err error
DB, err = gorm.Open(postgres.Open(cfg.DSN()), &gorm.Config{
Logger: newLogger,
})
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}

log.Println("Database connection established")
}

// GetDB returns the database instance.
func GetDB() *gorm.DB {
if DB == nil {
log.Fatal("Database connection is not initialized. Call Connect() first.")
}
return DB
}
35 changes: 35 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
services:
bot:
build:
context: .
dockerfile: Dockerfile
container_name: bot
depends_on:
- postgres
environment:
- DB_HOST=postgres
- DB_PORT=5432
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_NAME}
- DB_SSLMODE=disable
volumes:
- ./bin:/app/bin
command: ["sh", "-c", "while :; do sleep infinity; done"]
# command: ["./bin/bot"]
restart: always

postgres:
image: postgres:16
container_name: postgres
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:
23 changes: 20 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,28 @@ module github.com/faulteh/nap-and-go

go 1.23.4

require rsc.io/quote v1.5.2
require (
gorm.io/driver/postgres v1.5.11
gorm.io/gorm v1.25.12
)

require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/sampler v1.3.0 // indirect
github.com/bwmarrin/discordgo v0.28.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
)

replace github.com/faulteh/nap-and-go/pkg => ./pkg

replace github.com/faulteh/nap-and-go/config => ./config

replace github.com/faulteh/nap-and-go/db => ./db
Loading

0 comments on commit 4b0dfb8

Please sign in to comment.