Skip to content

Commit

Permalink
Merge pull request #129 from Hornochs/add_automate_server_to_discord
Browse files Browse the repository at this point in the history
Adding Python Script to automatically add Servers to DiscordGSM
  • Loading branch information
BattlefieldDuck authored Feb 3, 2025
2 parents 513d5bc + 39ad0c4 commit 868f340
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 0 deletions.
93 changes: 93 additions & 0 deletions ADD_SERVER_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# DiscordGSM Server Automation Script

Command-line tool to automate adding game servers to DiscordGSM's SQLite database.

## Requirements

- Python 3.6+
- SQLite3
- Access to DiscordGSM's `servers.db` file
- **Important**: Must run in DiscordGSM's virtual environment
```bash
source /path/to/discordgsm/venv/bin/activate # Linux/Mac
# or
\path\to\discordgsm\venv\Scripts\activate # Windows
```

## Installation

1. Save `add_server.py` to your desired location
2. Ensure you have write access to DiscordGSM's database directory

## Usage

### Command Line

```bash
python3 add_server.py \
--guild_id YOUR_GUILD_ID \
--channel_id YOUR_CHANNEL_ID \
--game_id GAME_ID \
--address SERVER_ADDRESS \
--query_port QUERY_PORT \
[--db_path PATH_TO_DB] \
[--ignore-existing]
```

### Arguments

Required:
- `--guild_id`: Discord server (guild) ID
- `--channel_id`: Discord channel ID
- `--game_id`: Game identifier (e.g., "minecraft", "valheim")
- `--address`: Server address/hostname
- `--query_port`: Query port number

Optional:
- `--db_path`: Custom path to `servers.db` (defaults to `./data/servers.db`)
- `--ignore-existing`: Continue execution if server already exists

## Examples

Basic usage:
```bash
python3 add_server.py \
--guild_id 123456789 \
--channel_id 987654321 \
--game_id minecraft \
--address mc.example.com \
--query_port 25565
```

Ignoring existing servers:
```bash
python3 add_server.py \
--guild_id 123456789 \
--channel_id 987654321 \
--game_id valheim \
--address valheim.example.com \
--query_port 2457 \
--ignore-existing
```

## Error Handling

- Validates database existence
- Checks for existing servers with same address and query port
- Provides detailed error messages including channel and game info for existing servers
- Returns exit code 1 on error unless `--ignore-existing` is set

## Ansible Integration

Use `add_servers.yml` for automated deployment:

```yaml
vars:
ignore_existing: true # Set to false to fail on existing servers
```
Key features:
- Database existence validation
- Optional failure on existing servers (`ignore_existing`)
- Detailed output summary
- Proper idempotency handling
151 changes: 151 additions & 0 deletions discordgsm/add_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import sqlite3
import json
from typing import Optional, Dict, Tuple
from dataclasses import dataclass
import os
from pathlib import Path
import argparse
import sys

@dataclass
class ServerConfig:
guild_id: int
channel_id: int
game_id: str
address: str
query_port: int
query_extra: Dict = None
style_id: str = "Medium"
style_data: Dict = None
position: Optional[int] = None
status: bool = False
result: Dict = None
message_id: Optional[int] = None

class DGSMAutomation:
def __init__(self, db_path: str = None):
if db_path is None:
db_path = os.path.join(Path(__file__).parent, "data", "servers.db")
self.db_path = db_path
if not os.path.exists(self.db_path):
raise FileNotFoundError(f"Database not found at {self.db_path}")
self._init_db()

