mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
- Update to red-lavalink v0.2.0 (blocked by Cog-Creators/Red-Lavalink#41) - Force lavalink to use TLSv1.2 on java 11+ (blocked by #2270) I would add equalizer support, but there's no way to know the full Lavalink version and thus whether it's supported ahead of time.
131 lines
3.7 KiB
Python
131 lines
3.7 KiB
Python
import shlex
|
|
import shutil
|
|
import asyncio
|
|
import asyncio.subprocess
|
|
import os
|
|
import logging
|
|
import re
|
|
from subprocess import Popen, DEVNULL
|
|
from typing import Optional, Tuple
|
|
|
|
_JavaVersion = Tuple[int, int]
|
|
|
|
log = logging.getLogger("red.audio.manager")
|
|
|
|
proc = None
|
|
SHUTDOWN = asyncio.Event()
|
|
|
|
|
|
def has_java_error(pid):
|
|
from . import LAVALINK_DOWNLOAD_DIR
|
|
|
|
poss_error_file = LAVALINK_DOWNLOAD_DIR / "hs_err_pid{}.log".format(pid)
|
|
return poss_error_file.exists()
|
|
|
|
|
|
async def monitor_lavalink_server(loop):
|
|
while not SHUTDOWN.is_set():
|
|
if proc.poll() is not None:
|
|
break
|
|
await asyncio.sleep(0.5)
|
|
|
|
if not SHUTDOWN.is_set():
|
|
log.info("Lavalink jar shutdown.")
|
|
if not has_java_error(proc.pid):
|
|
log.info("Restarting Lavalink jar.")
|
|
await start_lavalink_server(loop)
|
|
else:
|
|
log.error(
|
|
"Your Java is borked. Please find the hs_err_pid{}.log file"
|
|
" in the Audio data folder and report this issue.".format(proc.pid)
|
|
)
|
|
|
|
|
|
async def has_java(loop) -> Tuple[bool, Optional[_JavaVersion]]:
|
|
java_available = shutil.which("java") is not None
|
|
if not java_available:
|
|
return False, None
|
|
|
|
version = await get_java_version(loop)
|
|
return (2, 0) > version >= (1, 8) or version >= (8, 0), version
|
|
|
|
|
|
async def get_java_version(loop) -> _JavaVersion:
|
|
"""
|
|
This assumes we've already checked that java exists.
|
|
"""
|
|
_proc: asyncio.subprocess.Process = await asyncio.create_subprocess_exec(
|
|
"java",
|
|
"-version",
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
loop=loop,
|
|
)
|
|
# java -version outputs to stderr
|
|
_, err = await _proc.communicate()
|
|
|
|
version_info: str = err.decode("utf-8")
|
|
# We expect the output to look something like:
|
|
# $ java -version
|
|
# ...
|
|
# ... version "MAJOR.MINOR.PATCH[_BUILD]" ...
|
|
# ...
|
|
# We only care about the major and minor parts though.
|
|
version_line_re = re.compile(
|
|
r'version "(?P<major>\d+).(?P<minor>\d+).\d+(?:_\d+)?(?:-[A-Za-z0-9]+)?"'
|
|
)
|
|
short_version_re = re.compile(r'version "(?P<major>\d+)"')
|
|
|
|
lines = version_info.splitlines()
|
|
for line in lines:
|
|
match = version_line_re.search(line)
|
|
short_match = short_version_re.search(line)
|
|
if match:
|
|
return int(match["major"]), int(match["minor"])
|
|
elif short_match:
|
|
return int(short_match["major"]), 0
|
|
|
|
raise RuntimeError(
|
|
"The output of `java -version` was unexpected. Please report this issue on Red's "
|
|
"issue tracker."
|
|
)
|
|
|
|
|
|
async def start_lavalink_server(loop):
|
|
java_available, java_version = await has_java(loop)
|
|
if not java_available:
|
|
raise RuntimeError("You must install Java 1.8+ for Lavalink to run.")
|
|
|
|
if java_version == (1, 8):
|
|
extra_flags = "-Dsun.zip.disableMemoryMapping=true"
|
|
elif java_version >= (11, 0):
|
|
extra_flags = "-Djdk.tls.client.protocols=TLSv1.2"
|
|
else:
|
|
extra_flags = ""
|
|
|
|
from . import LAVALINK_DOWNLOAD_DIR, LAVALINK_JAR_FILE
|
|
|
|
start_cmd = "java {} -jar {}".format(extra_flags, LAVALINK_JAR_FILE.resolve())
|
|
|
|
global proc
|
|
proc = Popen(
|
|
shlex.split(start_cmd, posix=os.name == "posix"),
|
|
cwd=str(LAVALINK_DOWNLOAD_DIR),
|
|
stdout=DEVNULL,
|
|
stderr=DEVNULL,
|
|
)
|
|
|
|
log.info("Lavalink jar started. PID: {}".format(proc.pid))
|
|
|
|
loop.create_task(monitor_lavalink_server(loop))
|
|
|
|
|
|
def shutdown_lavalink_server():
|
|
log.info("Shutting down lavalink server.")
|
|
SHUTDOWN.set()
|
|
global proc
|
|
if proc is not None:
|
|
proc.terminate()
|
|
proc.wait()
|
|
proc = None
|