-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add .gitignore, pyproject.toml, .github/workflows/run.yml, and prisma…
…/schema.prisma files
- Loading branch information
Showing
5 changed files
with
335 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,33 @@ | ||
name: Update Nodes | ||
|
||
on: | ||
schedule: | ||
- cron: '*/1 * * * *' # Runs every minute | ||
|
||
jobs: | ||
update: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout Repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: '3.x' | ||
|
||
- name: Install Poetry | ||
run: | | ||
curl -sSL https://install.python-poetry.org | python3 - | ||
- name: Install Dependencies | ||
run: | | ||
poetry install | ||
- name: Run Python Script | ||
env: | ||
DATABASE_URL: ${{ secrets.DATABASE_URL }} | ||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} | ||
run: | | ||
poetry run python3 main.py |
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,6 @@ | ||
node_modules | ||
# Keep environment variables out of version control | ||
.env | ||
|
||
# Ignore poetry lock file | ||
poetry.lock |
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,242 @@ | ||
import json | ||
import aiohttp | ||
import asyncio | ||
from prisma import Prisma | ||
import os | ||
import datetime | ||
|
||
|
||
def format_bytes(size): | ||
if size == 0: | ||
return '0 B' | ||
sizes = ['B', 'KB', 'MB', 'GB', 'TB'] | ||
i = 0 | ||
while size >= 1024: | ||
size /= 1024 | ||
i += 1 | ||
return f"{size:.2f} {sizes[i]}" | ||
|
||
|
||
def uptime(ms): | ||
days = ms // 86400000 | ||
hours = (ms % 86400000) // 3600000 | ||
minutes = ((ms % 86400000) % 3600000) // 60000 | ||
seconds = (((ms % 86400000) % 3600000) % 60000) // 1000 | ||
|
||
parts = [] | ||
if days > 0: | ||
parts.append(f"{days}d") | ||
if hours > 0: | ||
parts.append(f"{hours}h") | ||
if minutes > 0: | ||
parts.append(f"{minutes}m") | ||
if seconds > 0: | ||
parts.append(f"{seconds}s") | ||
|
||
return ' '.join(parts) | ||
|
||
|
||
def get_default_info(): | ||
return { | ||
"version": "Unknown", | ||
"buildTime": datetime.datetime.now().timestamp(), | ||
"git": { | ||
"branch": "Unknown", | ||
"commit": "Unknown", | ||
"commitTime": 0 | ||
}, | ||
"jvm": "Unknown", | ||
"lavaplayer": "Unknown", | ||
"sourceManagers": ["Unknown"], | ||
"filters": ["Unknown"], | ||
"plugins": ["Unknown"] | ||
} | ||
|
||
# Function to update node info in the database | ||
async def update_node_info(db: Prisma, node, info, stats, user): | ||
try: | ||
author_data = { | ||
"authorId": node['authorId'], | ||
"iconUrl": user.get('avatar', 'default_avatar_url'), # Use default value if 'avatar' is missing | ||
"username": user['username'], # No need to handle missing username since it defaults to 'Unknown' in get_user_data | ||
"url": user['url'] | ||
} if user else None | ||
author_json = json.dumps(author_data) | ||
info_json = json.dumps(info) | ||
|
||
await db.node.upsert( | ||
where={"identifier": node['identifier']}, | ||
data={ | ||
"update": { | ||
"authorId": node['authorId'], | ||
"host": node['host'], | ||
"identifier": node['identifier'], | ||
"password": node['password'], | ||
"port": node['port'], | ||
"restVersion": node['restVersion'], | ||
"secure": node['secure'], | ||
"isConnected": True, | ||
"info": info_json, | ||
"memory": f"{format_bytes(stats['memory']['used'])} - {stats['cpu']['lavalinkLoad']:.2f}%", | ||
"cpu": f"{stats['cpu']['systemLoad']:.2f}%", | ||
"connections": f"{stats['playingPlayers']} / {stats['players']}", | ||
"systemLoad": f"{stats['cpu']['systemLoad']:.2f}%", | ||
"cpuCores": stats['cpu']['cores'], | ||
"uptime": uptime(stats['uptime']), | ||
}, | ||
"create": { | ||
"authorId": node['authorId'], | ||
"host": node['host'], | ||
"identifier": node['identifier'], | ||
"password": node['password'], | ||
"port": node['port'], | ||
"restVersion": node['restVersion'], | ||
"secure": node['secure'], | ||
"isConnected": True, | ||
"info": info_json, | ||
"memory": f"{stats['memory']['used']} - {stats['cpu']['lavalinkLoad']:.2f}%", | ||
"cpu": f"{stats['cpu']['systemLoad']:.2f}%", | ||
"connections": f"{stats['playingPlayers']} / {stats['players']}", | ||
"systemLoad": f"{stats['cpu']['systemLoad']:.2f}%", | ||
"cpuCores": stats['cpu']['cores'], | ||
"uptime": uptime(stats['uptime']), | ||
"author": author_json | ||
} | ||
} | ||
) | ||
print(f"Updated node: {node['identifier']}") | ||
except Exception as e: | ||
print(f"Error updating node {node['identifier']} info: {str(e)}") | ||
|
||
# Function to check if a node is online | ||
async def check_node_online(session, db, node): | ||
protocol = "https" if node['secure'] else "http" | ||
base_url = f"{protocol}://{node['host']}:{node['port']}/" | ||
password = node['password'] | ||
version_url = base_url + "version" | ||
info_url = base_url + f"{node['restVersion']}/info" | ||
stats_url = base_url + f"{node['restVersion']}/stats" | ||
|
||
headers = { | ||
"Authorization": password, | ||
'User-Agent': 'Lavalink list Status by (Appu)' | ||
} | ||
try: | ||
async with session.get(version_url, headers=headers, timeout=15) as response: | ||
if response.status == 200: | ||
async with session.get(info_url, headers=headers, timeout=15) as info_response: | ||
async with session.get(stats_url, headers=headers, timeout=15) as stats_response: | ||
if info_response.status == 200 and stats_response.status == 200: | ||
info = await info_response.json() | ||
stats = await stats_response.json() | ||
user = await get_user_data(session, node['authorId']) | ||
await update_node_info(db, node, info, stats, user) | ||
print(f"Updated node: {node['identifier']}") | ||
else: | ||
# Node is offline, update its status in the database | ||
await update_node_offline(db, node) | ||
print(f"{node['identifier']} is offline") | ||
else: | ||
# Node is offline, update its status in the database | ||
user = await get_user_data(session, node['authorId']) | ||
await update_node_offline(db, node, user) | ||
print(f"{node['identifier']} is offline") | ||
except asyncio.TimeoutError: | ||
# Timeout occurred while checking the node status | ||
print(f"Timeout occurred while checking {node['identifier']} status") | ||
# Update the node status in the database to mark it as offline | ||
user = await get_user_data(session, node['authorId']) | ||
await update_node_offline(db, node, user) | ||
except aiohttp.ClientError as e: | ||
# HTTP error occurred while checking the node status | ||
print(f"HTTP error occurred while checking {node['identifier']} status: {str(e)}") | ||
user = await get_user_data(session, node['authorId']) | ||
await update_node_offline(db, node, user) | ||
|
||
|
||
async def update_node_offline(db: Prisma, node, user): | ||
try: | ||
info = get_default_info() | ||
author_data = { | ||
"authorId": node['authorId'], | ||
"iconUrl": user.get('avatar', 'default_avatar_url'), # Use default value if 'avatar' is missing | ||
"username": user['username'], # No need to handle missing username since it defaults to 'Unknown' in get_user_data | ||
"url": user['url'] | ||
} if user else None | ||
author_json = json.dumps(author_data) | ||
info_json = json.dumps(info) | ||
|
||
await db.node.upsert( | ||
where={"identifier": node['identifier']}, | ||
data={ | ||
"update": { | ||
"isConnected": False, | ||
"info": info_json, | ||
"memory": "0 B - 0.0%", | ||
"cpu": "0.0%", | ||
"connections": "0 / 0", | ||
"systemLoad": "0.0%", | ||
"cpuCores": 0, | ||
"uptime": "0s", | ||
}, | ||
"create": { | ||
"authorId": node['authorId'], | ||
"host": node['host'], | ||
"identifier": node['identifier'], | ||
"password": node['password'], | ||
"port": node['port'], | ||
"restVersion": node['restVersion'], | ||
"secure": node['secure'], | ||
"isConnected": False, | ||
"info": info_json, | ||
"memory": "0 B - 0.0%", | ||
"cpu": "0.0%", | ||
"connections": "0 / 0", | ||
"systemLoad": "0.0%", | ||
"cpuCores": 0, | ||
"uptime": "0s", | ||
"author": author_json | ||
} | ||
} | ||
) | ||
except Exception as e: | ||
print(f"Error updating node {node['identifier']} info: {str(e)}") | ||
|
||
|
||
# Load nodes from JSON | ||
with open('nodes.json') as f: | ||
nodes = json.load(f) | ||
|
||
# Fetch user data | ||
async def get_user_data(session, id): | ||
try: | ||
token = os.getenv("DISCORD_TOKEN") | ||
headers = { | ||
"Authorization": f"Bot {token}", | ||
"Content-Type": "application/json" | ||
} | ||
async with session.get(f"https://discord.com/api/v10/users/{id}", headers=headers) as response: | ||
user_data = await response.json() | ||
username = user_data.get('username', 'Unknown') | ||
# Check if 'avatar' field exists, if not set default value | ||
avatar_url = f"https://cdn.discordapp.com/avatars/{id}/{user_data.get('avatar', 'default_avatar')}.png" | ||
user_url = f"https://discord.com/users/{id}" | ||
return {'avatar': avatar_url, 'username': username, 'url': user_url} | ||
except Exception as e: | ||
print(f"Error fetching user data: {str(e)}") | ||
return {'avatar': 'default_avatar_url', 'username': 'Unknown', 'url': ''} | ||
|
||
|
||
async def main(): | ||
db = Prisma() | ||
await db.connect() | ||
|
||
async with aiohttp.ClientSession() as session: | ||
tasks = [check_node_online(session, db, node) for node in nodes] | ||
await asyncio.gather(*tasks) | ||
|
||
await db.disconnect() | ||
|
||
asyncio.run(main()) | ||
|
||
|
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,36 @@ | ||
// This is your Prisma schema file, | ||
// learn more about it in the docs: https://pris.ly/d/prisma-schema | ||
|
||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? | ||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init | ||
|
||
generator client { | ||
provider = "prisma-client-py" | ||
} | ||
|
||
datasource db { | ||
provider = "postgresql" | ||
url = env("DATABASE_URL") | ||
} | ||
|
||
model Node { | ||
id String @id @default(cuid()) | ||
authorId String | ||
host String | ||
identifier String @unique | ||
password String | ||
port Int | ||
restVersion String | ||
secure Boolean | ||
isConnected Boolean @default(false) | ||
info Json? | ||
author Json? | ||
memory String? | ||
connections String? | ||
systemLoad String? | ||
cpuCores Int? | ||
uptime String? | ||
cpu String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
} |
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,18 @@ | ||
[tool.poetry] | ||
name = "lavalink-list" | ||
version = "0.1.0" | ||
description = "" | ||
authors = ["brblacky <[email protected]>"] | ||
readme = "README.md" | ||
|
||
[tool.poetry.dependencies] | ||
python = "^3.10" | ||
requests = "^2.31.0" | ||
asyncio = "^3.4.3" | ||
prisma = "^0.13.1" | ||
aiohttp = "^3.9.3" | ||
|
||
|
||
[build-system] | ||
requires = ["poetry-core"] | ||
build-backend = "poetry.core.masonry.api" |