def _init_db(self):
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS servers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
position INT NOT NULL,
guild_id BIGINT NOT NULL,
channel_id BIGINT NOT NULL,
message_id BIGINT,
game_id TEXT NOT NULL,
address TEXT NOT NULL,
query_port INT(5) NOT NULL,
query_extra TEXT NOT NULL,
status INT(1) NOT NULL,
result TEXT NOT NULL,
style_id TEXT NOT NULL,
style_data TEXT NOT NULL
)
''')
conn.commit()

def server_exists(self, address: str, query_port: int) -> Tuple[bool, Optional[Dict]]:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(
'SELECT channel_id, game_id FROM servers WHERE address = ? AND query_port = ?',
(address, query_port)
)
result = cursor.fetchone()
if result:
return True, {
'channel_id': result[0],
'game_id': result[1]
}
return False, None

def add_server(self, config: ServerConfig) -> Tuple[bool, str]:
try:
exists, existing_data = self.server_exists(config.address, config.query_port)
if exists:
return False, f"Server {config.address}:{config.query_port} already exists in channel {existing_data['channel_id']} for game {existing_data['game_id']}"

with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()

if config.position is None:
cursor.execute(
'SELECT COALESCE(MAX(position + 1), 0) FROM servers WHERE channel_id = ?',
(config.channel_id,)
)
config.position = cursor.fetchone()[0]

config.query_extra = config.query_extra or {}
config.style_data = config.style_data or {"locale": "en-US", "timezone": "UTC"}
config.result = config.result or {"name": "", "map": "", "password": False, "raw": {}, "connect": "", "numplayers": 0, "numbots": 0, "maxplayers": 0, "players": [], "bots": []}

cursor.execute('''
INSERT INTO servers (
position, guild_id, channel_id, game_id, address, query_port,
query_extra, status, result, style_id, style_data, message_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
config.position,
config.guild_id,
config.channel_id,
config.game_id,
config.address,
config.query_port,
json.dumps(config.query_extra),
int(config.status),
json.dumps(config.result),
config.style_id,
json.dumps(config.style_data),
config.message_id
))
conn.commit()
return True, f"Successfully added server {config.address}:{config.query_port}"
except sqlite3.Error as e:
return False, f"Database error: {str(e)}"
except Exception as e:
return False, f"Unexpected error: {str(e)}"

def main():
parser = argparse.ArgumentParser(description='Add server to DiscordGSM')
parser.add_argument('--guild_id', type=int, required=True)
parser.add_argument('--channel_id', type=int, required=True)
parser.add_argument('--game_id', type=str, required=True)
parser.add_argument('--address', type=str, required=True)
parser.add_argument('--query_port', type=int, required=True)
parser.add_argument('--db_path', type=str, help='Path to servers.db')
parser.add_argument('--ignore-existing', action='store_true', help='Continue if server exists')

args = parser.parse_args()

try:
automation = DGSMAutomation(db_path=args.db_path)

server_config = ServerConfig(
guild_id=args.guild_id,
channel_id=args.channel_id,
game_id=args.game_id,
address=args.address,
query_port=args.query_port
)

success, message = automation.add_server(server_config)
print(message)

if not success and not args.ignore_existing:
sys.exit(1)

except Exception as e:
print(f"Error: {str(e)}")
sys.exit(1)

if __name__ == "__main__":
main()
43 changes: 43 additions & 0 deletions discordgsm/add_servers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
- name: Add servers to DiscordGSM
hosts: localhost
gather_facts: no

vars:
discordgsm_db: "/path/to/servers.db"
ignore_existing: true # Set to false to fail on existing servers
servers:
- guild_id: 123456789
channel_id: 987654321
game_id: "minecraft"
address: "mc.example.com"
query_port: 25565
# Add more servers as needed

tasks:
- name: Ensure DiscordGSM database exists
stat:
path: "{{ discordgsm_db }}"
register: db_check
failed_when: not db_check.stat.exists

- name: Add server to DiscordGSM
command: >
python3 add_server.py
--guild_id {{ item.guild_id }}
--channel_id {{ item.channel_id }}
--game_id {{ item.game_id }}
--address {{ item.address }}
--query_port {{ item.query_port }}
--db_path {{ discordgsm_db }}
{% if ignore_existing %}--ignore-existing{% endif %}
register: result
failed_when:
- result.rc != 0
- not ignore_existing
changed_when: "'Successfully added server' in result.stdout"
with_items: "{{ servers }}"

- name: Show results
debug:
msg: "{{ result.results | map(attribute='stdout_lines') | list }}"

0 comments on commit 868f340

Please sign in to comment.