diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6178365c..d95f6c4d 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/.idea/pwnagotchi.iml b/.idea/pwnagotchi.iml
index 7e680cfc..b258c893 100644
--- a/.idea/pwnagotchi.iml
+++ b/.idea/pwnagotchi.iml
@@ -4,7 +4,7 @@
-
+
diff --git a/pwnagotchi/__init__.py b/pwnagotchi/__init__.py
index c871ae9d..d0b1ed41 100644
--- a/pwnagotchi/__init__.py
+++ b/pwnagotchi/__init__.py
@@ -3,7 +3,6 @@ import logging
import time
import re
-
from pwnagotchi._version import __version__
_name = None
diff --git a/pwnagotchi/_version.py b/pwnagotchi/_version.py
index a4be3f11..b9fdf8c0 100644
--- a/pwnagotchi/_version.py
+++ b/pwnagotchi/_version.py
@@ -1 +1 @@
-__version__ = '2.3.8'
+__version__ = '2.3.9'
diff --git a/pwnagotchi/bettercap.py b/pwnagotchi/bettercap.py
index 5fd84786..fb57f077 100644
--- a/pwnagotchi/bettercap.py
+++ b/pwnagotchi/bettercap.py
@@ -2,11 +2,18 @@ import json
import logging
import requests
import websockets
+import asyncio
+import random
from requests.auth import HTTPBasicAuth
from time import sleep
-requests.adapters.DEFAULT_RETRIES = 5 # increase retries number
+requests.adapters.DEFAULT_RETRIES = 5 # increase retries number
+
+ping_timeout = 90
+ping_interval = 60
+
+max_sleep = 2.0
def decode(r, verbose_errors=True):
@@ -40,34 +47,62 @@ class Client(object):
async def start_websocket(self, consumer):
s = "%s/events" % self.websocket
- async with websockets.connect(s, ping_interval=60, ping_timeout=90) as ws:
- while True:
- try:
- async for msg in ws:
+
+ # More modern version of the approach below
+ # logging.info("Creating new websocket...")
+ # async for ws in websockets.connect(s):
+ # try:
+ # async for msg in ws:
+ # try:
+ # await consumer(msg)
+ # except Exception as ex:
+ # logging.debug("Error while parsing event (%s)", ex)
+ # except websockets.exceptions.ConnectionClosedError:
+ # sleep_time = max_sleep*random.random()
+ # logger.warning('Retrying websocket connection in {} sec'.format(sleep_time))
+ # await asyncio.sleep(sleep_time)
+ # continue
+
+ # restarted every time the connection fails
+ while True:
+ logging.info("creating new websocket...")
+ try:
+ async with websockets.connect(s, ping_interval=ping_interval, ping_timeout=ping_timeout) as ws:
+ # listener loop
+ while True:
try:
- await consumer(msg)
- except Exception as ex:
- logging.debug("Error while parsing event (%s)", ex)
- except websockets.ConnectionClosedError:
- logging.error("Lost websocket connection. Reconnecting...")
- continue
- except websockets.WebSocketException as wex:
- logging.error("Websocket exception (%s)", wex)
- continue
- except OSError as e:
- logging.error("Websocket OSError exception (%s) with parameter %s", e, s)
- continue
- except Exception as e:
- logging.error("Other exception (%s) with parameter %s", e, s)
- continue
+ async for msg in ws:
+ try:
+ await consumer(msg)
+ except Exception as ex:
+ logging.debug("error while parsing event (%s)", ex)
+ except websockets.exceptions.ConnectionClosedError:
+ try:
+ pong = await ws.ping()
+ await asyncio.wait_for(pong, timeout=ping_timeout)
+ logging.warning('ping OK, keeping connection alive...')
+ continue
+ except:
+ sleep_time = max_sleep*random.random()
+ logging.warning('ping error - retrying connection in {} sec'.format(sleep_time))
+ await asyncio.sleep(sleep_time)
+ break
+ except ConnectionRefusedError:
+ sleep_time = max_sleep*random.random()
+ logging.warning('nobody seems to listen to the bettercap endpoint...')
+ logging.warning('retrying connection in {} sec'.format(sleep_time))
+ await asyncio.sleep(sleep_time)
+ continue
def run(self, command, verbose_errors=True):
- for _ in range(0,2):
+ for _ in range(0, 2):
try:
r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command})
except requests.exceptions.ConnectionError as e:
+ sleep_time = max_sleep*random.random()
logging.exception("Request connection error (%s) while running command (%s)", e, command)
- sleep(1) # Sleep for 1-s before trying a second time
+ logging.warning('Retrying run in {} sec'.format(sleep_time))
+ sleep(sleep_time)
else:
break
diff --git a/pwnagotchi/plugins/__init__.py b/pwnagotchi/plugins/__init__.py
index 8c0a981d..f6104a2e 100644
--- a/pwnagotchi/plugins/__init__.py
+++ b/pwnagotchi/plugins/__init__.py
@@ -76,6 +76,7 @@ def on(event_name, *args, **kwargs):
for plugin_name in loaded.keys():
one(plugin_name, event_name, *args, **kwargs)
+
def locked_cb(lock_name, cb, *args, **kwargs):
global locks
diff --git a/pwnagotchi/plugins/default/bt-tether.py b/pwnagotchi/plugins/default/bt-tether.py
index c0a8ac22..a65c603b 100644
--- a/pwnagotchi/plugins/default/bt-tether.py
+++ b/pwnagotchi/plugins/default/bt-tether.py
@@ -423,7 +423,6 @@ class BTTether(plugins.Plugin):
__license__ = 'GPL3'
__description__ = 'This makes the display reachable over bluetooth'
-
def __init__(self):
self.ready = False
self.options = dict()
@@ -432,7 +431,6 @@ class BTTether(plugins.Plugin):
self.running = True
self.status = '-'
-
def on_loaded(self):
# new config
if 'devices' in self.options:
@@ -574,18 +572,15 @@ class BTTether(plugins.Plugin):
if any_device_connected:
self.status = 'C'
-
def on_unload(self, ui):
self.running = False
with ui._lock:
ui.remove_element('bluetooth')
-
def on_ui_setup(self, ui):
with ui._lock:
ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', position=(ui.width() / 2 - 15, 0),
label_font=fonts.Bold, text_font=fonts.Medium))
-
def on_ui_update(self, ui):
ui.set('bluetooth', self.status)
diff --git a/requirements.txt b/requirements.txt
index cce7d0ec..decdc195 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,4 +22,3 @@ torch
torchvision
stable_baselines3
RPi.GPIO
-backoff