def get_article_json(id: IntLike, only_from_cache=False, process_json=True) -> Union[dict, None]: """ Get article json by id `only_from_cache` is for multiget_article_json() """ key = Keys.article_json.format(id) data = rd.get(key) # none is returned if not exists if data is not None: json_article = json.loads(data.decode()) rd.expire(key, Keys.article_json_expire) if not process_json: return json_article return Article.process_json(json_article) if only_from_cache: return None article = Article.query.get(id) if article is None: return None json_article = article.to_json(cache=True) cache_article_json(json_article) if not process_json: return json_article return Article.process_json(json_article)
def get_status_json(id: IntLike, only_from_cache=False, process_json=True) -> Union[dict, None]: """Get processed status_json * None is returned in case of status is not found * `only_from_cache` is for multiget_status_json() """ key = KEYS.status_json.format(id) data = rd.get(key) # data is a dict with bytes key and bytes value if data: # hit in redis cache result = json.loads(data.decode()) rd.expire(key, KEYS.status_json_expire) if process_json: return Status.process_json(result) return result if only_from_cache: return None print("Can't load status {} from redis".format(id)) print("Try to load from mysql") status = Status.query.get(id) if status is None: print("Can't load status {} from mysql".format(id)) return None result = status.to_json(cache=True) cache_status_json(result) if process_json: return Status.process_json(result) return result
def _load_user_timeline(id): """ Load user timeline from database """ sql = """ select * from ( select 0 as kind, id, timestamp from statuses where user_id=:UID or user_id in ( select followed_id from user_follows as F where F.follower_id=:UID ) union select 1 as kind, id, timestamp from articles where official_account_id in ( select official_account_id from subscriptions as S where S.users_id=:UID ) ) as t order by timestamp DESC limit :LIMIT offset :OFFSET; """ # NOTE: `S.users_id` is a typo of column name(Don't change) key = Keys.user_timeline.format(id) result = db.engine.execute(text(sql), UID=id, LIMIT=100, OFFSET=0) result = list(result) args = [] for item in result: if item['kind'] == 0: timeline_item = Keys.timeline_status_item.format(item['id']) score = Score.timestamp_to_score(item['timestamp']) rd.zadd(key, score, timeline_item) elif item['kind'] == 1: timeline_item = Keys.timeline_article_item.format(item['id']) score = Score.timestamp_to_score(item['timestamp']) args += [score, timeline_item] if args: rd.zadd(key, *args) rd.expire(key, Keys.user_timeline_expire)
def _cache_liked_users(id: IntLike): key = KEYS.status_liked_users.format(id) sql = 'select user_id from status_likes where status_id=:SID' result = db.engine.execute(text(sql), SID=id) liked_user_ids = [row[0] for row in result] liked_user_ids.append(-1) rd.sadd(key, *liked_user_ids) rd.expire(key, KEYS.status_liked_users_expire)
def add_to_cache(self, value, label=None): if type(value) != str: value = ujson.dumps(value) key = self._get_key(label=label) resp = rd.set(name=key, value=value) rd.expire(name=key, time=app.config['CACHE_KEY_EXPIRE']) return resp
def get_subscriber_ids(id: IntLike): key = KEYS.official_account_subscribers.format(id) ids = rd.smembers(key) if not ids: _cache_account_subscribers(id) ids = rd.smembers(key) rd.expire(key, KEYS.official_account_subscribers_expire) ids = [t.decode() for t in ids] return ids
def get_follower_ids(id: IntLike): key = Keys.user_followers.format(id) # returns an empty set if key not exists ids = rd.smembers(key) if not ids: _cache_followers(id) ids = rd.smembers(key) rd.expire(key, Keys.user_followers_expire) ids = [t.decode() for t in ids] return ids
def _cache_account_subscribers(id: IntLike): key = KEYS.official_account_subscribers.format(id) sql = """ select users_id from subscriptions where official_account_id=:OID """ result = db.engine.execute(text(sql), OID=id) subscriber_ids = [row[0] for row in result] subscriber_ids.append(-1) rd.sadd(key, *subscriber_ids) rd.expire(key, KEYS.official_account_subscribers_expire)
def _cache_followers(id: IntLike): key = Keys.user_followers.format(id) sql = "select follower_id from user_follows where followed_id=:UID" result = db.engine.execute(text(sql), UID=id) follower_ids = [row[0] for row in result] """ As redis does not support empty set, but we still need to know whether an empty set is cached, so we need a placeholder element(use self's id is good) """ follower_ids.append(id) rd.sadd(key, *follower_ids) rd.expire(key, Keys.user_followers_expire)
def get_user(id: IntLike): """ None is returned if user can't found """ key = Keys.user.format(id) data = rd.get(key) if data != None: user = pickle.loads(data) user = db.session.merge(user, load=False) rd.expire(key, Keys.user_expire) return user user = User.query.get(id) if user != None: data = pickle.dumps(user) rd.set(key, data, Keys.user_expire) return user
def get_user_json(id: IntLike) -> Union[dict, None]: """ None is returned in case of user not exists """ key = Keys.user_json.format(id) data = rd.get(key) if data: json_user = json.loads(data.decode()) rd.expire(key, Keys.user_json_expire) return User.process_json(json_user) user = get_user(id) if user is None: return None json_user = user.to_json(cache=True) cache_user_json(json_user) return User.process_json(json_user)
def get_official_account_json(id: IntLike): """ Get official_account_json from redis by id None is returned in case of not found """ key = KEYS.official_account_json.format(id) data = rd.get(key) if data is not None: json_account = json.loads(data.decode()) rd.expire(key, KEYS.official_account_json_expire) return OfficialAccount.process_json(json_account) account = OfficialAccount.query.get(id) if account is None: return None json_account = account.to_json(cache=True) cache_account_json(json_account) return OfficialAccount.process_json(json_account)
def get_group_josn(id: IntLike): """ Get group json from redis None is returned in case of not found """ key = KEYS.group_json.format(id) data = rd.get(key) if data is not None: json_group = json.loads(data.decode()) rd.expire(key, KEYS.group_json_expire) return Group.process_json(json_group) group = Group.query.get(id) if group is None: return None json_group = group.to_json(cache=True) cache_group_json(json_group) return Group.process_json(json_group)
def login(): auth = request.authorization if not auth: return jsonify('Authorization request missing'), 401 if not auth.username: return jsonify('Username is missing'), 401 if not auth.password: return jsonify('Password is missing'), 401 user = Users.query.filter_by(email=auth.username).first() if not user: return jsonify('Username not found'), 401 # if check_password_hash(user.password, auth.password): print(user.password) if bcrypt.checkpw(auth.password.encode('utf-8'), user.password.encode('utf-8') ): # generate session id sessionid = str(uuid.uuid4()) print('sessionid at login:'******'uid' : user.id, 'cid' : user.cid, 'sessionid' : sessionid, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=app.config['SESSION_EXPIRY']) } token = create_access_token(identity=user.id, headers=jwt_payload) # set session keys and setting expiry in redis # rd.hset(user.id,'token', token) rd.hset(user.id,'sessionid', sessionid) rd.expire(user.id, app.config['SESSION_EXPIRY']) # set additional keys in redis rd.hset(user.id,'segid', user.segid) rd.hset(user.id,'cid', user.cid) return jsonify({'token' : token}) return jsonify('Invalid Password'), 401
def get_timeline(): """ 获取个人Timeline 参数: limit: 可选,default=10 offset: 可选,default=10 """ limit = request.args.get('limit', 10, type=int) offset = request.args.get('offset', 0, type=int) key = Keys.user_timeline.format(g.user.id) print("View:", key) if not rd.exists(key): # A long time no-logged in user comes back #rd.rpush(Keys.timeline_events_queue, # Keys.user_returned.format(g.user.id)) _load_user_timeline(g.user.id) """element: type:id, type=s|a""" datas = rd.zrevrange(key, offset, offset + limit - 1) rd.expire(key, Keys.user_timeline_expire) items = [d.decode() for d in datas] print("Timeline items:", items) status_ids = [] article_ids = [] for item in items: if item[0] == Keys.timeline_status_prefix: status_ids.append(item[2:]) elif item[0] == Keys.timeline_article_prefix: article_ids.append(item[2:]) else: raise Exception("No such type") statuses = Cache.multiget_status_json(status_ids) articles = Cache.multiget_article_json(article_ids) res_map = {} for s in statuses: item_key = Keys.timeline_status_item.format(s['id']) res_map[item_key] = s for a in articles: item_key = Keys.timeline_article_item.format(a['id']) res_map[item_key] = a res = [res_map[t] for t in items if t in res_map] return jsonify(res)
def get_group_user_title(group_id: IntLike, user_id: IntLike): """ Get user's title in some group "" is returned if not found """ key = KEYS.group_user_title.format(group_id=group_id, user_id=user_id) data = rd.get(key) if data is not None: rd.expire(key, KEYS.group_user_title_expire) return data.decode() sql = """ select title from group_memberships where user_id=:UID and group_id=:GID """ result = db.engine.execute(text(sql), UID=user_id, GID=group_id) res = result.first() if res is None: return "" title = res[0] rd.set(key, title, ex=KEYS.group_user_title_expire) return title