Writing an application plugin is a very similar process to writing a channel plugin. However, instead of being selected via the Channel Wizard, they are loaded by Awasu when it starts and appear in the Plugins window.
To see an application plugin in action, copy the two files in the SamplePythonPlugin/ directory to the AppPlugins/ directory in the Awasu installation directory, then restart Awasu. You should see a new entry in the Plugins window.
When Awasu starts, it scans AppPlugins/ (and its sub-directories) looking for files with a .plugin extension. This file contains information about the plugin e.g.
[Config] Plugin = SamplePythonPlugin.py AppPluginId = SamplePythonPlugin AppPluginDisplayName = Sample Python Plugin
The Plugin parameter gives the name of the plugin script, which must reside in the same directory. AppPluginId must be a unique identifier string while AppPluginDisplayName is the display name that the user will see.
When the user first opens the plugin from the Plugins window, the plugin will be asked to generate an HTML page that will be shown to the user. The plugin script will be run with a Windows INI file as before, but with a few more parameters:
[System] Command = GenerateMainPage AppServerUrl = ... PluginServerUrl = ...
where the Command parameter specifies what the plugin is being asked to do. In this case, it will be GenerateMainPage and the plugin should accordingly print out to the console an HTML page that Awasu will show to the user in a browser window.
As before, you can define channel parameters for the plugin. This example also defines a global plugin parameter:
[PluginParameterDefinition-1] Name = DomainName Type = string DefaultValue = http://www.test.com Description = Domain name for generated URL's. IsRequired = 1 [ChannelParameterDefinition-1] Name = nItems Type = int DefaultValue = 10 Description = Number of items to generate. IsRequired = 1 [ChannelParameterDefinition-2] Name = ItemTitleStem Type = string DefaultValue = Item Title Description = Stem to use for generated item titles. IsRequired = 1 [ChannelParameterDefinition-3] Name = GenerateDescriptions Type = bool DefaultValue = 1 Description = Flags if descriptions should be generated for feed items.
Global plugin parameters (defined in PluginParameterDefinition- sections) are shared by all channels serviced by the plugin i.e. if the user changes their values, it will affect every channel. This example also defines 3 other parameters that can be set independently for each channel.
It is possible to embed special links in the generated HTML page that will cause a request to be routed back to the plugin when the user clicks on them. This lets users interact with the plugin.
The general format of these URL's looks like this:
PLUGIN_SERVER_URL/APP_PLUGIN_ID/RequestName?ParamStringwhere PLUGIN_SERVER_URL is the string defined by the PluginServerUrl value in the INI file and APP_PLUGIN_ID is the plugin's ID. RequestName and ParamString can be anything you like and will be passed back to the plugin when the user clicks on the link. For example, if your HTML-generation code looked something like this:
url = PLUGIN_SERVER_URL + "/" + APP_PLUGIN_ID + "/foo/bar?p1=hello&p2=world" print "<a href='" + url + "'>Click here!</a>"when the user clicks on the link, the plugin will be called with the following information in the INI file:
[System] Command = ProcessRequest PluginRequest = foo/bar ParamString = p1=Hello&p2=World
Calls to the Awasu API can also be sent, using the values specified in the AppServerUrl and AppToken parameters.
For example, to embed a link that lets users subscribe to Awasu's feed, you would do something like this:
url = APP_SERVER_URL + "/channels/subscribe?url=http://www.awasu.com/news.xml" print "Click <a href='" + url + "'>here</a> to subscribe to Awasu."
If you're technically-minded, a description of how this all works can also be found here.
Getting back to our sample plugin, the script starts off with this piece of code (at the bottom of the file):
# get the name of the INI file configFilename = sys.argv # process the requested command scriptCmd = win32api.GetProfileVal( SYSTEM_PARAMETERS_SECTION_NAME , "Command" , "" , configFilename ) if scriptCmd == "GenerateMainPage" : generateMainPage( configFilename ) elif scriptCmd == "ProcessRequest" : pluginRequest = win32api.GetProfileVal( SYSTEM_PARAMETERS_SECTION_NAME , "PluginRequest" , "" , configFilename ) paramString = win32api.GetProfileVal( SYSTEM_PARAMETERS_SECTION_NAME , "ParamString" , "" , configFilename ) processRequest( configFilename , pluginRequest , paramString ) else : raise PluginError , "Unknown script command: "+scriptCmd
We get the name of our INI file and determine what we're being asked to do: generate the main page or process a request (because the user clicked on a link that has been routed back to us). An exception is raised if an error occurs which will print a message to the error console. Awasu will detect this and treat it as an error.
This is the generateMainPage() function that builds the plugin's HTML start page:
# get the app settings appServerUrl = win32api.GetProfileVal( SYSTEM_PARAMETERS_SECTION_NAME , "AppServerUrl" , "" , configFilename ) if appServerUrl == "" : raise PluginError , "No app server URL was specified." appPluginServerUrl = win32api.GetProfileVal( SYSTEM_PARAMETERS_SECTION_NAME , "AppPluginServerUrl" , "" , configFilename ) if appPluginServerUrl == "" : raise PluginError , "No app plugin server URL was specified." # get the plugin settings domainName = win32api.GetProfileVal( PLUGIN_PARAMETERS_SECTION_NAME , "DomainName" , "" , configFilename ) if domainName == "" : raise PluginError , "No domain name was specified." # generate a URL that will let the user subscribe to a channel that # we will generate. We embed some information in URL path and parameters # for demonstration purposes. These will get passed in to processRequest() # when the channel is updated. apiToken = win32api.GetProfileVal( SYSTEM_PARAMETERS_SECTION_NAME , "ApiToken" , "" , configFilename ) url = appServerUrl + "/channels/subscribe" url = url + "?token=" + apiToken url = url + "&url=" + appPluginServerUrl + "/" + APP_PLUGIN_ID + "/foo/bar?p1=Hello%26p2=World" # generate the main page print "<html>" print "<body>" print "<h2>Sample Python Plugin</h2>" print "<p>This is the main page for the sample Python plugin." print "<p>The plugin settings are:" print "<ul>" print " <li>DomainName: " + domainName print "</ul>" print "<p>Click <a href='" + url + "'>here</a> to subscribe to a test channel." print "</body>" print "</html>"
We insert a link that will send a channel subscription request to Awasu for a URL that will be routed back to us when it is used.
When Awasu goes to update the channel, the URL tells it that the channel is actually being generated by a plugin. The plugin is then run again with the Command parameter set to ProcessRequest and our processRequest() function is called:
# get the plugin settings domainName = win32api.GetProfileVal( PLUGIN_PARAMETERS_SECTION_NAME , "DomainName" , "" , configFilename ) if domainName == "" : raise PluginError , "No domain name was specified." # get the channel settings nItems = win32api.GetProfileVal( CHANNEL_PARAMETERS_SECTION_NAME , "nItems" , 15 , configFilename ) itemTitleStem = win32api.GetProfileVal( CHANNEL_PARAMETERS_SECTION_NAME , "ItemTitleStem" , "Item Title" , configFilename ) generateDescriptions = win32api.GetProfileVal( CHANNEL_PARAMETERS_SECTION_NAME , "GenerateDescriptions" , 1 , configFilename ) # put together a channel description description = ... # code not relevant to this discussion snipped here # generate the RSS feed print "<rss>" print "<channel>" print print "<title>Sample Python Plugin</title>" print "<link>" + domainName + "</link>" print "<description><![CDATA[" + description + "]]></description>" print for i in range(1,nItems+1) : print "<item>" print " <title>" + itemTitleStem + "-" + str(i) + "</title>" print " <link>" + domainName + "/item" + str(i) + ".html</link>" if generateDescriptions : print " <description>This is a dummy description for item " + str(i) + "</description>" print "</item>" print print "</channel>" print "</rss>"