mirror of
https://github.com/CopterExpress/clever-show.git
synced 2026-06-02 18:19:33 +00:00
Added client removing functionality
This commit is contained in:
@@ -103,7 +103,7 @@ class Client(object):
|
||||
try:
|
||||
while True:
|
||||
self._reconnect()
|
||||
#self._process_connections()
|
||||
self._process_connections()
|
||||
|
||||
except (KeyboardInterrupt, ):
|
||||
logger.critical("Caught interrupt, exiting!")
|
||||
@@ -138,15 +138,12 @@ class Client(object):
|
||||
self.broadcast_bind(timeout*2, attempt_limit)
|
||||
attempt_count = 0
|
||||
|
||||
|
||||
def _connect(self):
|
||||
self.connected = True
|
||||
self.client_socket.setblocking(False)
|
||||
events = selectors.EVENT_READ # | selectors.EVENT_WRITE
|
||||
self.selector.register(self.client_socket, events, data=self.server_connection)
|
||||
self.server_connection.connect(self.selector, self.client_socket, (self.server_host, self.server_port))
|
||||
self._process_connections()
|
||||
|
||||
|
||||
def broadcast_bind(self, timeout=3.0, attempt_limit=5):
|
||||
broadcast_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
@@ -200,7 +197,7 @@ class Client(object):
|
||||
logger.error(
|
||||
"Exception {} occurred for {}! Resetting connection!".format(error, connection.addr)
|
||||
)
|
||||
self.server_connection.close()
|
||||
self.server_connection._close()
|
||||
self.connected = False
|
||||
|
||||
if isinstance(error, OSError):
|
||||
|
||||
@@ -87,6 +87,14 @@ class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
|
||||
self.endInsertRows()
|
||||
|
||||
def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
|
||||
self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
|
||||
self.data_contents = self.data_contents[:position] + self.data_contents[position + rows:]
|
||||
self.endRemoveRows()
|
||||
print("removed")
|
||||
|
||||
return True
|
||||
|
||||
def user_selected(self, contents=()):
|
||||
contents = contents or self.data_contents
|
||||
return filter(lambda x: x.states.checked == Qt.Checked, contents)
|
||||
@@ -205,6 +213,10 @@ class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
def add_client(self, client):
|
||||
self.insertRows([client])
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def remove_client(self, row):
|
||||
self.removeRows(row)
|
||||
|
||||
|
||||
def col_check(col):
|
||||
def inner(f):
|
||||
@@ -331,6 +343,7 @@ class CopterProxyModel(QtCore.QSortFilterProxyModel):
|
||||
class SignalManager(QtCore.QObject):
|
||||
update_data_signal = QtCore.pyqtSignal(int, int, QtCore.QVariant, QtCore.QVariant)
|
||||
add_client_signal = QtCore.pyqtSignal(object)
|
||||
remove_client_signal = QtCore.pyqtSignal(int)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -161,7 +161,7 @@ class Server:
|
||||
client.process_events(mask)
|
||||
except Exception as error:
|
||||
logging.error("Exception {} occurred for {}! Resetting connection!".format(error, client.addr))
|
||||
client.close()
|
||||
client.close(True)
|
||||
else: # Notifier
|
||||
client.process_events(mask)
|
||||
|
||||
@@ -301,16 +301,29 @@ class Client(messaging.ConnectionManager):
|
||||
def _got_id(self, value):
|
||||
logging.info("Got copter id: {} for client {}".format(value, self.addr))
|
||||
self.copter_id = value
|
||||
if Client.on_first_connect:
|
||||
Client.on_first_connect(self)
|
||||
if self.on_first_connect:
|
||||
self.on_first_connect(self)
|
||||
|
||||
def close(self):
|
||||
def close(self, inner=False):
|
||||
self.connected = False
|
||||
|
||||
if Client.on_disconnect:
|
||||
Client.on_disconnect(self)
|
||||
if self.on_disconnect:
|
||||
self.on_disconnect(self)
|
||||
|
||||
super(Client, self).close()
|
||||
if inner:
|
||||
super(Client, self)._close()
|
||||
else:
|
||||
super(Client, self).close()
|
||||
|
||||
logging.info("Connection to {} closed!".format(self.copter_id))
|
||||
|
||||
def remove(self):
|
||||
if self.connected:
|
||||
self.close()
|
||||
|
||||
print("closed")
|
||||
self.clients.pop(self.addr[0])
|
||||
logging.info("Client {} successfully removed!".format(self.copter_id))
|
||||
|
||||
@requires_connect
|
||||
def _send(self, data):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'server_gui.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.13.1
|
||||
# Created by: PyQt5 UI code generator 5.13.0
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@@ -167,7 +167,7 @@ class Ui_MainWindow(object):
|
||||
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1220, 25))
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1220, 26))
|
||||
self.menubar.setObjectName("menubar")
|
||||
self.menuOptions = QtWidgets.QMenu(self.menubar)
|
||||
self.menuOptions.setObjectName("menuOptions")
|
||||
@@ -222,6 +222,8 @@ class Ui_MainWindow(object):
|
||||
self.actionSend_any_command.setObjectName("actionSend_any_command")
|
||||
self.action_stop_music = QtWidgets.QAction(MainWindow)
|
||||
self.action_stop_music.setObjectName("action_stop_music")
|
||||
self.action_remove_row = QtWidgets.QAction(MainWindow)
|
||||
self.action_remove_row.setObjectName("action_remove_row")
|
||||
self.menuDeveloper_mode.addAction(self.action_send_any_file)
|
||||
self.menuDeveloper_mode.addAction(self.actionSend_any_command)
|
||||
self.menuOptions.addAction(self.action_send_animations)
|
||||
@@ -241,6 +243,7 @@ class Ui_MainWindow(object):
|
||||
self.menuDrone.addAction(self.action_reset_z_offset)
|
||||
self.menuDrone.addSeparator()
|
||||
self.menuDrone.addAction(self.menuDeveloper_mode_2.menuAction())
|
||||
self.menuDrone.addAction(self.action_remove_row)
|
||||
self.menuMusic.addAction(self.action_select_music_file)
|
||||
self.menuMusic.addAction(self.action_play_music)
|
||||
self.menuMusic.addAction(self.action_stop_music)
|
||||
@@ -302,3 +305,14 @@ class Ui_MainWindow(object):
|
||||
self.action_send_any_file.setText(_translate("MainWindow", "Send any file"))
|
||||
self.actionSend_any_command.setText(_translate("MainWindow", "Send any command"))
|
||||
self.action_stop_music.setText(_translate("MainWindow", "Stop music"))
|
||||
self.action_remove_row.setText(_translate("MainWindow", "Remove from table"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
MainWindow = QtWidgets.QMainWindow()
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(MainWindow)
|
||||
MainWindow.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -328,7 +328,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1220</width>
|
||||
<height>25</height>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuOptions">
|
||||
@@ -374,6 +374,7 @@
|
||||
<addaction name="action_reset_z_offset"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuDeveloper_mode_2"/>
|
||||
<addaction name="action_remove_row"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuMusic">
|
||||
<property name="title">
|
||||
@@ -491,6 +492,11 @@
|
||||
<string>Stop music</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_remove_row">
|
||||
<property name="text">
|
||||
<string>Remove from table</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>start_delay_spin</tabstop>
|
||||
|
||||
@@ -68,9 +68,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
self.model = CopterDataModel()
|
||||
self.proxy_model = CopterProxyModel()
|
||||
self.signals = SignalManager()
|
||||
self.gyro_calibrated = {}
|
||||
self.level_calibrated = {}
|
||||
self.first_col_is_checked = False
|
||||
self.player = QtMultimedia.QMediaPlayer()
|
||||
|
||||
self.init_model()
|
||||
@@ -88,6 +85,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
# Connect signals to manipulate model from threads
|
||||
self.signals.update_data_signal.connect(self.model.update_item)
|
||||
self.signals.add_client_signal.connect(self.model.add_client)
|
||||
self.signals.remove_client_signal.connect(self.model.remove_client)
|
||||
|
||||
|
||||
# Connect model signals to UI
|
||||
self.model.selected_ready_signal.connect(self.ui.start_button.setEnabled)
|
||||
@@ -136,6 +135,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
self.ui.calibrate_gyro.clicked.connect(self.calibrate_gyro_selected)
|
||||
self.ui.calibrate_level.clicked.connect(self.calibrate_level_selected)
|
||||
|
||||
self.ui.action_remove_row.triggered.connect(self.remove_selected)
|
||||
|
||||
self.ui.action_send_animations.triggered.connect(self.send_animations)
|
||||
self.ui.action_send_configurations.triggered.connect(self.send_configurations)
|
||||
self.ui.action_send_Aruco_map.triggered.connect(self.send_aruco)
|
||||
@@ -203,6 +204,18 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
self.signals.update_data_signal.emit(row, col, data, Qt.EditRole)
|
||||
|
||||
@pyqtSlot()
|
||||
def remove_selected(self):
|
||||
for copter in self.model.user_selected():
|
||||
row_num = self.model.data_contents.index(copter)
|
||||
|
||||
print(1)
|
||||
copter.client.remove()
|
||||
print(2)
|
||||
|
||||
self.signals.remove_client_signal.emit(row_num)
|
||||
print(3)
|
||||
|
||||
@pyqtSlot()
|
||||
@confirmation_required("This operation will takeoff selected copters with delay and start animation. Proceed?")
|
||||
def send_starttime_selected(self, **kwargs):
|
||||
@@ -284,7 +297,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
lambda x: x.copter_id == client.copter_id, self.model.data_contents)))
|
||||
col = 5
|
||||
data = 'CALIBRATING'
|
||||
self.signals.update_data_signal.emit(row, col, data)
|
||||
self.signals.update_data_signal.emit(row, col, data, Qt.EditRole)
|
||||
# Send request
|
||||
client.get_response("calibrate_gyro", self._get_calibration_info, callback_args=(5, copter.copter_id))
|
||||
|
||||
@@ -297,7 +310,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
lambda x: x.copter_id == client.copter_id, self.model.data_contents)))
|
||||
col = 5
|
||||
data = 'CALIBRATING'
|
||||
self.signals.update_data_signal.emit(row, col, data)
|
||||
self.signals.update_data_signal.emit(row, col, data, Qt.EditRole)
|
||||
# Send request
|
||||
client.get_response("calibrate_level", self._get_calibration_info, callback_args=(5, copter.copter_id))
|
||||
|
||||
@@ -305,7 +318,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
row = self.model.data_contents.index(next(
|
||||
filter(lambda x: x.copter_id == copter_id, self.model.data_contents)))
|
||||
data = str(value)
|
||||
self.signals.update_data_signal.emit(row, col, data)
|
||||
self.signals.update_data_signal.emit(row, col, data, Qt.EditRole)
|
||||
|
||||
@pyqtSlot()
|
||||
def send_animations(self):
|
||||
|
||||
@@ -185,9 +185,7 @@ class ConnectionManager(object):
|
||||
self.socket = None
|
||||
self.addr = None
|
||||
|
||||
self.selector = None
|
||||
self.socket = None
|
||||
self.addr = None
|
||||
self._should_close = False
|
||||
|
||||
self._recv_buffer = b""
|
||||
self._send_buffer = b""
|
||||
@@ -198,6 +196,7 @@ class ConnectionManager(object):
|
||||
|
||||
self._send_lock = threading.Lock()
|
||||
self._request_lock = threading.Lock()
|
||||
self._close_lock = threading.Lock()
|
||||
|
||||
self.BUFFER_SIZE = 1024
|
||||
self.resume_queue = False
|
||||
@@ -225,8 +224,16 @@ class ConnectionManager(object):
|
||||
self._set_selector_events_mask('r')
|
||||
|
||||
def close(self):
|
||||
with self._close_lock:
|
||||
self._should_close = True
|
||||
|
||||
self._set_selector_events_mask('w')
|
||||
NotifierSock().notify()
|
||||
|
||||
def _close(self):
|
||||
logger.info("Closing connection to {}".format(self.addr))
|
||||
try:
|
||||
logger.info("Unregistering selector of {}".format(self.addr))
|
||||
self.selector.unregister(self.socket)
|
||||
except AttributeError:
|
||||
pass
|
||||
@@ -236,6 +243,7 @@ class ConnectionManager(object):
|
||||
self.selector = None
|
||||
|
||||
try:
|
||||
logger.info("Closing socket of of {}".format(self.addr))
|
||||
self.socket.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
@@ -244,7 +252,18 @@ class ConnectionManager(object):
|
||||
finally:
|
||||
self.socket = None
|
||||
|
||||
with self._close_lock:
|
||||
self._should_close = False
|
||||
|
||||
logger.info("CLOSED connection to {}".format(self.addr))
|
||||
|
||||
def process_events(self, mask):
|
||||
with self._close_lock:
|
||||
close = self._should_close
|
||||
if close:
|
||||
self._close()
|
||||
return
|
||||
|
||||
if mask & selectors.EVENT_READ:
|
||||
self.read()
|
||||
if mask & selectors.EVENT_WRITE:
|
||||
|
||||
Reference in New Issue
Block a user