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 PluginThe 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?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 (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=WorldSending 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 # 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: "+scriptCmdWe 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>"