Can a plugin react to an event from another plugin?

Do you have questions about writing plugins or scripts in Python? Meet the coders here.
Post Reply
Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Can a plugin react to an event from another plugin?

Post by Septik » Sat Oct 14, 2017 8:50 am

Working on a plugin that needs to react to a message to the Webserver. Is this possible, and how would I go about it? Preferably, I'd have a function that receives the message in the event and does some work with it.

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Sat Oct 14, 2017 2:20 pm

it sure can react.


what you would do is bind a callback function to the event..

so if you are making a plugin that needs to know if an event has gotten triggered you would have to add the following code to your plugin
when the plugin starts you will need to bind a callback method to that event. you are also able to pass variables to this if you like but if no variables are passed it will pass an instance of the notification handler instead. so you will always have to specify at least one keyword in your callback even if you do not use it. and you have to remember to unbind the event when you stop your plugin.

you would use eg.event to access the actual event it's self. so if there is a message in the payload. eg.event.payload is what you would want to do. Now remember this is running in the action thread which is the thread that all events are processed in so if whatever it is you are doing is going to take a long while or trigger any kind of a loop better to create a new thread to handle it and return True or False so the action thread can continue on it's merry way.

Code: Select all


def __start__(self):
    eg.Bind('Name.Of.The.Event', self.SOME_METHOD)
	
def __stop__(self):
    eg.Unbind('Name.Of.The.Event', self.SOME_METHOD)

def SOME_METHOD(self, dummy_event):
    # do what you need to do here. but you will need to return a True or a False.
    # if you return True the event will not process any further if you return False
    # the event will move onto processing the macros it is tied to
    return False

If you like the work I have been doing then feel free to Image

Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Re: Can a plugin react to an event from another plugin?

Post by Septik » Sat Oct 14, 2017 3:50 pm

kgschlosser wrote:
Sat Oct 14, 2017 2:20 pm
it sure can react.


what you would do is bind a callback function to the event..

so if you are making a plugin that needs to know if an event has gotten triggered you would have to add the following code to your plugin
when the plugin starts you will need to bind a callback method to that event. you are also able to pass variables to this if you like but if no variables are passed it will pass an instance of the notification handler instead. so you will always have to specify at least one keyword in your callback even if you do not use it. and you have to remember to unbind the event when you stop your plugin.

you would use eg.event to access the actual event it's self. so if there is a message in the payload. eg.event.payload is what you would want to do. Now remember this is running in the action thread which is the thread that all events are processed in so if whatever it is you are doing is going to take a long while or trigger any kind of a loop better to create a new thread to handle it and return True or False so the action thread can continue on it's merry way.

Code: Select all


def __start__(self):
    eg.Bind('Name.Of.The.Event', self.SOME_METHOD)
	
def __stop__(self):
    eg.Unbind('Name.Of.The.Event', self.SOME_METHOD)

def SOME_METHOD(self, dummy_event):
    # do what you need to do here. but you will need to return a True or a False.
    # if you return True the event will not process any further if you return False
    # the event will move onto processing the macros it is tied to
    return False

Thanks, appreciate the clear explanation. Before reading this, I implemented the following:

Code: Select all

    def waitForCode(self):
        time_out = time.time() + 30
        accessCode = None
        
        print "Attempting to acquire access code."
        
        while time_out > time.time():
            if eg.event.prefix == "HTTP":
                code = eg.event.suffix
                accessCode = code.split("code=", 1)
                break
                
        if accessCode == None:
            print "Failed to retrieve access code!"
            return
            
        <code for fetching access code>

    def __call__(self):
        <other stuff>
        threadWaitForCode = threading.Thread(target=self.waitForCode,args=())
        
I went with the separate thread to be able to use a timeout. No idea if this is an efficient way of doing things however! Pretty much started using Python a couple of days ago.

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Sat Oct 14, 2017 6:41 pm

the biggest issue with that is the super high CPU overhead and also EG will error when closing because it has no way to stop the thread from running.

I have given several code examples of how to use threading properly so EG can shutdown properly. Tho these coding examples are designed more for a script so you would be able to remove the binding to Main.OnClose and have the __stop__ method call the stop in the thread instead. this way it will shutdown if someone disables the plugin.

if there is a way to go about doing what you want to do without the need to spin off a thread that has to do endless looping to find a specific thing then that is always the best. by using the bind method with a callback it stores the callback using the event name as a marker for it. so that when the event comes in it looks for available callbacks set to it. if it finds them then it will make a call to it. Not looping threads involved.

I stated to use a thread if what you are doing inside of the callback is going to take a while or has some kind of a loop in it. If the action thread stalls for more then 3 or 5 seconds i believe EG will go into a Not Responding. sometimes it can recover.. but if the time is to long it will crash EG. so that is when you would want to use the threading this way the callback can return properly and whatever it is you need to do can also be done without the crashing side effect.

