Skip to content

Commit

Permalink
Add .gitignore, pyproject.toml, .github/workflows/run.yml, and prisma…
Browse files Browse the repository at this point in the history
…/schema.prisma files
  • Loading branch information
appujet committed Apr 9, 2024
1 parent a6d13c6 commit 6ed1fbb
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/run.yml
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
6 changes: 6 additions & 0 deletions .gitignore
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
242 changes: 242 additions & 0 deletions main.py
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())


36 changes: 36 additions & 0 deletions prisma/schema.prisma
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
}
18 changes: 18 additions & 0 deletions pyproject.toml
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"

0 comments on commit 6ed1fbb

Please sign in to comment.