2013-08-16 32 views
0

Firebase中,为聊天室创建“房间”很容易,就像他们各种样本中记录的一样。参与人数有限的Firebase房间

对于聊天的数据结构,我会用这样的:

rooms 
    room1 
     member_count 
     members 
      user1 
      user2 
     messages 
      message1 

但现在我想创建创建的每间客房参与者的数量限制,就是每聊3个用户房间。

你怎么能做到这一点?

在他们的文档中,看起来最有前途的一件事是使用transactions。你能证实这是一个好方法吗?或者这是错误的方法?

这样的解决方案呢?

Firebase countRef = new Firebase("https://mychat.firebaseIO-demo.com/rooms/room1"); 
countRef.runTransaction(new Transaction.Handler() { 
    @Override 
    public Transaction.Result doTransaction(MutableData currentData) { 
     int oldMemberCount = currentData.child("member_count").getValue(Integer.class); 
     currentData.child("member_count").setValue(oldMemberCount + 1); // try to update member count 
     return Transaction.success(currentData); 
    } 

    @Override 
    public void onComplete(FirebaseError error, boolean committed, DataSnapshot currentData) { 
     if (error != null || !commited) { 
      // rollback value (how? just do nothing?) 
     } 
     else { 
      // transaction has been commited (value has already been saved?) 
      currentData.child("members").child(CURRENT_USER_UUID).setValue(CURRENT_USER_NAME); // add user to the members list 
     } 
    } 
}); 

如果您可以对此方法发表评论,那将会很棒。此外,如果交易失败,当然也不能满足这种情况。用户仍然想加入,无论是否有另一个用户同时尝试加入。那么,怎么办?把这段代码放到一个函数中,并在错误情况下再次调用函数?

编辑:

要创建一个新的空间与自动唯一的ID,一个当然可以在Firebase参考使用push()

但是,如果你想添加成员到那个房间,那么上述问题仍然存在。另一种解决方案可能是在加入时在成员列表中设置用户的priority。当将其优先级设置为当前时间戳时,可以将成员列表回调设置为3(成员)limit。但是这看起来并不高雅,也不干净。

+0

难道你不能只读值的members_count,如果它低于3,那么'join'else'abort'? –

+0

不,如果两个客户端试图同时加入,他们都会将members_count设置为4并加入。之后,实际上有5个客户会在房间里。而这种情况在实时应用中很可能,不是吗? – caw

+0

如果您在连接之前进行了检查,并且在连接之后,您会很好。你知道的Firebase不是30毫秒的实时。它们非常快,但不会像你所说的30毫秒延迟。如果你那么快,你需要一个服务器,它执行逻辑并且不使用Firebase。 但是,一种可行的解决方案是制定一个安全规则,该规则禁止在val()。children()。length === 2')写入。这将正常工作。 –

回答

2

如果您每个房间的参与者数量固定(且相对较少),则最好使用交易。但是,它可能是最好的聊天室创建为每个人精心命名的对象,例如:

/rooms 
    /<roomid, generated by push()> 
    /users 
     one: null 
     two: null 
     three: null 

加入一个房间看起来像(在JavaScript代码,请转换成Java如适用);

var userid = "myuserid"; 
var ref = new Firebase("<my-firebase>.firebaseio.com/rooms/<roomid>/users"); 
ref.transaction(function(users) { 
    if (!users.one) { 
    // Claim slot 1 
    users.one = userid; 
    return users; 
    } else if (!users.two) { 
    // Claim slot 2 
    users.two = userid; 
    return users; 
    } else if (!users.three) { 
    // Claim slot 3 
    users.three = userid; 
    return users; 
    } 
    // Room is full, abort the transaction. 
    return; 
}, function(err, committed, snapshot) { 
    if (committed && !err) { 
    // Joined room successfully. 
    } else { 
    // Could not join room because it was full. 
    } 
}); 

如果Firebase未能将值提交给服务器,它将自动调用交易功能。除了上面的代码,你还需要落实防止用户声称这已经采取了时隙中的一些安全规则:

{ 
    "rules": { 
    "rooms": { 
     "$roomid": { 
     "users": { 
      "$slot": { 
      ".write": "!data.exists()" 
      } 
     } 
     } 
    } 
    } 
} 

您可以通过锻造上传这些规则,图形化调试器为您的火力地堡和你应该很好走!

+0

非常感谢!这正是我的意思:)但为什么需要安全规则?从关于事务的文档(如果没有其他人修改它,事务成功并调用完成回调,否则,如果发生冲突,Firebase客户端将检索新值并重新运行更新函数)我明白你可以使用没有安全规则的事务,因为它们确保没有其他人修改数据。如果有人这样做,你首先得到新的价值,并可以再次检查房间是否空着。这是错的吗? – caw

+0

我在问,因为这会非常好,当然,如果用户可以再次离开频道,并有其他人可以声称他的插槽。没有安全规则,这将是可能的。但是,根据您的安全规则,您无法将自己从插槽中移除,因为只要数据存在,写入特权就会消失,对吧? – caw

+1

没错,安全规则仅适用于防止恶意客户占用他人的位置。但是,正如你指出的那样,这也意味着你不能将自己从房间中移出。您可以删除安全规则以允许使用该安全规则,或者如果您通过某种身份验证机制来记录用户,则可以将规则更改为“!data.exists()|| auth.id == data.val() “以确保只有声称有地点的用户可以自行删除。 – Anant