any time you loop like you are without a pause (using time.sleep() is not the proper solution) the threads is chewing up an absoutly massive amount of CPU clicks. EG is coded to use only one core. so if you have a 4 core CPU and you see the EventGhost process using 25% of each of the cores. that is 100% of a single core and that is the hughest it will ever go. thus causing major slowdown for other things. you can set a wait interval of 0.1 seconds and drop from 100% of a single core down to 20%. which is a huge reduction. But in the land of Events this 0.1 seconds can cause you to miss an event. that's why it is better to do the callback method.
If you like the work I have been doing then feel free to Image

Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Re: Can a plugin react to an event from another plugin?

Post by Septik » Sat Oct 14, 2017 7:40 pm

I see. Really appreciate the feedback. After a little testing I was unable to implement this, however. The plugin just shows up as red when trying to import it, and last time I tried to import it when red it crashed EventGhost. I'd share some code but I wanna play around with it first cause I suspect you'd have to read through a lot of it to find my mistake(s). If I get any closer to a solution but still struggle I'll post my code here.

Anyway, thank you very much.

Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Re: Can a plugin react to an event from another plugin?

Post by Septik » Sat Oct 14, 2017 8:30 pm

Alright, after playing around with it some more I've now got something that doesn't crash, but it doesn't work either. Here's the code:

Code: Select all

class getFirstAccessToken(eg.ActionBase):
    name = "Get initial access token"
    description = "Perform this once if you haven't acquired an access token yet."
    
    def __start__(self):
        eg.Bind('HTTP', self.waitForCode)
        
    def __stop__(self):
        eg.Unbind('HTTP', self.waitForCode)
    
    
    def waitForCode(self, event):
        print "Attempting to acquire access code."

        accessCode = None
        print event.suffix
        
        accessCode = event.suffix
        
        if accessCode == None:
            print "Failed to retrieve access code!"
            return
        
        <Stuff happens here (mostly requests.post())>
        
        print "Access code successfully acquired!"
        
        return True
The event I'm trying to catch looks like "HTTP.code=<long string of text>". I've tried Bind/Unbind('HTTP.code' [...]) and ('HTTP.code=*') as well. That didn't work either but gave no errors.

