Playing a sound as a value changes - meteor

I am developing a lobby for multiplayer online experiment. The lobby basically is a stage where the participants wait until we have the required number of people. I want to play a bell sound that I have in the project public directory public/newPlayerSound.mp3 .. and I have the following helper:
Template.lobby_page.helpers({
numWaiting(){
if (Meteor.userId()){
let lobby = Lobbies.findOne({players:Meteor.userId()});
if (lobby){
//play the newPlayerSound.mp3
return lobby.players.length
}
}
},
});
I want to play the newPlayerSound.mp3 every-time the numWaiting() changes. What would be an easy way to do this?

Based on what Uri has said here, you can use HTMLAudioElement.
new Audio("newPlayerSound.mp3").play()

Related

Firestore is unusably slow with a simple hello world scenario

I have one collection with a document that has a subcollection of three documents something like this.
task-sets: {
"<owners-uid>": {
owner: <owners-uid>,
tasks: {
"<task 1 id>": {
name: 'Bake a Cake',
description: 'Bake a delicious cake with a colorful frosting.'
},
"<task 2 id>": {
name: 'Invite Friends',
description: 'Invite any friends that might enjoy delicious cake.'
},
"<task 3 id>": {
name: 'Pin Tail on Donkey',
description: 'Blindfold a guest and have them attempt to pin a paper tail to a poster of a tailless donkey.'
},
}
}
I then run this code to get this one document.
export async function getRemoteTasks() {
const user = authState.get().user;
const db = firebase.firestore();
console.time('getRemoteTasks');
const taskSetDocument = await db.collection('task-sets').doc(user.uid).get();
const querySnapshot = await taskSetDocument.ref.collection('tasks').get();
console.timeEnd('getRemoteTasks');
let tasks = [];
querySnapshot.forEach(fillArray(tasks));
return tasks;
}
The two query lines in this function between console.time and console.timeEnd take 115 seconds to run.
Please do not duplicate this. Believe me, I've gone through every single one of the slow firestore query questions on SO. All of them are performance problems. My problem is that firestore is broken for me. This is a simple hello world test case with a relatively simple query. It is taking forever. Something is broken here. I need to know what that is. None of the other questions answered my problem at all.
Maybe its because this is a development run and if I deployed it, it would get faster. Please, I've put so much work into this project as a firebase project, and this one problem is a deal breaker for me.
Eureka! I found my problem and the solution. It was very esoteric. I have a react app. I am using a package called react-ridge-state to hold globally the authentication status of my user. I have an Authentication provider that sets that global state. What I didn't realize is that react-ridge-state causes a component rerender when the state is changed. I suppose that is the point of it. This created an infinite loop rerender. That was causing the slow down, probably because it wasn't letting the promise resolve.
I wish there was a way to increase the visibility of rerender loops like this. This solution came to me in a dream last night, and I put a breakpoint in my code and found the loop. Way to go intuition!
Solution: Continuous rendering of components was preventing resolution of the promise returned by firestore.

How to create an alert to notify an user when some amount % of threshold reached DailyAsyncApex Executions

On 2 occasions in the past month, we have managed to hit our daily limit on asynchronous apex executions. Salesforce temporarily increased our limit to 425000 but it will be scaled down to 250000 in a week's time. Once we reach the limit, a lot of the SF functions will fail and this has tremendously impacted both internal staff and external customers.
So to prevent this from happening in the future, we need to create some kind of alert in Salesforce to monitor our daily asynchronous apex method executions. Our maximum daily limit is 250000. The alert will need to create a P3 helpdesk ticket and notify couple of users say USER A and USER B once it reaches 70% threshold.
Kindly advise what is possible to achieve the same
Thanks & Regards,
Harjeet
There's a promising Limits method but it doesn't seem to work currently ("reserved for future use"): System.debug(Limits.getAsyncCalls() + ' / ' + Limits.getLimitAsyncCalls());
There's an idea you can upvote: https://success.salesforce.com/ideaView?id=0873A0000003VIFQA2 ;)
You could query SELECT COUNT() FROM AsyncApexJob WHERE ... but that sounds like a bad idea ;)
I think your best course of action is to use SF REST API. There's a "limits" resource you can fetch. You could do it from SF itself (bad idea because if you'd schedule it to run every hour then well, of course it will contribute to the limit consumption too ;)) or from some external app that'd connect to your SF...
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_limits.htm
You can quickly try it out for example in workbench.developerforce.com before you decide you do want to deep dive into coding it.
Of course if you have control over your batch jobs, queuable, schedulable & #future calls you could implement some rough counter of executions in a helper object for example... won't help you much if most of the jobs are coming from managed packages though...
Got 1 more idea but it's pretty hardcore - you should be able to make a REST API call from javascript. so you could create a simple VF page (even without any apex controller), put JS callout on it, have it check every 5 mins and do something if threshold is hit... But that means IT person would have to have this page open all the time (perhaps as a home page component)... Messy :)
I was having the exact same issue so I created a simple JsForce script in NodeJS to monitor the call to the /limits endpoint.
You can connect a Free Monitoring service like UpTimerobot.com or PingDom.com and get an email when you find the Word "Warning" >50% or "Error" > 80%.
async function getSfLimits() {
try {
//Let's login into salesforce
const login = await conn.login(SF_USERNAME, SF_PASSWORD+SF_SECURITY_TOKEN);
//Call the API
const sfLimits = await conn.requestGet('/services/data/v51.0/limits');
return sfLimits;
} catch(err) {
console.log(err);
}
}
https://github.com/carlosdevia/salesforcelimits

