Made network requests safe, fixed connection reestablish mem leak
This commit is contained in:
parent
f7075b01e3
commit
db315652d1
142
bot.py
142
bot.py
|
@ -39,7 +39,8 @@ class QBittorrentAPICaller():
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
self.reestablish_session()
|
# self.reestablish_session()
|
||||||
|
self.run_session_maintainer()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.logout()
|
self.logout()
|
||||||
|
@ -58,55 +59,122 @@ class QBittorrentAPICaller():
|
||||||
return to_ret
|
return to_ret
|
||||||
|
|
||||||
# We need to reestablish a connection to the server periodically, this does that
|
# We need to reestablish a connection to the server periodically, this does that
|
||||||
def reestablish_session(self):
|
#def reestablish_session(self):
|
||||||
# Every 10 minutes, run this
|
# Every 10 minutes, run this
|
||||||
threading.Timer(600, self.reestablish_session).start()
|
#threading.Timer(600, self.reestablish_session).start()
|
||||||
|
# self.logout()
|
||||||
|
# self.login()
|
||||||
|
# logging.info("Reestablished connection to QBittorrent server")
|
||||||
|
|
||||||
|
def run_session_maintainer(self):
|
||||||
|
def loop():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
self.logout()
|
self.logout()
|
||||||
self.login()
|
self.login()
|
||||||
logging.info("Reestablished connection to QBittorrent server")
|
logging.info("Reestablished connection to QBittorrent server")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Session maintainer error: {e}", exc_info=True)
|
||||||
|
time.sleep(600) # 10 minutes
|
||||||
|
threading.Thread(target=loop, daemon=True).start()
|
||||||
|
|
||||||
def truncate_string(self, s, max_length=25):
|
def truncate_string(self, s, max_length=25):
|
||||||
return s[:max_length] + '...' if len(s) > max_length else s
|
return s[:max_length] + '...' if len(s) > max_length else s
|
||||||
|
|
||||||
|
def safe_get(self, path, params=None):
|
||||||
|
try:
|
||||||
|
# resp = self.session.get(self.url + path, params=params, timeout=5)
|
||||||
|
resp = self.session.get(path, params=params, timeout=5)
|
||||||
|
resp.raise_for_status()
|
||||||
|
return resp
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.warning(f"GET {path} failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def safe_post(self, path, data=None):
|
||||||
|
try:
|
||||||
|
# resp = self.session.post(self.url + path, data=data, timeout=5)
|
||||||
|
resp = self.session.post(path, data=data, timeout=5)
|
||||||
|
resp.raise_for_status()
|
||||||
|
return resp
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.warning(f"POST {path} failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
the_url = self.url + "/" + "api/v2/auth/login"
|
the_url = self.url + "/" + "api/v2/auth/login"
|
||||||
data={"username":self.username, "password":self.password}
|
data={"username":self.username, "password":self.password}
|
||||||
|
|
||||||
resp = self.session.post(the_url, data=data)
|
try:
|
||||||
|
resp = self.session.post(the_url, data=data, timeout=5)
|
||||||
|
resp.raise_for_status()
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.warning(f"Login failed: {e}")
|
||||||
|
#resp = self.session.post(the_url, data=data)
|
||||||
|
|
||||||
def logout(self):
|
def logout(self):
|
||||||
the_url = self.url + "/" + "api/v2/auth/logout"
|
the_url = self.url + "/" + "api/v2/auth/logout"
|
||||||
resp = self.session.post(the_url)
|
# resp = self.session.post(the_url)
|
||||||
|
try:
|
||||||
|
resp = self.session.post(the_url, timeout=5)
|
||||||
|
resp.raise_for_status()
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.warning(f"Logout failed: {e}")
|
||||||
|
|
||||||
|
couldnt_connect_text = "Could not connect to qbittorrent server"
|
||||||
|
|
||||||
def version(self):
|
def version(self):
|
||||||
the_url = self.url + "/" + "api/v2/app/version"
|
the_url = self.url + "/" + "api/v2/app/version"
|
||||||
resp = self.session.get(the_url)
|
# resp = self.session.get(the_url)
|
||||||
if resp.status_code != 200:
|
# if resp.status_code != 200:
|
||||||
return "Got status" + str(resp.status_code)
|
# return "Got status" + str(resp.status_code)
|
||||||
|
# return resp.text
|
||||||
|
resp = self.safe_get(the_url)
|
||||||
|
if not resp:
|
||||||
|
return self.couldnt_connect_text
|
||||||
|
else:
|
||||||
return resp.text
|
return resp.text
|
||||||
|
|
||||||
def webapiVersion(self):
|
def webapiVersion(self):
|
||||||
the_url = self.url + "/" + "api/v2/app/webapiVersion"
|
the_url = self.url + "/" + "api/v2/app/webapiVersion"
|
||||||
resp = self.session.get(the_url)
|
resp = self.safe_get(the_url)
|
||||||
if resp.status_code != 200:
|
if not resp:
|
||||||
return "Got status" + str(resp.status_code)
|
return self.couldnt_connect_text
|
||||||
|
else:
|
||||||
return resp.text
|
return resp.text
|
||||||
|
# try:
|
||||||
|
# resp = self.session.get(the_url)
|
||||||
|
# resp.raise_for_status()
|
||||||
|
# return resp.text
|
||||||
|
# except requests.exceptions.RequestException as e:
|
||||||
|
# logging.warning(f"Couldn't get version")
|
||||||
|
# if resp.status_code != 200:
|
||||||
|
# return "Got status" + str(resp.status_code)
|
||||||
|
|
||||||
def buildInfo(self):
|
def buildInfo(self):
|
||||||
the_url = self.url + "/" + "api/v2/app/buildInfo"
|
the_url = self.url + "/" + "api/v2/app/buildInfo"
|
||||||
resp = self.session.get(the_url)
|
resp = self.safe_get(the_url)
|
||||||
if resp.status_code != 200:
|
if not resp:
|
||||||
return "Got status" + str(resp.status_code)
|
return self.couldnt_connect_text
|
||||||
|
else:
|
||||||
return json_to_key_value_string(resp.text)
|
return json_to_key_value_string(resp.text)
|
||||||
|
|
||||||
|
# resp = self.session.get(the_url)
|
||||||
|
# if resp.status_code != 200:
|
||||||
|
# return "Got status" + str(resp.status_code)
|
||||||
|
|
||||||
|
# return json_to_key_value_string(resp.text)
|
||||||
|
|
||||||
def torrentList(self, modifier=""):
|
def torrentList(self, modifier=""):
|
||||||
the_url = self.url + "/" + "api/v2/torrents/info"
|
the_url = self.url + "/" + "api/v2/torrents/info"
|
||||||
to_ret = "```\n"
|
to_ret = "```\n"
|
||||||
for f in ["downloading", "completed"]:
|
for f in ["downloading", "completed"]:
|
||||||
resp = self.session.post(the_url, data={"filter":f})
|
# resp = self.session.post(the_url, data={"filter":f})
|
||||||
if resp.status_code != 200:
|
# if resp.status_code != 200:
|
||||||
return "Got status" + str(resp.status_code)
|
# return "Got status" + str(resp.status_code)
|
||||||
|
resp = self.safe_post(the_url, data={"filter":f})
|
||||||
|
if not resp:
|
||||||
|
return self.couldnt_connect_text
|
||||||
|
|
||||||
parsed = json.loads(resp.text)
|
parsed = json.loads(resp.text)
|
||||||
to_ret += f.upper() + "\n"
|
to_ret += f.upper() + "\n"
|
||||||
|
@ -122,13 +190,17 @@ class QBittorrentAPICaller():
|
||||||
to_ret += "```"
|
to_ret += "```"
|
||||||
return to_ret
|
return to_ret
|
||||||
|
|
||||||
|
# Too lazy to make this safe, hopefully will be fine idk
|
||||||
def add(self, url, username, category="unknown"):
|
def add(self, url, username, category="unknown"):
|
||||||
if not url.startswith("magnet:"):
|
if not url.startswith("magnet:"):
|
||||||
return "Please supply a magnet link (begins with \"magnet:\")"
|
return "Please supply a magnet link (begins with \"magnet:\")"
|
||||||
|
|
||||||
the_url = self.url + "/" + "api/v2/torrents/add"
|
the_url = self.url + "/" + "api/v2/torrents/add"
|
||||||
|
|
||||||
resp = self.session.post(the_url, data={"urls":url,"category":category,"tags":username})
|
# resp = self.session.post(the_url, data={"urls":url,"category":category,"tags":username})
|
||||||
|
resp = self.safe_post(the_url, data={"urls":url,"category":category,"tags":username})
|
||||||
|
if not resp:
|
||||||
|
return self.couldnt_connect_text
|
||||||
if (resp.status_code == 415):
|
if (resp.status_code == 415):
|
||||||
return "Torrent file not valid"
|
return "Torrent file not valid"
|
||||||
|
|
||||||
|
@ -138,7 +210,10 @@ class QBittorrentAPICaller():
|
||||||
# Make request to torrentlist with particular hash
|
# Make request to torrentlist with particular hash
|
||||||
the_url2 = self.url + "/" + "api/v2/torrents/info"
|
the_url2 = self.url + "/" + "api/v2/torrents/info"
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
resp2 = self.session.post(the_url2)
|
# resp2 = self.session.post(the_url2)
|
||||||
|
resp2 = self.safe_post(the_url2)
|
||||||
|
if not resp2:
|
||||||
|
return self.couldnt_connect_text
|
||||||
if (resp2.status_code != 200):
|
if (resp2.status_code != 200):
|
||||||
return "Could not verify if torrent was added"
|
return "Could not verify if torrent was added"
|
||||||
parsed = json.loads(resp2.text)
|
parsed = json.loads(resp2.text)
|
||||||
|
@ -153,27 +228,39 @@ class QBittorrentAPICaller():
|
||||||
|
|
||||||
def get_search_plugins(self):
|
def get_search_plugins(self):
|
||||||
the_url = self.url + "/" + "api/v2/search/plugins"
|
the_url = self.url + "/" + "api/v2/search/plugins"
|
||||||
return self.session.post(the_url)
|
# return self.session.post(the_url)
|
||||||
|
resp = self.safe_post(the_url)
|
||||||
|
return resp if resp else self.couldnt_connect_text
|
||||||
|
|
||||||
def search_start(self, searchstring, category="all"):
|
def search_start(self, searchstring, category="all"):
|
||||||
the_url = self.url + "/" + "api/v2/search/start"
|
the_url = self.url + "/" + "api/v2/search/start"
|
||||||
return self.session.post(the_url, data={"pattern":searchstring, "plugins":"enabled", "category":category})
|
resp = self.safe_post(the_url, data={"pattern":searchstring, "plugins":"enabled", "category":category})
|
||||||
|
return resp if resp else self.couldnt_connect_text
|
||||||
|
# return self.session.post(the_url, data={"pattern":searchstring, "plugins":"enabled", "category":category})
|
||||||
|
|
||||||
def search_status(self, search_id):
|
def search_status(self, search_id):
|
||||||
the_url = self.url + "/" + "api/v2/search/status"
|
the_url = self.url + "/" + "api/v2/search/status"
|
||||||
return self.session.post(the_url, data={"id":search_id})
|
resp = self.safe_post(the_url, data={"id":search_id})
|
||||||
|
return resp if resp else self.couldnt_connect_text
|
||||||
|
# return self.session.post(the_url, data={"id":search_id})
|
||||||
|
|
||||||
def search_stop(self, search_id):
|
def search_stop(self, search_id):
|
||||||
the_url = self.url + "/" + "api/v2/search/stop"
|
the_url = self.url + "/" + "api/v2/search/stop"
|
||||||
return self.session.post(the_url, data={"id":search_id})
|
resp = self.safe_post(the_url, data={"id":search_id})
|
||||||
|
return resp if resp else self.couldnt_connect_text
|
||||||
|
# return self.session.post(the_url, data={"id":search_id})
|
||||||
|
|
||||||
def search_results(self, search_id):
|
def search_results(self, search_id):
|
||||||
the_url = self.url + "/" + "api/v2/search/results"
|
the_url = self.url + "/" + "api/v2/search/results"
|
||||||
return self.session.post(the_url, data={"id":search_id})
|
resp = self.safe_post(the_url, data={"id":search_id})
|
||||||
|
return resp if resp else self.couldnt_connect_text
|
||||||
|
# return self.session.post(the_url, data={"id":search_id})
|
||||||
|
|
||||||
def search_delete(self, search_id):
|
def search_delete(self, search_id):
|
||||||
the_url = self.url + "/" + "api/v2/search/delete"
|
the_url = self.url + "/" + "api/v2/search/delete"
|
||||||
return self.session.post(the_url, data={"id":search_id})
|
resp = self.safe_post(the_url, data={"id":search_id})
|
||||||
|
return resp if resp else self.couldnt_connect_text
|
||||||
|
# return self.session.post(the_url, data={"id":search_id})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -198,7 +285,8 @@ class QBBot(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
# If you wanted more functionality, here's how to register plugins:
|
# If you wanted more functionality, here's how to register plugins:
|
||||||
# self.register_plugin('xep_0030') # Service Discovery
|
# self.register_plugin('xep_0030') # Service Discovery
|
||||||
# self.register_plugin('xep_0199') # XMPP Ping
|
self.register_plugin('xep_0199') # XMPP Ping
|
||||||
|
self['xep_0199'].enable_keepalive(interval=60, timeout=10)
|
||||||
|
|
||||||
# Here's how to access plugins once you've registered them:
|
# Here's how to access plugins once you've registered them:
|
||||||
# self['xep_0030'].add_feature('echo_demo')
|
# self['xep_0030'].add_feature('echo_demo')
|
||||||
|
|
Loading…
Reference in New Issue