Basically the waitForCode function (method?) never gets triggered. Not quite sure how to make it so. :(

Edit: In any case - would it be an idea to do eg.Bind in def __call__ and then eg.Unbind after (un/successfully) performing the waitForCode function?

Edit 2: Kind of unrelated, but I just discovered that if I bring up the plugin configure window (by loading the plugin), apply after making some changes and then click "Cancel", I get a bunch of errors. Can't really decipher them, apart from that it looks like EventGhost is trying to get attribute 'lastException' from a non-existing object:

Code: Select all

Traceback (most recent call last) (0.5.0-rc2):
  File "wx\_core.pyc", line 16766, in <lambda>
  File "C:\Program Files (x86)\EventGhost\eg\Core.py", line 218, in Notify
    listener(value)
  File "C:\Program Files (x86)\EventGhost\eg\Classes\MainFrame\TreeCtrl.py", line 769, in OnNodeChanged
    node.SetAttributes(self, itemId)
  File "C:\Program Files (x86)\EventGhost\eg\Classes\PluginItem.py", line 197, in SetAttributes
    if self.info.lastException or self.info.initFailed:
AttributeError: 'NoneType' object has no attribute 'lastException'
Traceback (most recent call last) (0.5.0-rc2):
  File "wx\_core.pyc", line 16766, in <lambda>
  File "C:\Program Files (x86)\EventGhost\eg\Core.py", line 218, in Notify
    listener(value)
  File "C:\Program Files (x86)\EventGhost\eg\Classes\MainFrame\TreeCtrl.py", line 769, in OnNodeChanged
    node.SetAttributes(self, itemId)
  File "C:\Program Files (x86)\EventGhost\eg\Classes\PluginItem.py", line 197, in SetAttributes
    if self.info.lastException or self.info.initFailed:
AttributeError: 'NoneType' object has no attribute 'lastException'
Edit 3: As for my initial issue: I guess it comes down to whether or not I can use eg.Bind with a wildcard event. Is that possible, somehow?

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Sat Oct 14, 2017 10:45 pm

I would need to see the plugin in it's entierty to see what is going on with the cancel button deal.

And you cannot use eg.Bind with a wild carded event. For that we would register a call back with eg.log.LogListener I am on my cell so I am not going to key out the code for it. I am not sure exactly how your plugin is supposed to work. So it might be best if ya zip it up and attach it to a post. This way I have a better idea of what you are wanting to do. As a suggestion if you have GitHub we can use that for me to provide coding examples it will show you exactly what has changed. Of you do not have GitHub I would suggest to get it. It makes it a lot easier to share code and to also conversate about changes or things that were done.

So I leave this at either do the GitHub thing and send me a link to it in a PM or zip it up and attach it. I will ha e a look see when o get home in a few hours
If you like the work I have been doing then feel free to Image

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Sat Oct 14, 2017 10:46 pm

I would need to see the plugin in it's entierty to see what is going on with the cancel button deal.

And you cannot use eg.Bind with a wild carded event. For that we would register a call back with eg.log.LogListener I am on my cell so I am not going to key out the code for it. I am not sure exactly how your plugin is supposed to work. So it might be best if ya zip it up and attach it to a post. This way I have a better idea of what you are wanting to do. As a suggestion if you have GitHub we can use that for me to provide coding examples it will show you exactly what has changed. Of you do not have GitHub I would suggest to get it. It makes it a lot easier to share code and to also conversate about changes or things that were done.

So I leave this at either do the GitHub thing and send me a link to it in a PM or zip it up and attach it. I will ha e a look see when o get home in a few hours
If you like the work I have been doing then feel free to Image

Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Re: Can a plugin react to an event from another plugin?

Post by Septik » Sat Oct 14, 2017 10:57 pm

Sounds great! I'm also on my phone right now, but already uploaded a pretty recent version of the plugin in this thread.

Regarding GitHub, I've been meaning to get it, and this is a great occasion for it. Will get it set up ASAP.

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Sun Oct 15, 2017 2:02 am

No worries m8

I am git stupid myself but I can help ya navigate through some of the verbage and basic tasks I would also suggest getting Pycharm for an IDE and you can use this to update to GitHub. Tho I am not 100% familiar with how it works. So I use gitkraken to set up a new repo or to create a new branch. Then I use Pycharm to code in and push the changes to GitHub. I do not know now how to have Pycharm handle it all. Maybe some day I will spend the time.

But I will help ya out the best I can.

Another good thing for you to do is to fork the EventGhost repo. And read the old/new pull requests and comments. It's a good way to learn the inner workings of EG. I do want to make a push to get some more information and docs as to the API of it. I am still learning it and finding new things almost on a daily basis.
If you like the work I have been doing then feel free to Image

Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Re: Can a plugin react to an event from another plugin?

Post by Septik » Sun Oct 15, 2017 3:23 pm

Thanks for the advice. I got myself PyCharm and was actually able to get it for free (student license)! I set up a repo and (after some struggling) manually uploaded the __init__.py to it. Here is the repo. Feel free to... make pull requests (is that what people do? :lol: ) If possible I can add you and others who want to participate to some sort of contributor list so you don't need to request permission. I'd need some instructions on how to achieve that, however.

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Sun Oct 15, 2017 10:18 pm

with github it's your code. all we do is make Pull Requests (get yer mind out of the gutter) if you you think the code is worthy of being added then you can merge the code into yours. No one should have that ability on your personal account except yourself.
If you like the work I have been doing then feel free to Image

Septik
Posts: 37
Joined: Sun Feb 15, 2015 1:29 pm

Re: Can a plugin react to an event from another plugin?

Post by Septik » Mon Oct 16, 2017 4:11 am

kgschlosser wrote:
Sun Oct 15, 2017 10:18 pm
with github it's your code. all we do is make Pull Requests (get yer mind out of the gutter) if you you think the code is worthy of being added then you can merge the code into yours. No one should have that ability on your personal account except yourself.
Makes sense! Still learning the details of GitHub. :oops: By the way: I understand you're probably busy, but could you share some example code or something that would help me solve the problem about reacting to a wildcard event?

You mentioned eg.Log.LogListener earlier, but I can't find any extensive info on it online so haven't been able to get the syntax right (pretty much guesswork at this point). This part is my major hurdle right now and I'd very much appreciate a gentle push! :)

User avatar
kgschlosser
Site Admin
Posts: 3595
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Can a plugin react to an event from another plugin?

Post by kgschlosser » Mon Oct 16, 2017 5:14 am

how about this..

I will kinda direct you and see if you can go from there.


This is how EG works. for the most part if an attribute (variable) of "eg" has functions then it is a class. and if it is a class then the class name is the module name. and the modules are located in eg/Classes

so if you go to your python install and open up the eg/Classes folder. you are going to find Log.py! and if you read Log.py and in the class Log you will find a method name AddLogListener (I made a boo boo on that one earlier when i called it LogListener) under that method you will see what it does and what it does with what you pass to it and it will also tell you what you have to pass to it in order for it to work. you will also need to read the method _WriteLine.

Another hint is how you can tell if an entry in the log is an event or not.

Code: Select all

if icon == eg.Icons.EVENT_ICON:
if you still have an issue trying to get it send me a PM
If you like the work I have been doing then feel free to Image

Post Reply