Compare commits
2 Commits
cbcd90732d
...
1cac1d2e66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cac1d2e66 | ||
| 06d3098940 |
12
Dockerfile
12
Dockerfile
@@ -2,16 +2,20 @@ FROM python:3.14-slim
|
|||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
apt-get update; \
|
apt-get update; \
|
||||||
apt-get install -y --no-install-recommends cloc; \
|
apt-get install -y --no-install-recommends cloc git; \
|
||||||
apt-get dist-clean
|
apt-get clean; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN pip install --no-cache-dir discord asyncio requests
|
RUN pip install --no-cache-dir discord.py requests
|
||||||
|
|
||||||
COPY main.py .
|
COPY main.py .
|
||||||
COPY PICable.py .
|
COPY PICable.py .
|
||||||
|
|
||||||
RUN useradd -m appuser
|
RUN useradd -m appuser && \
|
||||||
|
mkdir -p /temp && \
|
||||||
|
chown appuser:appuser /temp
|
||||||
|
|
||||||
USER appuser
|
USER appuser
|
||||||
|
|
||||||
CMD ["python", "main.py"]
|
CMD ["python", "main.py"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
picable:
|
picable:
|
||||||
build: .
|
image: didas72/picable:latest
|
||||||
container_name: picable
|
container_name: picable
|
||||||
environment:
|
environment:
|
||||||
- PICABLE_DISCORD_TOKEN=yourdiscordtoken
|
- PICABLE_DISCORD_TOKEN=yourdiscordtoken
|
||||||
|
|||||||
186
main.py
186
main.py
@@ -11,100 +11,106 @@ MAX_STORAGE_KB = 50 * 1024 * 1024 # 50GB
|
|||||||
DISCORD_TOKEN = os.getenv("PICABLE_DISCORD_TOKEN")
|
DISCORD_TOKEN = os.getenv("PICABLE_DISCORD_TOKEN")
|
||||||
GITHUB_TOKEN = os.getenv("PICABLE_GITHUB_TOKEN")
|
GITHUB_TOKEN = os.getenv("PICABLE_GITHUB_TOKEN")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
current_storage_kb = 0
|
||||||
current_storage_kb = 0
|
storage_condition = Condition()
|
||||||
storage_condition = Condition()
|
current_repositories = set()
|
||||||
current_repositories = set()
|
current_repositories_lock = Lock()
|
||||||
current_repositories_lock = Lock()
|
|
||||||
|
|
||||||
if not DISCORD_TOKEN or not GITHUB_TOKEN:
|
if not DISCORD_TOKEN or not GITHUB_TOKEN:
|
||||||
print("Discord or Github tokens not set in env. Use variables PICABLE_DISCORD_TOKEN and PICABLE_GITHUB_TOKEN")
|
print("Discord or Github tokens not set in env. Use variables PICABLE_DISCORD_TOKEN and PICABLE_GITHUB_TOKEN")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
intents = Intents.default()
|
intents = Intents.default()
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
client = commands.Bot(command_prefix="/", intents=intents)
|
client = commands.Bot(command_prefix="/", intents=intents)
|
||||||
client.run(DISCORD_TOKEN)
|
|
||||||
|
|
||||||
@client.event
|
|
||||||
async def on_ready():
|
@client.event
|
||||||
print(f"We have logged in as {client.user}")
|
async def on_ready():
|
||||||
await client.change_presence(activity=Game("with PIC ideas"))
|
print(f"We have logged in as {client.user}")
|
||||||
|
await client.change_presence(activity=Game("with PIC ideas"))
|
||||||
|
try:
|
||||||
|
synced = await client.tree.sync()
|
||||||
|
print(f"Synced {len(synced)} command(s)")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to sync commands: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
@client.tree.command(name="ping", description="Check the bot's latency.")
|
||||||
|
async def ping(interaction: Interaction):
|
||||||
|
latency = client.latency * 1000
|
||||||
|
await interaction.response.send_message(f"Pong! Latency: {latency:.2f}ms")
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_picable(owner: str, repository: str, repository_size_kb: int, github_token: str):
|
||||||
|
global current_storage_kb
|
||||||
|
async with storage_condition:
|
||||||
|
await storage_condition.wait_for(lambda: current_storage_kb + repository_size_kb <= MAX_STORAGE_KB)
|
||||||
|
current_storage_kb += repository_size_kb
|
||||||
|
|
||||||
|
print(f"Storage is {current_storage_kb / MAX_STORAGE_KB * 100:.2f}% full.")
|
||||||
|
return await to_thread(PICable, owner, repository, github_token)
|
||||||
|
|
||||||
|
|
||||||
|
@client.tree.command(name="picable", description="Check if a Github repository is eligible for PIC.")
|
||||||
|
@app_commands.describe(owner="The owner of the repository", repository="The name of the repository")
|
||||||
|
async def picable(interaction: Interaction, owner: str, repository: str):
|
||||||
|
await interaction.response.defer(thinking=True)
|
||||||
|
|
||||||
|
repository_full_name = f"{owner}/{repository}"
|
||||||
|
async with current_repositories_lock:
|
||||||
|
if repository_full_name in current_repositories:
|
||||||
|
await interaction.followup.send(
|
||||||
|
f"The repository {repository_full_name} is already being analyzed. Please wait for the current analysis to complete. :warning:"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
current_repositories.add(repository_full_name)
|
||||||
|
|
||||||
|
url = f"https://api.github.com/repos/{owner}/{repository}"
|
||||||
|
headers = {"Authorization": f"token {GITHUB_TOKEN}"}
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
|
||||||
|
if not response.status_code == 200:
|
||||||
|
await interaction.followup.send(
|
||||||
|
"Invalid Repository. Please check the repository name and owner and try again. :x:"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
repo_info = response.json()
|
||||||
|
repository_size_kb = repo_info["size"]
|
||||||
|
print(f"Repository size: {repository_size_kb / 1024} MB")
|
||||||
|
|
||||||
|
if repository_size_kb > MAX_STORAGE_KB:
|
||||||
|
await interaction.followup.send(
|
||||||
|
f"The repository {repository_full_name} is too large to analyze. Please try a smaller repository. :warning:"
|
||||||
|
)
|
||||||
|
current_repositories.remove(repository_full_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
global current_storage_kb
|
||||||
|
try:
|
||||||
|
result_future = create_task(handle_picable(owner, repository, repository_size_kb, GITHUB_TOKEN))
|
||||||
try:
|
try:
|
||||||
synced = await client.tree.sync()
|
result = await wait_for(shield(result_future), timeout=600)
|
||||||
print(f"Synced {len(synced)} command(s)")
|
await interaction.followup.send(result)
|
||||||
except Exception as e:
|
except TimeoutError:
|
||||||
print(f"Failed to sync commands: {e}")
|
await interaction.followup.send(
|
||||||
|
f"The analysis for {repository_full_name} is still taking place. The results will be posted here once the analysis is complete. :clock4:"
|
||||||
@client.tree.command(name="ping", description="Check the bot's latency.")
|
)
|
||||||
async def ping(interaction: Interaction):
|
result = await result_future
|
||||||
latency = client.latency * 1000
|
await interaction.channel.send(f"{interaction.user.mention}\n{result}")
|
||||||
await interaction.response.send_message(f"Pong! Latency: {latency:.2f}ms")
|
except Exception as e:
|
||||||
|
print(f"Error processing PICable check: {e}")
|
||||||
async def handle_picable(owner: str, repository: str, repository_size_kb: int, github_token: str):
|
await interaction.channel.send("An error occurred while processing your request. Please try again later.")
|
||||||
global current_storage_kb
|
finally:
|
||||||
async with storage_condition:
|
|
||||||
await storage_condition.wait_for(lambda: current_storage_kb + repository_size_kb <= MAX_STORAGE_KB)
|
|
||||||
current_storage_kb += repository_size_kb
|
|
||||||
|
|
||||||
print(f"Storage is {current_storage_kb / MAX_STORAGE_KB * 100:.2f}% full.")
|
|
||||||
return await to_thread(PICable, owner, repository, github_token)
|
|
||||||
|
|
||||||
@client.tree.command(name="picable", description="Check if a Github repository is eligible for PIC.")
|
|
||||||
@app_commands.describe(owner="The owner of the repository", repository="The name of the repository")
|
|
||||||
async def picable(interaction: Interaction, owner: str, repository: str):
|
|
||||||
await interaction.response.defer(thinking=True)
|
|
||||||
|
|
||||||
repository_full_name = f"{owner}/{repository}"
|
|
||||||
async with current_repositories_lock:
|
async with current_repositories_lock:
|
||||||
if repository_full_name in current_repositories:
|
|
||||||
await interaction.followup.send(
|
|
||||||
f"The repository {repository_full_name} is already being analyzed. Please wait for the current analysis to complete. :warning:"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
current_repositories.add(repository_full_name)
|
|
||||||
|
|
||||||
url = f"https://api.github.com/repos/{owner}/{repository}"
|
|
||||||
headers = {"Authorization": f"token {GITHUB_TOKEN}"}
|
|
||||||
response = requests.get(url, headers=headers)
|
|
||||||
|
|
||||||
if not response.status_code == 200:
|
|
||||||
await interaction.followup.send(
|
|
||||||
"Invalid Repository. Please check the repository name and owner and try again. :x:"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
response.raise_for_status()
|
|
||||||
repo_info = response.json()
|
|
||||||
repository_size_kb = repo_info["size"]
|
|
||||||
print(f"Repository size: {repository_size_kb / 1024} MB")
|
|
||||||
|
|
||||||
if repository_size_kb > MAX_STORAGE_KB:
|
|
||||||
await interaction.followup.send(
|
|
||||||
f"The repository {repository_full_name} is too large to analyze. Please try a smaller repository. :warning:"
|
|
||||||
)
|
|
||||||
current_repositories.remove(repository_full_name)
|
current_repositories.remove(repository_full_name)
|
||||||
return
|
async with storage_condition:
|
||||||
|
current_storage_kb -= repository_size_kb
|
||||||
|
storage_condition.notify_all()
|
||||||
|
|
||||||
global current_storage_kb
|
|
||||||
try:
|
if __name__ == "__main__":
|
||||||
result_future = create_task(handle_picable(owner, repository, repository_size_kb, GITHUB_TOKEN))
|
client.run(DISCORD_TOKEN)
|
||||||
try:
|
|
||||||
result = await wait_for(shield(result_future), timeout=600)
|
|
||||||
await interaction.followup.send(result)
|
|
||||||
except TimeoutError:
|
|
||||||
await interaction.followup.send(
|
|
||||||
f"The analysis for {repository_full_name} is still taking place. The results will be posted here once the analysis is complete. :clock4:"
|
|
||||||
)
|
|
||||||
result = await result_future
|
|
||||||
await interaction.channel.send(f"{interaction.user.mention}\n{result}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error processing PICable check: {e}")
|
|
||||||
await interaction.channel.send("An error occurred while processing your request. Please try again later.")
|
|
||||||
finally:
|
|
||||||
async with current_repositories_lock:
|
|
||||||
current_repositories.remove(repository_full_name)
|
|
||||||
async with storage_condition:
|
|
||||||
current_storage_kb -= repository_size_kb
|
|
||||||
storage_condition.notify_all()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user