def _collect(self, limit): size_x, size_y = (1280, 1024) handle, snapshot_file = tempfile.mkstemp('.png') command = 'fswebcam -q -r %dx%d --png 9 -D 1 -S 7 --no-banner %s' % (size_x, size_y, snapshot_file) subprocess.check_call(command, shell=True) os.close(handle) memdam.log().debug("Saved " + snapshot_file + " (Size: " + str(size_x) + " x " + str(size_y) + ")") if os.path.getsize(snapshot_file) <= 0: memdam.log().warn("Failed to capture webcam image") os.remove(snapshot_file) return [] if self._is_similar_to_last_image(snapshot_file): os.remove(snapshot_file) return [] copied_location = memdam.common.utils.make_temp_path() shutil.copy(snapshot_file, copied_location) if self._last_image != None: os.remove(self._last_image) self._last_image = copied_location snapshot = self._save_file(snapshot_file, consume_file=True) return [memdam.common.event.new(u"com.memdam.webcam", data__file=snapshot)]
def _is_similar_to_last_image(self, screenshot): ''' :param screenshot: the image to check for similarity against our previous capture :type screenshot: string(path) :returns: True iff the image is sufficiently similar to the last one we took. :rtype: boolean ''' if self._last_image is None: return False difference = memdam.common.image.rmsdiff(Image.open(self._last_image), Image.open(screenshot)) memdam.log().debug("SNAPSHOT DIFFERENCE=%s", difference) return difference < self._threshold
def handle_errors(err): """ Generic JSON error handler. Adds a bit more color to what happened. """ exc_info = sys.exc_info() trace_data = '\n'.join(traceback.format_exception(*exc_info)) if isinstance(err, werkzeug.exceptions.HTTPException): response_data = dict(description=err.description) status_code = err.code else: response_data = dict(description=str(err)) status_code = 500 response_data['code'] = status_code response_data['failed'] = True response_data['trace'] = trace_data memdam.log().info("Request failed: " + str(response_data)) return flask.make_response(flask.jsonify(response_data), status_code)
def report(e): exc_info = sys.exc_info() htmlContent = get_error_html(e, exc_info) textContent = '\n'.join(traceback.format_exception(*exc_info)) memdam.log().error(textContent) if memdam.config.mandrill_key == None: filename = "/tmp/python_%s_%s_error.html" % \ (os.getpid(), threading.current_thread().ident) html_file = open(filename, "wb") html_file.write(htmlContent) html_file.close() webbrowser.open_new_tab("file://%s" % (filename)) #just so that it doesn't pop up a million windows sys.exit() else: send_email(memdam.config.mandrill_key, textContent, htmlContent)
def _process(self, work_id): memdam.log().info("Processing event " + str(work_id)) event = self._event_source.get(work_id) for field, blob_ref in event.blob_ids: memdam.log().info("Processing blob " + str(work_id)) temp_file = memdam.common.utils.make_temp_path() try: #TODO: someday, can check for existence in dest first, so that we don't have to re-upload files. Maybe ensure etag or something self._blob_source.get_data_to_file(blob_ref, temp_file) except memdam.blobstore.api.MissingBlob: #check that it exists at the destination at least: assert self._blob_dest.exists(blob_ref), "Fail. Tried to synchronize blob %s for event %s but there is no data for it?" % (blob_ref, work_id) self._blob_dest.set_data_from_file(blob_ref, temp_file) os.remove(temp_file) self._event_dest.save([event]) self._event_source.delete(event.id__id) for field, blob_ref in event.blob_ids: self._blob_source.delete(blob_ref)
def _snapshot_func(self): '''Needs to be called from the main thread so that it can take a screenshot of the desktop''' try: import PyQt4.QtGui handle, screenshot_file = tempfile.mkstemp(".png") PyQt4.QtGui.QPixmap.grabWindow(PyQt4.QtGui.QApplication.desktop().winId()).save(screenshot_file, 'png') try: os.close(handle) except Exception, e: memdam.log().warn("Failed to close this file handle %s because %s" % (handle, e)) memdam.log().debug("Saved screenshot to " + screenshot_file) if self._is_similar_to_last_image(screenshot_file): os.remove(screenshot_file) return [] copied_location = memdam.common.utils.make_temp_path() shutil.copy(screenshot_file, copied_location) if self._last_image != None: os.remove(self._last_image) self._last_image = copied_location screenshot = self._save_file(screenshot_file, consume_file=True) return [memdam.common.event.new(u"com.memdam.screenshot", data__file=screenshot)]
def _collect(self, limit): if limit <= 0: memdam.log().error("SamplingCollector %s was skipped!" % (self)) else: return self.sample()
def _print_some_statements(num): """Print some statements and exit""" for i in range(0, num): memdam.log().info("log " + str(i)) time.sleep(0.3)
def save(self, events): memdam.log().debug("Saving events") sorted_events = sorted(events, key=lambda x: x.namespace) for namespace, grouped_events in itertools.groupby(sorted_events, lambda x: x.namespace): table_name = namespace_to_table_name(namespace) self._save_events(list(grouped_events), table_name)
def _save_events(self, events, table_name): """ Save all events of the same type to the database at once """ memdam.log().debug("Saving %s events to %s" % (len(events), table_name)) if len(events) <= 0: return assert SqliteColumn.SQL_NAME_REGEX.match(table_name), "Invalid name for table: %s" % (table_name) key_names = set() for event in events: for key in event.keys: key_names.add(key) #certain key names are ignored because they are stored implicity in the location of #this database (user, namespace) for reserved_name in ("type__namespace", "user__id"): if reserved_name in key_names: key_names.remove(reserved_name) should_update_columns = True if self.folder != ":memory:": #does table not exist? db_file = os.path.join(self.folder, table_name + Eventstore.EXTENSION) if not os.path.exists(db_file): #try to acquire lock lock_file = os.path.join(self.folder, table_name + Eventstore.LOCK_EXTENSION) lock = lockfile.LockFile(lock_file) with lock: #two possible scenarios: #1. we got the lock AFTER someone else, who already made the table: if os.path.exists(db_file): #TODO: move this somewhere more sensible try: os.remove(lock) except: pass #2. we got the lock BEFORE anyone else, so we're responsible for making the table: else: should_update_columns = False #make the table and create the columns temp_db_file = os.path.join(self.folder, table_name + Eventstore.CREATE_TABLE_EXTENSION) self._create_database(table_name, key_names, temp_db_file) #move the file back to it's regular location os.rename(temp_db_file, db_file) #TODO: move this somewhere more sensible try: os.remove(lock) except: pass conn = self._connect(table_name, read_only=False) if should_update_columns: def update_columns(): cur = conn.cursor() existing_columns = self._query_existing_columns(cur, table_name) required_columns = self._generate_columns(cur, key_names, table_name) self._update_columns(cur, existing_columns, required_columns) #TODO: use the locking approach for updating as well as creating? execute_with_retries(update_columns, 5) cur = conn.cursor() cur.execute("BEGIN EXCLUSIVE") self._insert_events(cur, events, key_names, table_name) conn.commit()