Meteor: send message to user at hot code push

How can I let the user know when they are getting a hot code push?
At the moment the screen will go blank during the push, and the user will feel it's rather weird. I want to reassure them the app is updating.
Is there a hook or something which I can use?
Here's the shortest solution I've found so far that doesn't require external packages:
var ALERT_DELAY = 3000;
var needToShowAlert = true;
Reload._onMigrate(function (retry) {
if (needToShowAlert) {
console.log('going to reload in 3 seconds...');
needToShowAlert = false;
_.delay(retry, ALERT_DELAY);
return [false];
} else {
return [true];
}
});
You can just copy that into the client code of your app and change two things:
Replace the console.log with an alert modal or something informing the user that the screen is about to reload.
Replace ALERT_DELAY with some number of milliseconds that you think are appropriate for the user to read the modal from (1).
Other notes
I'd recommend watching this video on Evented Mind, which explains what's going on in a little more detail.
You can also read the comments in the reload source for further enlightenment.
I can image more complex reload logic, especially around deciding when to allow a reload. Also see this pacakge for one possible implementation.
You could send something on Meteor.startup() in your client-side code. I personally use Bert to toast messages.

Meteor realtime game - match two players according to their score?

I want to build a realtime quiz game which randomly matches two players (according to their winning rate if they are logged in). I've read through the book Discover Meteor and have a basic understanding of the framework, but I just have no idea of how to implement the matching part. Anyone know how to do that?
if you want to match users who have scores close to each other, you can do something like this : mongodb - Find document with closest integer value
The Meteor code for those Mongo queries is very similar, but there are some subtle differences that are kind of tricky. In Meteor, it would look something like this :
SP // "selected player" = the User you want to match someone up with
var score = SP.score; // selected player's score
var queryLow = {score: {$lte:score},_id:{$ne:SP._id}};
var queryHigh = {score:{$gte:score},_id:{$ne:SP._id}};
// "L" is the player with the closest lower score
var L=Players.findOne(queryLow,{sort:{score:-1},limit:1});
// "H" is the player with the closest higher score
var H=Players.findOne(queryHigh,{sort:{score:1},limit:1});
so, now you have references to the players with scores right above and right below the 'selected player'. In terms of making it random, perhaps start with a simple algorithm like "match me with the next available player who's score is closest" , then if it's too predictable and boring you can throw some randomness into the algorithm.
you can view the above Meteor code working live here http://meteorpad.com/pad/4umMP4iY8AkB9ct2d/ClosestScore
and you can Fork it and mess about with the queries to see how it works.
good luck! Meteor is great, I really like it.
If you add the package peppelg:random-opponent-matcher to your application, you can match together opponents like this:
On the server, you need to have an instance of RandomOpponentMatcher like this:
new RandomOpponentMatcher('my-matcher', {name: 'fifo'}, function(user1, user2){
// Create the match/game they should play.
})
The function you pass to RandomOpponentMatcher will get called when two users been matched to play against each other. In it, you'll probably want to create the match the users should play against each other (this package does only match opponents together, it does not contain any functionality for playing games/matches).
On the client, you need to create an instance of RandomOpponentMatcher as well, but you only pass the name to it (the same name as you used on the server):
myMatcher = new RandomOpponentMatcher('my-matcher')
Then when the users is logged in and which to be matched with a random opponent, all you need to do is to call the add method. For example:
<template name="myTemplate">
<button class="clickMatchesWithOpponent">Match me with someone!</button>
</template>
Template.myTemplate.events({
'click .clickMatchesWithOpponent': function(event, template){
myMatcher.add()
}
})
When two different logged in users has clicked on the button, the function you passed to RandomOpponentMatcher on the server will get called.
One implementation might be as follows:
A user somehow triggers a 'looking for game' event that sets an attribute on user.profile.lookingForGame to true. The event then makes a call to a server side Meteor method which queries for all other online users looking for games.
From there you it really depends on how you want to handle users once they 'match'.
To determine all online users, try using the User Status package:
https://github.com/mizzao/meteor-user-status
Once added, any online user will have an attribute in the profile object of 'online'. You can use this to query for all online users.

casperjs and a/b testing

i have a signup.js test that automates signing up for my web app (obviously). we're currently a/b testing a new flow that takes you to a different page ('.com/signupa' vs '.com/signupb') and i'm wondering what the best way to reflect this in my test.
options:
use evaluateOrDie and make it die at .com/signupb (this seems dumb)
flesh out test for .com/signupb and make it go that route if it hits that test (is this possible?) something like..
casper.waitForResource("classic.png",
function success() {
this.echo('on the old signup flow ');
<continue with regular signup test>
},
function fail() {
this.test.assertExists("classic.png");
<do something else>
});
any other ideas greatly appreciated!
My preference would be to hide some information in each of your pages, so you can cleanly switch on them. E.g.
<span id="version1"></span>
vs.
<span id="version2"></span>
Then, after submitting the form:
casper.then(function(){
if (this.exists('#version2')) {
testNewSite(this);
} else {
testOldSite(this);
}
});
But detecting on something you already know is only in one of the pages, like the "classic.png" you show in your question, is also fine. (It just feels a little more brittle: the web development team can break your tests by renaming that image, or putting an image with that name in the new version, etc., etc.)

Resources