Shoutbox

Sleep - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: Sleep (/showthread.php?tid=96019)

Sleep by Scale on 12-18-2010 at 08:52 PM

Hey guys,

I'm working on a script, and i was wondering how to 'pause' the script.
Should i just call sleep in kernel32? The effect kinda depends on how the scripting engine is built.

Separate thread for each script?


RE: Sleep by mynetx on 12-18-2010 at 08:56 PM

Hello Scale,

To pause the execution, you would have to create a timer using MsgPlus::AddTimer. When the timer has expired, your function OnEvent_Timer will be called with the given Timer ID string.

Does this help you out?


RE: Sleep by Scale on 12-18-2010 at 09:09 PM

That's gonna make for some BAD coding :P
Timers and loops is a bad mix ;)

Guess sleep is out of the question then,
Thanks anyway


RE: Sleep by matty on 12-18-2010 at 11:47 PM

Currently each script is run inside the main thread of Windows Live Messenger. Calling Sleep will cause the entire thread to pause.

Simply externalize the code you wish to run after a specific matter of time. Pass the function name as the timer id then use eval to execute the function. Not the best way but currently the only plausible workaround.


RE: Sleep by Amec on 01-23-2011 at 08:06 AM

Instead of passing function names to OnEvent_Timer, you could implement setTimeout and use callbacks. An example implementation would be...

code:
var timers = [];
   
function setTimeout(func, delay) {
    var timerId = "TIMEOUT_" + delay + "_" + Math.floor(Math.random()*100000000);
    MsgPlus.AddTimer(timerId, delay);
    timers[timerId] = func;
    return timerId;
}

function clearTimeout(timerId) {
    if(timerId.substr(0, 7) === "TIMEOUT")
    {
        MsgPlus.CancelTimer(timerId);
        timers[timerId] = null;
    }
}

function setInterval(func, delay) {
    var timerId = "INTERVAL_" + delay + "_" + Math.floor(Math.random()*100000000);
    MsgPlus.AddTimer(timerId, delay);
    timers[timerId] = func;
    return timerId;
}

function clearInterval(timerId) {
    if(timerId.substr(0, 8) === "INTERVAL")
    {
        MsgPlus.CancelTimer(timerId);
        timers[timerId] = null;
    }
}

function OnEvent_Timer(timerId)
{
    if(timerId.substr(0, 7) === "TIMEOUT")
    {
        timers[timerId].call(this);
        clearTimeout(timerId);
    }
    else if(timerId.substr(0, 8) === "INTERVAL")
    {
        timers[timerId].call(this);   
        MsgPlus.AddTimer(timerId, Number(timerId.split("_")[1]));
    }
}

...and an example usage would be...

code:
function OnEvent_Initialize(MessengerStart) {
    [...] //do stuff

    setTimeout(function () { //sleep for two seconds
        [...] //do more stuff
    }, 2000);

}

It's not pretty, and can get pretty deeply nested... But I think it's better than evaling stuff.
RE: Sleep by Matti on 01-23-2011 at 11:02 AM

@Amec: That implementation would do the job just fine, but there's still room for improvement.

  • You're trying to add elements to the timers array, but since you're using a string as key you're actually just setting an object property. Either you use numerical indexes and make proper use of the array, or you just make timers an object. Because you're not actually using any array-specific features, you can simply get away with an object here.
  • Instead of parsing data out of the keys in OnEvent_Timer, you can just store objects as elements in timers and read the properties instead.
  • You should check whether the timerId actually exists in timers in OnEvent_Timer. Sure, chances are slim that you'll ever get an invalid timer, but you never know.
  • Try to reuse some of your code! setTimeout and setInterval are almost identical. ;)
I had a go with this myself, threw in some tasty OOP and here's what I came up with:
Javascript code:
/* Somewhat private worker classes */
// Timer sets up a timer and exposes methods
var Timer = function(fCallback, nInterval) {
    this.Callback = function() {
        fCallback.call(this);
        this.Cancel();
    };
    this.Interval = nInterval;
    // Add to storage
    this.Index = Timer.Storage.length;
    Timer.Storage.push(this);
    // Identifier for timer events
    this.Id = 'Timer#'+this.Index;
    MsgPlus.AddTimer(this.Id, this.Interval);
};
// Storage array as static property
Timer.Storage = [];
// Instance methods
Timer.prototype = {
    Refresh : function() {
        Timers[this.Index] = this;
        MsgPlus.AddTimer(this.Id, this.Interval);
    },
    Cancel : function() {
        Timers[this.Index] = null;
        MsgPlus.CancelTimer(this.Id);
    }
};
 
// Interval is identical to Timer, except for its Callback property
var Interval = function(fCallback, nInterval) {
    // Call superclass constructor
    Timer.apply(this, arguments);
    // Callback refreshes timer instead of canceling it
    this.Callback = function() {
        fCallback.call(this);
        this.Refresh();
    };
};
Interval.prototype = Timer.prototype; // Prototypical inheritance! :O
 
// Timer event handling
function OnEvent_Timer(timerId) {
    if((m = /^Timer#(\d+)$/.exec(timerId)) !== null) {
        var nIndex = 1*m[1], timer = Timer.Storage[nIndex];
        if(timer && timer.Callback) {
            timer.Callback();
            return;
        }
    }
    // Other timers can be handled here...
}
 
function setTimeout(func, delay) {
    var timer = new Timer(func, delay);
    return timer.Index;
}
function setInterval(func, delay) {
    var interval = new Interval(func, delay);
    return interval.Index;
}
 
function clearTimeout(timerIndex) {
    var timer = Timer.Storage[timerIndex];
    if(timer && timer.Cancel) {
        timer.Cancel();
    }
}
var clearInterval = clearTimeout;

In fact, you could use this code without the functions at the bottom and simply go with the classes.

I don't want to scare you off, I simply thought I'd show you another way to do it. Feel free to play around with it. :)