在各种在线服务和社交网络中,用户对象可以是构成一切的基本构建块。 我们的 Twitter 仿制品也不例外。
我们将用户的信息存储在 Redis 中,作为 HASH,类似于我们在第 1 章中存储文章的方式。我们将存储的数据包括用户的用户名、他们有多少粉丝、他们关注了多少人、他们发布了多少状态消息、他们的注册日期以及我们决定在线存储的任何其他元信息。 图 8.1 显示了一个示例 HASH,其中包含用户名为 dr_josiah(我的 Twitter 用户名)的用户的信息。
从这张图中,你可以看到我拥有相当数量的粉丝,以及其他信息。 当一个新用户注册时,我们只需要创建一个对象,将 following、followers 和 post count 设置为零,为注册时间设置一个新的时间戳,以及相关的用户名。 执行此初始创建的函数如下所示。
def create_user(conn, login, name): llogin = login.lower()
lock = acquire_lock_with_timeout(conn, 'user:' + llogin, 1)
尝试获取登录名小写版本的锁。 此函数在第 6 章中定义。
if not lock: return None
如果我们无法获得锁,则其他人已经拥有相同的登录名。
if conn.hget('users:', llogin): return None
我们还存储了一个登录名小写形式到用户 ID 的 HASH,因此如果已经存在一个登录名映射到一个 ID,我们就知道并且不会将其提供给第二个人。
id = conn.incr('user:id:')
每个用户都会获得一个唯一的 ID,该 ID 通过递增计数器生成。
pipeline = conn.pipeline(True)
pipeline.hset('users:', llogin, id)
将小写的登录名添加到从登录名到用户 ID 的 HASH。
pipeline.hmset('user:%s'%id, { 'login': login, 'id': id, 'name': name, 'followers': 0, 'following': 0, 'posts': 0, 'signup': time.time(),
将用户信息添加到用户的 HASH。
})
pipeline.execute()
release_lock(conn, 'user:' + llogin, lock)
释放登录名上的锁。
return id
返回用户的 ID。
在我们的函数中,我们执行预期的用户 HASH 中初始用户信息的设置,但我们还获取用户登录名周围的锁。 这个锁是必要的:它保证我们不会有两个请求同时尝试创建具有相同登录名的用户。 锁定后,我们验证登录名是否已被其他用户占用。 如果该名称尚未被占用,我们将为用户生成一个新的唯一 ID,将登录名添加到登录名到用户 ID 的映射中,然后创建用户的 HASH。
敏感用户信息由于用户 HASH 将被无数次地获取以用于呈现模板,或直接作为 API 请求的响应返回,因此我们不会在此 HASH 中存储敏感的用户信息。 目前,我们假设 HASHed 密码、电子邮件地址等存储在其他键中,或完全存储在不同的数据库中。
我们已经完成了创建用户并设置了所有必要的关于他们的元信息。 从这里开始,构建我们的 Twitter 仿制品的下一步是状态消息本身。