-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Steve Lawton
committed
Sep 26, 2024
0 parents
commit c075884
Showing
7 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
DISCORD_BOT_TOKEN= | ||
DISCORD_CHANNEL_ID= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Build Stage | ||
FROM golang:1.22-alpine AS builder | ||
WORKDIR /app | ||
COPY go.mod go.sum ./ | ||
RUN go mod download | ||
COPY . . | ||
RUN go build -o ip-monitor . | ||
|
||
# Run Stage | ||
FROM alpine:latest | ||
RUN apk --no-cache add ca-certificates tzdata | ||
WORKDIR /root/ | ||
COPY --from=builder /app/ip-monitor . | ||
CMD ["./ip-monitor"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# IP Monitor Discord Bot | ||
|
||
This Go application monitors your external IP address and updates a pinned message in a specified Discord channel whenever the IP changes. It also sends a broadcast message notifying about the IP change. | ||
|
||
## Table of Contents | ||
|
||
- [Prerequisites](#prerequisites) | ||
- [Setup Instructions](#setup-instructions) | ||
- [1. Clone the Repository](#1-clone-the-repository) | ||
- [2. Set Up Environment Variables](#2-set-up-environment-variables) | ||
- [3. Build the Docker Image](#3-build-the-docker-image) | ||
- [4. Run the Docker Container](#4-run-the-docker-container) | ||
- [Environment Variables](#environment-variables) | ||
- [Stopping the Bot](#stopping-the-bot) | ||
- [Updating the Bot](#updating-the-bot) | ||
- [Notes](#notes) | ||
- [Troubleshooting](#troubleshooting) | ||
- [License](#license) | ||
|
||
## Prerequisites | ||
|
||
- **Docker**: Ensure Docker is installed on your system. | ||
- **Discord Bot**: You need a Discord bot token and the ID of the channel where the bot will operate. | ||
|
||
## Setup Instructions | ||
|
||
### 1. Clone the Repository | ||
|
||
```bash | ||
git clone https://github.com/yourusername/ip-monitor.git | ||
cd ip-monitor | ||
``` | ||
|
||
### 2. Create a Discord Bot | ||
|
||
- Go to the [Discord Developer Portal](https://discord.com/developers/applications). | ||
- Create a new application and add a bot to it. | ||
- Copy the bot's token; you'll need it for authentication. | ||
- Invite the bot to your server with appropriate permissions (send messages, manage messages). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
version: '3' | ||
|
||
services: | ||
ip-monitor: | ||
build: . | ||
container_name: ip-monitor | ||
restart: unless-stopped | ||
environment: | ||
- DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN} | ||
- DISCORD_CHANNEL_ID=${DISCORD_CHANNEL_ID} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module ip-monitor | ||
|
||
go 1.22 | ||
|
||
require ( | ||
github.com/bwmarrin/discordgo v0.28.1 | ||
github.com/joho/godotenv v1.5.1 | ||
) | ||
|
||
require ( | ||
github.com/gorilla/websocket v1.5.3 // indirect | ||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect | ||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/bwmarrin/discordgo" | ||
"github.com/joho/godotenv" | ||
) | ||
|
||
const ( | ||
ipCheckURL = "https://api.ipify.org" // Service to get external IP | ||
checkInterval = 1 * time.Hour // Interval between IP checks | ||
) | ||
|
||
var ( | ||
previousIP string | ||
) | ||
|
||
func main() { | ||
// Load environment variables from .env file | ||
err := godotenv.Load() | ||
if err != nil { | ||
log.Println("No .env file found or error reading .env file") | ||
} | ||
|
||
// Now you can use os.Getenv to get the variables | ||
botToken := os.Getenv("DISCORD_BOT_TOKEN") | ||
channelID := os.Getenv("DISCORD_CHANNEL_ID") | ||
|
||
if botToken == "" || channelID == "" { | ||
log.Fatal("Bot token or channel ID not set. Please set DISCORD_BOT_TOKEN and DISCORD_CHANNEL_ID.") | ||
} | ||
|
||
// Create a new Discord session | ||
dg, err := discordgo.New("Bot " + botToken) | ||
if err != nil { | ||
log.Fatalf("Error creating Discord session: %v", err) | ||
} | ||
|
||
// Open a WebSocket connection to Discord | ||
err = dg.Open() | ||
if err != nil { | ||
log.Fatalf("Error opening connection to Discord: %v", err) | ||
} | ||
defer dg.Close() | ||
|
||
log.Println("Bot is now running. Press CTRL+C to exit.") | ||
|
||
// Handle graceful shutdown | ||
stop := make(chan os.Signal, 1) | ||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM) | ||
|
||
// Start the IP monitoring in a goroutine | ||
go func() { | ||
for { | ||
currentIP, err := getExternalIP() | ||
if err != nil { | ||
log.Printf("Error fetching external IP: %v", err) | ||
time.Sleep(checkInterval) | ||
continue | ||
} | ||
|
||
if currentIP != previousIP { | ||
log.Printf("IP changed from %s to %s", previousIP, currentIP) | ||
err = updateDiscordMessage(dg, channelID, currentIP) | ||
if err != nil { | ||
log.Printf("Error updating Discord message: %v", err) | ||
} | ||
previousIP = currentIP | ||
} | ||
|
||
time.Sleep(checkInterval) | ||
} | ||
}() | ||
|
||
// Wait for a termination signal | ||
<-stop | ||
log.Println("Shutting down bot.") | ||
} | ||
|
||
func getExternalIP() (string, error) { | ||
resp, err := http.Get(ipCheckURL) | ||
if err != nil { | ||
return "", err | ||
} | ||
defer resp.Body.Close() | ||
|
||
ip, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return string(ip), nil | ||
} | ||
|
||
func updateDiscordMessage(dg *discordgo.Session, channelID, currentIP string) error { | ||
// Fetch pinned messages | ||
pinnedMessages, err := dg.ChannelMessagesPinned(channelID) | ||
if err != nil { | ||
return fmt.Errorf("error fetching pinned messages: %w", err) | ||
} | ||
|
||
var pinnedMessageID string | ||
if len(pinnedMessages) > 0 { | ||
// Assume the first pinned message is the one to update | ||
pinnedMessageID = pinnedMessages[0].ID | ||
_, err = dg.ChannelMessageEdit(channelID, pinnedMessageID, fmt.Sprintf("Current IP Address: `%s`", currentIP)) | ||
if err != nil { | ||
return fmt.Errorf("error editing pinned message: %w", err) | ||
} | ||
} else { | ||
// Send a new message and pin it | ||
msg, err := dg.ChannelMessageSend(channelID, fmt.Sprintf("Current IP Address: `%s`", currentIP)) | ||
if err != nil { | ||
return fmt.Errorf("error sending message: %w", err) | ||
} | ||
|
||
err = dg.ChannelMessagePin(channelID, msg.ID) | ||
if err != nil { | ||
return fmt.Errorf("error pinning message: %w", err) | ||
} | ||
} | ||
|
||
// Send a broadcast message | ||
_, err = dg.ChannelMessageSend(channelID, fmt.Sprintf("IP Address has changed to `%s`", currentIP)) | ||
if err != nil { | ||
return fmt.Errorf("error sending broadcast message: %w", err) | ||
} | ||
|
||
return nil | ||
} |