The scenario is when a player clicks "join game" in an app, a cloud function is invoked to add the player to firebase database and the result is passed as response.
Database structure:
/games
|--/game_id
|----/players => this is a json array of uids and their status([{"uid1": true}, {"uid2":true},...])
|----/max_players = 10
The cloud function should check if the /players size is less than then /max_players and only if so, it should update the /players with the uid of the player and return the response.
Here is my cloud function:
export const addUserToGame = functions.https.onCall((data, context) => {
// Expected inputs - game_id(from data) and UID(from context)
if (context.auth == null) {
return {
"status": 403,
"message": "You are not authorized to access this feature"
};
}
const uid = context.auth.uid;
const game_id = data.game_id;
let gameIDRef = gamesRef.child(game_id);
return gameIDRef.transaction(function (t) {
if (t === null) {
// don't do anything, can i just do return;
} else {
let playersNode;
let isAlreadyPlayer = false;
if (t.players) {
console.log("players is not empty");
playersNode = t.players;
let players_count = playersNode.length;
let max_players: Number = t.max_players;
if (players_count >= max_players) {
// how can i return an error from here?
}
for (var i = 0; i < playersNode.length; i++) {
if (playersNode[i].uid === uid) {
isAlreadyPlayer = true;
}
break;
}
if (!isAlreadyPlayer) {
playersNode.push({
[uid]: "active"
});
}
t.players = playersNode;
return t;
} else {
playersNode = [];
playersNode.push({
[uid]: "active"
});
t.players = playersNode;
return t;
}
}
},function(error, committed, snapshot) {
if(committed) {
return {
"status": 200,
"message": "Player added successfully"
};
} else {
return {
"status": 403,
"message": "Error adding player to the game"
};
}
});
});
Please see the comments in the above code, how can i send back a response when a condition fails?
Thanks @Doug and @Renaud for quick response, i still have few questions:
Q1. So i have to use
return gameIDRef.transaction(t => {
}).then(result => {
}).catch(error => {
});
but when is this used? is this the callback version that @Renaud is referring to?
function (error, committed, snapshot) {
});
Q2. In the first way, when gameIDRef.transaction(t => {}) is called, what happens when there is no value with the game_id and when there is no value with game_id, i want to tell the user that there is no game with that specified id. How can i achieve that?
return gameIDRef.transaction(t => {
if(t === null)
return;
//Where does the control go from here? To then?
// Also i have a conditional check in my logic, which is to make sure the numbers of players doesn't exceed the max_players before adding the player
t.players = where the existing players are stored
t.max_players = maximum number of players a game can have
if(t.players.length >= t.max_players)
// How do i send back a message to client saying that the game is full?
// Throw an error like this?
throw new functions.https.HttpsError('failed-condition', 'The game is already full');
}).then(result => {
}).catch(error => {
// and handle it here to send message to client?
});