def respond(self, byteArray, meta=None): if not self.conn: return False self.log("Sending Response. dataType: {0}, renderId: {1}".format( meta.get("dataType"), meta.get("renderId"))) obj = {"type": self.TYPE_RESPONSE, "meta": meta or {}} memKey = self.nextMemoryKey() obj["memoryKey"] = memKey # TODO: check that the memory segment is not used # store data in shared memory mem = QSharedMemory(memKey) if mem.isAttached(): mem.detach() if not mem.create(len(byteArray)): self.log(mem.errorString()) return False self.log("Shared memory created: {0}, {1} bytes".format( memKey, len(byteArray))) mem.lock() try: ctypes.memmove(int(mem.data()), byteArray, len(byteArray)) finally: mem.unlock() self._mem[memKey] = mem self.conn.write(json.dumps(obj).encode("utf-8") + b"\n") self.conn.flush() return True
class MemoryCondition: def __init__(self, key='memory_condition_key'): self._shm = QSharedMemory(key) if not self._shm.attach(): if not self._shm.create(1): raise RuntimeError('error creating shared memory: %s' % self._shm.errorString()) self.condition = False def __enter__(self): self._shm.lock() if self._shm.data()[0] == b'\x00': self.condition = True self._shm.data()[0] = b'\x01' self._shm.unlock() return self.condition def __exit__(self, exc_type, exc_value, traceback): if self.condition: self._shm.lock() self._shm.data()[0] = b'\x00' self._shm.unlock()
class LivePlotClient(object): def __init__(self, timeout=2000, size=2**28): self.app = QCoreApplication.instance() if self.app is None: self.app = QCoreApplication([]) self.sock = QLocalSocket() self.sock.connectToServer("LivePlot") if not self.sock.waitForConnected(): raise EnvironmentError("Couldn't find LivePlotter instance") self.sock.disconnected.connect(self.disconnect_received) key = str(uuid.uuid4()) self.shared_mem = QSharedMemory(key) if not self.shared_mem.create(size): raise Exception("Couldn't create shared memory %s" % self.shared_mem.errorString()) logging.debug('Memory created with key %s and size %s' % (key, self.shared_mem.size())) self.sock.write(key.encode()) self.sock.waitForBytesWritten() self.is_connected = True self.timeout = timeout atexit.register(self.close) def close(self): self.shared_mem.detach() def send_to_plotter(self, meta, arr=None): if not self.is_connected: return if meta["name"] is None: meta["name"] = "*" if arr is not None: arrbytes = bytearray(arr) arrsize = len(arrbytes) if arrsize > self.shared_mem.size(): raise ValueError("Array too big %s > %s" % (arrsize, self.shared_mem.size())) meta['arrsize'] = arrsize meta['dtype'] = str(arr.dtype) meta['shape'] = arr.shape else: meta['arrsize'] = 0 meta_bytes = json.dumps(meta).ljust(300) if len(meta_bytes) > 300: raise ValueError("meta object is too large (> 300 char)") if arr is None: self.sock.write(meta_bytes.encode()) else: if not self.sock.bytesAvailable(): self.sock.waitForReadyRead() self.sock.read(2) self.shared_mem.lock() self.sock.write(meta_bytes.encode()) region = self.shared_mem.data() region[:arrsize] = arrbytes self.shared_mem.unlock() def plot_y(self, name, arr, extent=None, start_step=(0, 1), label=''): arr = np.array(arr) if extent is not None and start_step is not None: raise ValueError( 'extent and start_step provide the same info and are thus mutually exclusive' ) if extent is not None: x0, x1 = extent nx = len(arr) start_step = x0, float(x1 - x0) / nx meta = { 'name': name, 'operation': 'plot_y', 'start_step': start_step, 'rank': 1, 'label': label, } self.send_to_plotter(meta, arr.astype('float64')) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def plot_z(self, name, arr, extent=None, start_step=None, xname='X axis',\ xscale='arb. u.', yname='Y axis', yscale='arb. u.', zname='Y axis', zscale='arb. u.'): ''' extent is ((initial x, final x), (initial y, final y)) start_step is ((initial x, delta x), (initial_y, final_y)) ''' arr = np.array(arr) if extent is not None and start_step is not None: raise ValueError( 'extent and start_step provide the same info and are thus mutually exclusive' ) if extent is not None: (x0, x1), (y0, y1) = extent nx, ny = arr.shape start_step = (x0, float(x1 - x0) / nx), (y0, float(y1 - y0) / ny) meta = { 'name': name, 'operation': 'plot_z', 'rank': 2, 'start_step': start_step, 'X': xscale, 'Y': yscale, 'Z': zscale, 'Xname': xname, 'Yname': yname, 'Zname': zname, } self.send_to_plotter(meta, arr.astype('float64')) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def plot_xy(self, name, xs, ys, label='', xname='X axis', xscale='arb. u.',\ yname='Y axis', yscale='arb. u.', scatter='False', timeaxis='False'): arr = np.array([xs, ys]) meta = { 'name': name, 'operation': 'plot_xy', 'rank': 1, 'label': label, 'X': xscale, 'Y': yscale, 'Xname': xname, 'Yname': yname, 'Scatter': scatter, 'TimeAxis': timeaxis } self.send_to_plotter(meta, np.array([xs, ys]).astype('float64')) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def append_y(self, name, point, start_step=(0, 1), label='', xname='X axis',\ xscale='arb. u.', yname='Y axis', yscale='arb. u.',scatter='False', timeaxis='False'): self.send_to_plotter({ 'name': name, 'operation': 'append_y', 'value': point, 'start_step': start_step, 'rank': 1, 'label': label, 'X': xscale, 'Y': yscale, 'Xname': xname, 'Yname': yname, 'Scatter': scatter, 'TimeAxis': timeaxis }) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def append_xy(self, name, x, y, label=''): self.send_to_plotter({ 'name': name, 'operation': 'append_xy', 'value': (x, y), 'rank': 1, 'label': label, }) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def append_z(self, name, arr, start_step=None, xname='X axis',\ xscale='arb. u.', yname='Y axis', yscale='arb. u.', zname='Y axis', zscale='arb. u.'): arr = np.array(arr) meta = { 'name': name, 'operation': 'append_z', 'rank': 2, 'start_step': start_step, 'X': xscale, 'Y': yscale, 'Z': zscale, 'Xname': xname, 'Yname': yname, 'Zname': zname, } self.send_to_plotter(meta, arr.astype('float64')) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def label(self, name, text): self.send_to_plotter({ 'name': name, 'operation': 'label', 'value': text }) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def clear(self, name=None): self.send_to_plotter({'name': name, 'operation': 'clear'}) def hide(self, name=None): self.send_to_plotter({'name': name, 'operation': 'close'}) def remove(self, name=None): self.send_to_plotter({'name': name, 'operation': 'remove'}) self.send_to_plotter({ 'name': 'none', 'operation': 'none' }, np.array([0.])) def disconnect_received(self): self.is_connected = False warnings.warn( 'Disconnected from LivePlotter server, plotting has been disabled')
def receiveMessage(self): stream = QTextStream(self.conn) if stream.atEnd(): return data = stream.readAll() for json_str in data.split("\n")[:-1]: obj = json.loads(json_str) msgType = obj["type"] if msgType == self.TYPE_NOTIFICATION: self.log("Notification Received. code: {0}".format( obj["params"].get("code"))) if obj["params"].get("code") == self.N_DATA_RECEIVED: memKey = obj["params"]["memoryKey"] mem = self._mem[memKey] if mem.isAttached(): mem.detach() self.log( "Shared memory detached: key={0}".format(memKey)) del self._mem[memKey] else: self.notified.emit(obj["params"]) elif msgType == self.TYPE_REQUEST: self.log( "Request Received. dataType: {0}, renderId: {1}".format( obj["params"].get("dataType"), obj["params"].get("renderId"))) self.requestReceived.emit(obj["params"]) elif msgType == self.TYPE_RESPONSE: self.log( "Response Received. dataType: {0}, renderId: {1}".format( obj["meta"].get("dataType"), obj["meta"].get("renderId"))) mem = QSharedMemory(obj["memoryKey"]) if not mem.attach(QSharedMemory.ReadOnly): self.log( "Cannot attach this process to the shared memory segment: {0}" .format(mem.errorString())) return size = mem.size() self.log("Size of memory segment is {0} bytes.".format(size)) mem.lock() ba = QByteArray() buffer = QBuffer(ba) buffer.setData(mem.constData()) mem.unlock() mem.detach() data = ba.data() lines = data.split(b"\n") for line in lines[:5]: self.log(line[:76]) if len(lines) > 5: self.log("--Total {0} Lines Received--".format(len(lines))) self.notify({ "code": self.N_DATA_RECEIVED, "memoryKey": obj["memoryKey"] }) self.responseReceived.emit(data, obj["meta"])
class MusicianSuite(QApplication): signalReceived = pyqtSignal(object) def __init__(self, argv, key): super().__init__(argv) QSharedMemory(key).attach() self._memory = QSharedMemory(self) self._memory.setKey(key) if self._memory.attach(): self._running = True else: self._running = False if not self._memory.create(1): raise RuntimeError(self._memory.errorString()) self._key = key self._timeout = 1000 self._server = QLocalServer(self) if not self.isRunning(): self._server.newConnection.connect(self.handleMessage) self._server.listen(self._key) self._settings = QSettings("Raul Sangonzalo", "Musician Suite") # self._settings.setValue("currentDatabase", None) # testing purposes self.initialPrompt = InitialPrompt() self.initialPrompt.databaseSelected.connect(self.reloadInit) def isRunning(self): return self._running def handleMessage(self): socket = self._server.nextPendingConnection() if socket.waitForReadyRead(self._timeout): self.signalReceived.emit( socket.readAll().data().decode('utf-8')) socket.disconnectFromServer() else: Qt.QDebug(socket.errorString()) def sendNotification(self, message): if self.isRunning(): socket = QLocalSocket(self) socket.connectToServer(self._key, QIODevice.WriteOnly) if not socket.waitForConnected(self._timeout): print(socket.errorString()) return False if not isinstance(message, bytes): message = message.encode('utf-8') socket.write(message) if not socket.waitForBytesWritten(self._timeout): print(socket.errorString()) return False socket.disconnectFromServer() return True return False def init(self): """True initiation of the App, if only one instance""" if self._settings.value("currentDatabase") == None: self.initialPrompt.show() else: # check in case user moves the location of db location = self._settings.value("currentDatabase") print("------>", location) if not os.path.exists(location): self.initialPrompt.show() else: self.mainWindow = MusicMainWindow() # mac madness os.chdir(os.path.dirname(os.path.abspath(__file__))) resourcesPath = os.getcwd() resourcesPath = os.path.join(resourcesPath, "resources") if not os.path.exists(resourcesPath): os.mkdir(resourcesPath) self.MAIN_ICON = QIcon(os.path.join(resourcesPath, "test.ico")) self.ICON0 = QIcon( QPixmap(os.path.join(resourcesPath, "icon0.png"))) self.ICON1 = QIcon( QPixmap(os.path.join(resourcesPath, "icon1.png"))) self.RECORD_ICON = QIcon( QPixmap(os.path.join(resourcesPath, "record.png"))) self.widget = QWidget() self.trayIcon = QSystemTrayIcon(self.MAIN_ICON, self.widget) self.trayIcon.setToolTip("Musician Suite") self.trayIconMenu = QMenu() self.songListAction = QAction(self.ICON0, "Song List") self.recordIdeasAction = QAction(self.ICON1, "Recorded Ideas") self.recordAction = QAction(self.RECORD_ICON, "Record now!") self.exitAction = QAction("Exit") self.trayIconMenu.addAction(self.songListAction) self.trayIconMenu.addAction(self.recordIdeasAction) self.trayIconMenu.addAction(self.recordAction) self.trayIconMenu.addAction(self.exitAction) self.trayIcon.setContextMenu(self.trayIconMenu) self.trayIcon.show() self.trayIcon.activated.connect(self.iconDoubleClickMain) self.trayIconMenu.triggered.connect(self.messagePopup) self.mainWindow.stackedWidget.setCurrentIndex(0) self.signalReceived.connect(self.showMainWindow) self.mainWindow.show() def showMainWindow(self): self.mainWindow.show() def reloadInit(self): print("I am in reload Init") self.initialPrompt.hide() self.init() def iconDoubleClickMain(self, reason): if reason == QSystemTrayIcon.DoubleClick: self.mainWindow.stackedWidget.setCurrentIndex(0) self.mainWindow.show() def messagePopup(self, action): """Pressing the menu and toast """ if action == self.songListAction: if not self.mainWindow.isVisible(): self.mainWindow.stackedWidget.setCurrentIndex(0) self.mainWindow.show() elif action == self.recordIdeasAction: if not self.mainWindow.isVisible(): self.mainWindow.stackedWidget.setCurrentIndex(1) self.mainWindow.show() elif action == self.recordAction: self.startRecordingHook() else: self.exit() def startRecordingHook(self): self.mainWindow.stackedWidget.setCurrentIndex(1) self.mainWindow.show() listRows = self.mainWindow.recordIdeas.recordedIdeasListWidget.count() print(listRows) self.mainWindow.recordIdeas.recordedIdeasListWidget.setCurrentRow( listRows-1) self.mainWindow.recordIdeas.record()