_ := room.UpdatePropertis(roomID, func(properties map[string]interface{}) bool {if _, ok := properties["booked"]; !ok { properties["booked"] =truereturntrue }// The room has already been bookedreturnfalse})
How To Increment and/or Decrement A Numeric Room Property
Room module has an API to increment and/or decrement a numeric room property. This is useful when you have to update a numeric room property without race conditions.
// If the property called HP does not exist, it will create itcreated := room.IncrProperty(roomID, "HP", 1000)// Decrement the property called HP by -200decremented := room.IncrProperty(roomID, "HP", -200)// Increment the property called HP by 100incremented := room.IncrProperty(roomID, "HP", 100)
Room Properties With Data Capsule
Data Capsule is a data structure provided by Diarkis to help you manage interface{} data safely.
// This sets up handleRemoteRoomPropUpdate function to be invoked when mesh.SendRequest sends// The command message as shown abovemesh.Command(cmdID, handleRemoteRoomPropUpdate)funchandleRemoteRoomPropUpdate(req map[string]interface{}) (error, map[string]interface{}) { roomID := mesh.GetString(req, "roomID")var err error _ := room.UpdateProperties(roomID, func(props map[string]interface{}) bool {if _, ok := props["booked"]; !ok { props["booked"] =true// Booked the room successfullyreturntrue }// The room has already been booked... err = errors.New("Room has already been booked")returnfalse }) res :=make(map[string]interface{})return res, err}
How To Reserve A Room With Users
You may reserve places in a room with specific user IDs. When you reserve places in a room, those users with the reserved IDs will be able to join without worrying about if the room is full or not. If you make reservations for all possible members of the room, you may reject all other users without reservations to join.
NOTE: This operation is permitted only to the owner of the room.
Making Reservations
memberIDs :=make([]string, 4)memberIDs[0] ="user-id-123"memberIDs[1] ="user-id-456"memberIDs[2] ="user-id-789"memberIDs[3] ="user-id-012"// userData is the owner of the roomroom.Reserve(roomID, userData, memberIDs)
Canceling Reservations
memberIDs :=make([]string, 4)memberIDs[0] ="user-id-123"memberIDs[1] ="user-id-456"memberIDs[2] ="user-id-789"memberIDs[3] ="user-id-012"// userData is the owner of the roomroom.CancelReservation(roomID, userData, memberIDs)
How To Implement Locking Room Mechanism Using Room Properties
You may implement a locking mechanism to rooms with room properties. The example below demonstrates the implementation of a room locking mechanism that requires the client trying to unlock a room to have a passcode that is known to the room. You may implement a similar mechanism using the Room module’s SetJoinCondition method as well.
Note: The example uses the remote room property update technique that is described here.
addr, err := room.GetRoomNodeAddress(roomID)if err !=nil {// Handle errorreturn}req :=make(map[string]interface{})req["roomID"] = roomID// passcode comes from the clientreq["passcode"] = passcode// mesh.SendRequest is a inter-pod communication functionmesh.SendRequest(cmdID, addr, req, func(err error, res map[string]interface{}) {if err !=nil {// Handle errorreturn }// The room has been unlocked successfully})
mesh.Command(cmdID, unlockRoom)funcunlockRoom(req map[string]interface{}) (error, map[string]interface{}) { roomID := mesh.GetString(req, "roomID") passcode := mesh.GetString(req, "passcode")var err error _ := room.UpdateProperties(roomID, func(props map[string]interface{}) bool {if _, ok := props["unlocked"].(bool); !ok {// the room is already unlocked err := errors.New("Room already unlocked")returnfalse }if _, ok := props["passcode"].(string); !ok {// missing pass code... err := errors.New("Room is missing passcode...")returnfalse }if passcode != props["passcode"].(string) {// pass code the client has does not match err := errors.New("Pass code does not match")returnfalse }// pass code the client has matches props["unlocked"] =truereturntrue }) res :=make(map[string]interface{})return res, err}
How To Add Conditions To All Join Operations
Room’s join operation can optionally have “conditions” added to control how join operations function.
// This callback function will be called every time a join operation is called. By returning an error, you may reject the client to join.
room.SetJoinCondition(func(roomID string, userData *userData) error) {// Implement custom logic to control join// Example join condition:// The new client has to have "code" that has been pre-defined in the room property code := room.GetProperty(roomID)if code ==nil {// The room does not have a code, we assume the room to be public: proceed to joinreturnnil }// clientCode must be set to userData by userData.Set() before calling this clientCode :=GetRoomCodeFromUser(userData.Get("code"))if code == clientCode {// The code client has matches. Proceed to joinreturnnil }// join rejectedreturn errors.New("ClientCode does not match")})
Capturing Changes In A Room As An Event
Rooms raise an event whenever there is a change to the room. Changes with room properties, change of room members (joining and leaving), and change of room owner will trigger this event.
room.SetOnRoomChange(func(roomID string, memberIDs []string, props map[string]interface{}) { logger.Debug("There has been a change in the room %s", roomID)})
Capturing The Event On Room Owner Change
A room has an owner (The client that created the room or automatically elected member of the room). You may capture the event that is raised when the owner changes.
room.SetOnRoomOwnerChange(func(params interface{}) { roomData := params.(map[string]string) roomID := roomData["string"] roomOWnerUID := roomData["ownerID"] logger.Debug("The owner of the room %s has changed to %s", roomID, roomOwnerUID)})
Capturing The Event On Room Property Change
The event is raised when room properties are changed.
room.SetOnRoomPropertyUpdate(func(params interface{}) { roomData := params.(map[string]interface{}) roomID := roomData["roomID"].(string) properties := roomData.["properties"].(interface{}).(map[string]interface{}) logger.Debug("Room %s has detect change in its properties %v", roomID, properties)})
Capturing The Event On Room Destruction
The event is raised when a room has been deleted from the server.
room.SetOnRoomDiscard(func(roomID string) { logger.Debug("Room %s has been discarded", roomID)})
How To Use Announce()
room.Announce allows you to send messages to other members of a room. The difference between Broadcast and Message is that the sender client does NOT have to be a member of the room to send messages.
While it is flexible and useful in some cases not to worry about being a member of the room to send messages, it is also difficult to use Announce correctly without creating unexpected security holes.
If you let any client have access to Announce, Clients can send messages to any room as long as they know the targeted room ID. This could be exploited.
It is very important to have a control logic to call Announce in order to avoid abuse from the client.
The example below uses Announce in the callback of an event. By not having the client access directly to Announce, we can prevent numbers of potential security risks.
// SetOnAnnounce is raised when Broadcast, Message, Announce are invokedroom.SetOnAnnounce(func(roomID string, ver uint8, cmd uint16, msg []byte) {// We capture the message sent to the room and send it outside such as CDN etc. data :=CreateCDNData(roomID, ver, cmd, msg)SendCDN(data)})
How To Retrieve The Internal Address Of The Room From Room ID
Room ID contains the internal address of the server that the room is stored.