def get_push_target_tag(self, **kwargs): """ Retrieves a single target tag with given id. Args: **kwargs (dict): project_id, target_id, name - project_id: project id - target_id: target who is tagged with this tag - name: name of tag Returns: dict: target tag or error message """ project_id, tag_name = kwargs['project_id'], kwargs['name'] target = self.get_obj(project_id, 'target', kwargs['target_id']) if tag_name not in target.data['push_tags']: zlogger.error("Tag is doesn't exist in target's tags. Project id:{}," "target id:{}, tag name:{}".format(project_id, kwargs['target_id'], tag_name)) return {"error": {"code": -32006, "message": "Related tag couldn't be found in user's push tags."}} tag = self.get_obj(project_id, 'tag', "{}_{}".format(project_id, tag_name)) tag_type, val = (tag.data['tag_type'], target.data['push_tags'][tag_name]) value = [] if tag_type == 'key' else [val] if tag_type == 'key-value' else list(val.keys()) return {'key': tag_name, 'value_read': value}
def create_push_tag(self, **kwargs): """ Creates a single tag with given id. Args: **kwargs (dict): project_id, name, tag_type, value_type - project_id: project id - name: name of tag - tag_type: tag type - value_type: value type Returns: """ bucket = self.get_bucket(kwargs['project_id'], 'tag') tag_key = "{}_{}".format(kwargs['project_id'], kwargs['name']) if bucket.get(tag_key).exists: zlogger.error(" Tag to be saved is already exists. Project id:{}, tag name:{}".format( kwargs['project_id'], kwargs['name'])) return {"error": {"code": -32005, "message": "Invalid value, tag is already exists."}} kwargs['possible_values'] = {} kwargs.update(self.get_creation_info()) obj = bucket.new(data=kwargs) obj.add_index('tag_bin', kwargs['project_id']) obj.key = tag_key obj.store() zlogger.info("New push tag is created. Project id:{}, tag name:{}".format( kwargs['project_id'], kwargs['name']))
def get_obj(self, project_id, bucket_name, obj_id, bucket_type=DEFAULT_BUCKET_TYPE): """ Gets obj from riak. Args: - project_id(str): project id - bucket_name (str): bucket name - obj_id (str): riak object key Returns: - obj (obj): riak obj """ bucket = self.get_bucket(project_id, bucket_name, bucket_type) obj = bucket.get(obj_id) if not obj.exists: zlogger.error("Object not found. Bucket name:{}, id:{}".format( bucket.name, obj_id)) raise KeyError("Object Not Found, bucket:{}, key:{}".format( bucket.name, obj_id)) return obj
def on_log_message(self, ch, method, properties, body): """ Gets log messages from rabbit. Args: ch: Channel method: Method properties: Props body(dict): Body - params(dict): kwargs for methods - method(str): methods name Returns: None """ try: body = json.loads(body) method_name = body.get('method', None) event_worker_method = getattr(self, method_name) if method_name else None if event_worker_method is not None: event_worker_method(**body['params']) except Exception as exc: zlogger.error("An error occurred on_log_message method inside EventProcessor." "Exception: {}, ".format(exc))
def get_queues(self, subscriber_id): """ Get subscriber's queues from cache and checks change, if any change about subscriber's queues, cache record is deleted and updated queue info is set to cache. Args: - subscriber_id (str): Subscriber id Returns: - active_queues (list): User's active queues list """ is_change = False active_queues = [] cache_key = 'QueueList:{}'.format(subscriber_id) queues = self.cache.smembers(cache_key) for queue in queues: try: self.rabbit_cl.get_queue('zopsm', queue.decode()) active_queues.append(queue.decode()) except HTTPError as exc: zlogger.error("An error occurred: {}".format(exc)) is_change = True if is_change: self.cache.delete(cache_key) self.cache.sadd(cache_key, *active_queues) return active_queues
def update_client(self, **kwargs): """ Updates the client info with given values. Args: **kwargs (dict): project_id, client_id, target_id, validated_client: - project_id: project_id - client_id: id of client which is desired to be updated - target_id: id of user who wants to update the client information, possibly user of the client - validated_client: dict of updated client information including clientId, token, appVersion, deviceType, language, country, osVersion. Returns: """ client = self.get_obj(kwargs['project_id'], 'client', kwargs['client_id']) if client.data['target_id'] != kwargs['target_id']: zlogger.error("Target id is not equal to wanted client's target. Project id:{}, Target " "id:{}, client id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['client_id'])) return {"error": {"code": -32004, "message": "Unauthorized Operation Error"}} client.data.update(kwargs['validated_client']) client.data['last_update_time'] = datetime.now().strftime(DATETIME_FORMAT) client.store() zlogger.info("Client data is updated. Project id:{}, " "client id:{}".format(kwargs['project_id'], kwargs['client_id']))
def get_push_client_tag(self, **kwargs): """ Retrieves a single client tag with given id. Args: **kwargs (dict): project_id, client_id, key - project_id: project_id - client_id: client which is tagged with this tag - name: name of tag Returns: dict: client tag """ client = self.get_obj(kwargs['project_id'], 'client', kwargs['client_id']) if kwargs['name'] not in client.data['push_tags']: zlogger.error("Tag is doesn't exist in client's tags. Project id:{}, client id:{}, " "tag name:{}".format(kwargs['project_id'], kwargs['client_id'], kwargs['name'])) return {"error": {"code": -32006, "message": "Related tag couldn't be found in client's push tags."}} tag = self.get_obj(kwargs['project_id'], 'tag', "{}_{}".format(kwargs['project_id'], kwargs['name'])) tag_type, val = (tag.data['tag_type'], client.data['push_tags'][kwargs['name']]) value = [] if tag_type == 'key' else [val] if tag_type == 'key-value' else list(val.keys()) return {'key': kwargs['name'], 'value_read': value}
def on_close(self): """ To do when a ws connection close. """ try: user_id = self.path_kwargs.get("request_user_id", None) if user_id: queue_manager.remove_event_listener(self, user_id) except Exception as exc: zlogger.error( "An error occurred on close method inside MyWebSocketHandler. " "Exc: {}".format(exc))
def find_redis_role(redis_nodes): roles = {'master': [], 'slave': []} for node in redis_nodes: try: cache = ZRedis(host=node) cache.execute('PING') except Exception as e: zlogger.error(str(e)) # If failPassword should be provided because Redis Master expects that. cache = ZRedis(host=node, password=redis_db_pw) execute_role = cache.execute('ROLE') role_of_node = execute_role[0].decode() roles[role_of_node].append(node) return roles.get('master')[0], random.choice(roles.get('slave' if roles['slave'] else 'master'))
def remove_event_listener(self, listener, user_id): """ Remove listener from listener list. """ try: if self.event_listeners.get(user_id): self.event_listeners[user_id].remove(listener) if not self.event_listeners[user_id]: self.channel.queue_delete( queue=self.get_queue_name(user_id)) del self.event_listeners[user_id] except Exception as exc: zlogger.error( "An error occurred on remove_event_listener method inside QueueManager. " "User Id: {}, Exception: {}".format(user_id, exc))
def open(self, request_user_id, token): """ To do when a new ws connection. """ try: user_info, token_ttl = self.get_user_info_and_token(token) self.check_validity(user_info, request_user_id, token_ttl) IOLoop.current().add_timeout(deadline=timedelta(seconds=token_ttl), callback=self.token_timeout) queue_manager.add_event_listener(self, user_info) except Exception as exc: zlogger.error( "An error occurred on open method inside MyWebSocketHandler. " "Exc: {}".format(exc)) self.close()
def check_validity(self, user_info, request_user_id, token_ttl): """ Checks that token and user_id aren't invalid. """ user_id = user_info.get("user") if not user_id or not token_ttl > 60: zlogger.error("Unathorized error for value:{}".format(user_id)) raise web.HTTPError(status_code=401, log_message='Unauthorized error') # self.close(code=401, reason="Unauthorized error.") elif user_id != request_user_id: zlogger.error( "Unauthorized error. user_id inside Request parameter({}) and " "token(User id: {}) does not match.".format( request_user_id, user_id)) raise web.HTTPError(status_code=401, log_message='Unauthorized error')
def get_user_info_and_token(self, token): """ According to coming token, finds user info and token ttl from cache. """ token_key = cache.hmget(CACHE_TOKENS_KEYS, token)[0] if not token_key: zlogger.error("Unathorized error for token value:{}".format( token if token else "-")) raise web.HTTPError(status_code=401, log_message='Unauthorized error') token_ttl = cache.ttl(token_key.decode()) stored_value = cache.hgetall(token_key) user = {} if stored_value: for k, v in stored_value.items(): user[k.decode()] = v.decode() return user, token_ttl
def bindings_operation(self, operation, subscriber_id, route_key): """ According to given operation(create binding or delete binding), new bindings are created or existing bindings are removed. Args: - operation (str): 'create_binding' or 'delete_binding' - subscriber_id (str): riak subscriber object key Returns: """ queues = self.get_queues(subscriber_id) for queue in queues: try: getattr(self.rabbit_cl, operation)('zopsm', 'messages', queue, route_key) except HTTPError as exc: zlogger.error( "An error occur on bindings_operation method inside BaseWorkerJobs. " "Exc: {}".format(exc))
def delete_push_message(self, **kwargs): """ Deletes a message with given id if its type is scheduled or automated. Args: **kwargs (dict): project_id, message_id, target_id - project_id: - message_id: - target_id: Returns: """ message = self.get_obj(kwargs['project_id'], 'push_message', kwargs['message_id']) if message.data['target_id'] != kwargs['target_id']: zlogger.error("Message's sender is not equal to target. Project id:{}, target id:{}, " "message id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['message_id'])) return {"error": {"code": -32004, "message": "Unauthorized Operation Error"}} message.delete() zlogger.info("Message is deleted. Project id:{}, message id:{}".format( kwargs['project_id'], kwargs['message_id']))
def send_push_message(service_type, tokens, val, project_id): """ Sends push message to clients according to device service_type. Args: - tokens(list): client token list - val(dict): including title, body, service_type, language, icon, image, badge. """ services = {'ios': ios, 'android': android} try: res = services[service_type](tokens, val, project_id) zlogger.info("Push %s succces. project id: %s, success: %s", service_type, project_id, res.successes) zlogger.error( "Push %s result. project id: %s, failures: %s, errors: %s", service_type, project_id, res.failures, res.errors) except Exception as e: zlogger.error("Unified push error: %s", str(e))
def get_targets_client_ids(self, project_id, target_ids): """ Finds client ids of given target ids list. Args: project_id (str): project id ids (list): target ids list Returns: list: client ids """ client_ids = [] for id in target_ids: try: target_obj = self.get_obj(project_id, 'target', id) client_ids.extend(target_obj.data['clients'].keys()) except KeyError: zlogger.error( "Invalid target id. Key error occured in get_targets_client_ids " "method.Project id: {}, target_id: {}".format( project_id, id)) return client_ids
def get_push_message(self, **kwargs): """ Retrieves a single message with given message_id to target with given target_id. *User must be allowed to see the message. So, user must be the sender of the message. Args: **kwargs (dict): project_id, target_id, message_id - project_id: - target_id: - message_id: Returns: dict : message dict including id, creationTime, lastUpdateTime, isDeleted, isActive, sender, title, body, type, language, icon, image, badge, audience """ message = self.get_obj(kwargs['project_id'], 'push_message', kwargs['message_id']) if message.data['target_id'] != kwargs['target_id']: zlogger.error("Message's sender is not equal to target. Project id:{}, target id:{}, " "message id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['message_id'])) return {"error": {"code": -32004, "message": "Unauthorized Operation Error"}} return message.data
def delete_client(self, **kwargs): """ Deletes the client with given id. Args: **kwargs (dict): project_id, client_id, target_id: - project_id: project_id - client_id: id of client which is desired to be deleted - target_id: id of user who wants to delete the client, possibly user of the client Returns: """ client = self.get_obj(kwargs['project_id'], 'client', kwargs['client_id']) if client.data['target_id'] != kwargs['target_id']: zlogger.error("Target id is not equal to wanted client's target. Project id:{}, Target " "id:{}, client id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['client_id'])) return {"error": {"code": -32004, "message": "Unauthorized Operation Error"}} target = self.get_obj(kwargs['project_id'], 'target', client.data['target_id']) if kwargs['client_id'] not in target.data['clients']: zlogger.error("Client id doesn't exist in target's clients. Project id:{}," "target id:{}, client id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['client_id'])) return {"error": {"code": -32006, "message": "Client id doesn't exist in target"}} del target.data['clients'][kwargs['client_id']] target.data['last_update_time'] = datetime.now().strftime(DATETIME_FORMAT) target.store() client.delete() zlogger.info("Client is deleted. Project id:{}, client id:{}".format(kwargs['project_id'], kwargs['client_id']))
def get_client(self, **kwargs): """ Returns the client info as dict including clientId, token, appVersion, deviceType, language, country, osVersion, creationTime, lastUpdateTime, isDeleted, isActive. Args: **kwargs (dict): project_id, target_id, client_id: - project_id: project_id - target_id: id of user who wants to get the client information, possibly user - client_id: id of the client whose information is desired of the client Returns: dict : client data """ client = self.get_obj(kwargs['project_id'], 'client', kwargs['client_id']) if client.data['target_id'] != kwargs['target_id']: zlogger.error("Target id is not equal to wanted client's target. Project id:{}, Target " "id:{}, client id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['client_id'])) return {"error": {"code": -32004, "message": "Unauthorized Operation Error"}} return client.data
def update_push_message(self, **kwargs): """ Updates a message with given id. Args: **kwargs (dict): project_id, message_id, validated_message, target_id - project_id: project_id - message_id: - validated_message: dict of validated message including title, body, type, language, icon, image, badge. - target_id: Returns: """ message = self.get_obj(kwargs['project_id'], 'push_message', kwargs['message_id']) if message.data['target_id'] != kwargs['target_id']: zlogger.error("Message's sender is not equal to target. Project id:{}, target id:{}, " "message id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['message_id'])) return {"error": {"code": -32004, "message": "Unauthorized Operation Error"}} #todo:if message type is 'ordinary' , message doesnot updated if message.data['audience']: if not kwargs['validated_message']['audience']: zlogger.error("Message audience field can not be null. Project id:{}, target id:{}, " "message id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['message_id'])) return {"error": {"code": -32006, "message": "Message audience field can not be null"}} else: kwargs['validated_message']['consumers'] = {} elif message.data['consumers']: if not kwargs['validated_message']['consumers']: zlogger.error("Message consumers field can not be null. Project id:{}, target id:{}, " "message id:{}".format(kwargs['project_id'], kwargs['target_id'], kwargs['message_id'])) return {"error": {"code": -32006, "message": "Message consumers field can not be null"}} message.data.update(kwargs['validated_message']) message.data['last_update_time'] = datetime.now().strftime(DATETIME_FORMAT) message.store() zlogger.info("Message is updated. Project id:{}, message id:{}".format( kwargs['project_id'], kwargs['message_id']))
def on_request(self, ch, method, props, body): """ Publishes response by using do_job method Args: ch: Channel method: Method props: Properties body: Message Body Returns: None """ err = None err_msg = "" result = {} id = None params = {} try: body = json.loads(body) try: rabbit_cl = sd_rabbit.get_suitable_client( json.loads(sd_rabbit.rabbit_nodes)) jobs_inst = self.jobs[body['params']['service']] jobs_inst.update_instances(sd_riak.riak_pb, rabbit_cl, sd_redis.redis_master) worker_method = getattr(jobs_inst, body['method']) try: params = body['params'] result = worker_method(**params) id = body['id'] except TypeError as e: err_msg = "Invalid params: {}".format(e) err = {"code": -32602, "message": "Invalid Params"} except ConnectionRefusedError as e: err_msg = "RiakNode Connection Refused Error: {}".format(e) err = { "error": { "code": -32001, "message": "Internal Error" } } except KeyError as e: err_msg = "Object Not Found: {}".format(e) err = {"code": -32002, "message": "Object Not Found"} except KeyError as e: err_msg = "Invalid Request: {}".format(e) err = {"code": -32600, "message": "Invalid Request"} except ImportError as e: err_msg = "Method not found: {}".format(e) err = {"code": -32601, "message": "Method Not Found"} except JSONDecodeError as e: err_msg = "Parse error: {}".format(e) err = {"code": -32700, "message": "Parse Error"} except Exception as e: err_msg = "Internal error: {}".format(e) err = {"code": -32603, "message": "Internal Error"} # Reserved for implementation - defined server - errors. # http://www.jsonrpc.org/specification#error_object # TODO: -32000 to -32099 Server error response = {"jsonrpc": "2.0", "id": id} if err or (result and 'error' in result): response['error'] = err or result['error'] msg = "Blocking {blocking}, {method} with correlation id:{corr_id} of " \ "project:{project_id} and user:{usr_id}, resulted in an error:{err_msg}".format( method=params.get('method'), corr_id=params.get('id'), project_id=params.get('project_id'), err_msg=err_msg or response['error']['message'], usr_id=params.get('subscriber_id') or params.get('target_id'), blocking=not params.get('trackable') ) zlogger.error(msg) if params and params['trackable']: zlogger.info("", extra={ "purpose": "event", "params": { "trackingId": params.get('id'), "data": { "title": response['error']['message'], "description": "Event has failed.", "code": 500, }, "usr_id": params.get('subscriber_id') or params.get('target_id'), }, "method": "fails_non_blocking_jobs", }) else: response['result'] = result ch.basic_publish(exchange='', routing_key=props.reply_to, properties=pika.BasicProperties( correlation_id=props.correlation_id), body=json.dumps(response)) ch.basic_ack(delivery_tag=method.delivery_tag)