Application plugins

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 of the Control Center. To see one in action, copy the two files in the SamplePythonPlugin directory to $/AppPlugins and restart Awasu. You should see a new entry in the Control Center's 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:

[Config]
Plugin=SamplePythonPlugin.py
AppPluginId=SamplePythonPlugin
AppPluginDisplayName=Sample Python Plugin
The Plugin parameter gives the name of the actual 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 Control Center, the plugin will be asked to generate an initial 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=...
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 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, however, also defines a global plugin parameter:

[PluginParameterDefinition-1]
Name=DomainName
Type=string
DefaultValue=http://www.test.com
Description=Domain name for generated URL's.


[ChannelParameterDefinition-1]
Name=nItems
Type=int
DefaultValue=10
Description=Number of items to generate.


[ChannelParameterDefinition-2]
Name=ItemTitleStem
Type=string
DefaultValue=Item Title
Description=Stem to use for generated item titles.


[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. In other words, if the user changes their values, it will affect every channel. This example also defines 3 per-channel parameters that can be set independently for each channel.

 

Writing interactive plugins

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 allows users to interact with the plugin. The general format of these URL's looks like this:

PLUGIN_SERVER_URL/APP_PLUGIN_ID/RequestName?ParamString
where 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 (as long as the URL remains a valid one, of course) 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 would be called with the following information in the INI file:
[System]
Command=ProcessRequest
PluginRequest=foo/bar
ParamString=p1=Hello&p2=World

Sending requests to Awasu

Requests can be sent to the main Awasu application in a similar way. This time, you use the URL stem specified in the AppServerUrl parameter. For example, to embed a link that allows users to subscribe to Awasu's feed, you would do something like this:

url = APP_SERVER_URL + "/subscribe?url=http://www.awasu.com/news.rss"
print "Click <A href='" + url + "'>here</A> to subscribe to Awasu."

A list of valid requests is given in the appendix. If you're technically-minded, a description of how this all works can also be found in the appendix.

 

How the sample application plugin works

So, to get 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[1] 

# 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 i.e. 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 output. Awasu will detect this and treat it as an error.

This is the generateMainPage() function that builds the plugin's initial HTML 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.
url = appServerUrl + "/subscribe"
url = url + "?url=" + appPluginServerUrl + "/" + APP_PLUGIN_ID + "/foo/bar"
url = url + "?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. In other words, 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>"