Bioscreencast Wiki > Writing Python extensions for deki-wiki

Writing Python extensions for deki-wiki

From $1

The amazing thing about deki-wiki is that it has a WYSIWYG interface and front end - WYSIWYG means "what you see is what you get " . SO unlike most wikis where you need to learn some "markup"  ( formatting guidelines). In dek-wiki you pretty much just compose your wiki post like you would compose an email in gmail .

The other great thing about deki-wiki is the ability to extend deki-wiki using extensions that call web-services. So say you had all your data sitting on a custom database and you wanted to have it easily embeddable on deki-wiki , you can write a custom extension which talks  to your webservice.

We have our custom database --i.e the database of all videos and associated data in our database and we decided to make these videos easily embeddable inside any wiki at bioscreencastwiki. SO to embed a video from our site you would just have to grab the video code ( from the section wiki-embed) and then embedded it with the custom tag given below. You can control the size of the video with the two numbers in the tag . SO given here is video with id f404c3f31514978ff064080d5b0e6dd5 displayed at its native size of 896 by 736.

{{bioscreencast.embed("f404c3f31514978ff064080d5b0e6dd5",896,736)}}

 

SO Now onto

What gets sent back and forth

The wiki learns about the extension based on the "GET" information the extension sends back.

Our extension returns the following GET ( check out http://www.bioscreencast.com:82) . On safari you may have to select view-source to see the xml.

Or the  xml message which is the "manifest" for the web service

 

<extension>
  <title> My extension </title>
<namespace>bioscreencast</namespace>
<function>
 <name>embed</name>
 <uri>http://67.207.145.173:82</uri>
 <description>Returns an embedded video from the Bioscreencast  site</description>
 <param name="video" type = "uri">video uri</param>
 <param name="width" type ="int">video width</param>
 <param name="height" type ="int">video height</param>
  <return>
  <html xmlns:eval="http://mindtouch.com/2007/dekiscript">
  <body>
  <embed src="http://www.code-itch.com/flashplayer/mediaplayer.swf"
  eval:width="args.width"
  eval:height="args.height"
  allowscriptaccess="always"
  allowfullscreen="true"
  eval:flashvars="'height='..args.height..'&amp;width='..args.width..'&amp;file='..args.video"     />
 </body>
 </html>
 </return>
 </function>
 </extension>

The wiki talks to a webservice registered at a particular URL in the control panel. So as a wiki administrator you have to setup a service in the control panel. The language in which the two communicate is XML over HTTP . So the way a wiki understands the extension is by the answer the extension delivers to a GET request . The actual extension information interchange is handled by a POST message. 

SO for a link like the one above , here is what gets posted from the wiki to the web service..

 <value type="list"><value key="#" type="str">1c80e8d95bc7861a755b4fad76b29a32</value><value key="#" type="num">800</value><value key="#" type="num">600</value></value>

And the web service then processes this information , formats the output in dekiscript or another flavor of xml or even simple html and returns this "POST".

 <html> <body>

      <embed

        src="http://www.code-itch.com/flashplayer/mediaplayer.swf"

  width="672"

    height="552"

      allowscriptaccess="always"

        allowfullscreen="true"

   flashvars="height=552&amp;width=672&amp;file=http://bioscreencast.s3.amazonaws.com/243/1c80e8d95bc7861a755b4fad76b29a32.mov"      />

   </body>

    </html>
 

SO together the GET just establishes the messages that you can send ..and the post handles the actual information sent to the web-service , whereupon it chews through that formats the wiki markup , wraps it in xml that dekiwiki understands and returns it back to the wiki for display accordingly.

 

The extension pseudocode:

The extension is base don writing a custom BaseHTTPRequestHandler in Python running on an HTTPServer

All the code does is

  • Connect to database
  • Handle the GET request by describing the extension in dekiscript xml
  • Handle the POST request by parsing input values using python minidom API and then  constructing the return xml which describes the embed tag for the video

 

The extension code:


The code follows here

 #!/usr/bin/env python

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

import CGIHTTPServer,cgi,re,MySQLdb

class MyHandler(CGIHTTPServer.CGIHTTPRequestHandler):

def get_metadata(self,video_metadata_id):

import MySQLdb
connection = MySQLdb.connect ( host= "localhost" ,user = "craptastic",passwd = "crapulous",db = "the right database")
cursor = connection.cursor()
cursor.execute("select all the stuff required- SQL goes here)
rows = cursor.fetchall()
file_nm = "%s" % rows[0][0]
ext = file_nm[-3:]
uid = "%s" % rows[0][1]
video_dim_full = "%s" % rows[0][2]
video_dim = video_dim_full.split("x")
val_array = [ext,video_dim[0],video_dim[1],uid]
return val_array

def process_string_xml(self,dekixml):
import xml.dom.minidom
from xml.dom.minidom import Node
width ,height ,fin_width , fin_height ,ext,arg = 0,0,0 , 0 , "flv",""
dat = []
doc = xml.dom.minidom.parseString(dekixml)
dekistring = ''
text = doc.getElementsByTagName("value")
video_id = doc.getElementsByTagName("value")[1].lastChild.data
# Handle case where API call has full video_link text 
rex = "http\:\/\/www\.mywebsite\.com\/bsc\_movwin\.html\?var1\=(.*)\&var2\=(.*)\&var3=(. *)\&var4\=(.*)"
matched = re.search(rex,video_id)
if (matched != None):
arg = "%s" % matched.group(2)
dat = self.get_metadata(arg)
else:
arg = "%s" % video_id
dat = self.get_metadata(arg)
ext = dat[0]
try:
width = doc.getElementsByTagName("value")[2].lastChild.data
height = doc.getElementsByTagName("value")[3].lastChild.data
except:
pass
if width != 0 and height != 0 :
fin_width = min(int(width) , int(dat[1]))
fin_height = min(int(height),int(dat[2]))
vals = [dat[3],arg,fin_width,fin_height,ext]
else:
fin_width = int(dat[1])
fin_height = int(dat[2])
vals = [dat[3],arg,fin_width,fin_height,ext]
return vals

def do_GET(self):
self.send_response(200)
self.send_header('Content-type','application/xml')
self.end_headers()
str = '''<extension>
<title> My extension </title>
<namespace>bioscreencast</namespace>
<function>
<name>embed</name>
<description>Returns an embedded video from the mywebsite.com site</description>
<param name="video" type = "uri">video uri</param>
<param name="width" type ="int">video width</param>
<param name="height" type ="int">video height</param>
<return>
<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
<body>
<embed
src="mediaplayer.swf"
eval:width="args.width"
eval:height="args.height"
allowscriptaccess="always"
allowfullscreen="true"
eval:flashvars="'height='..args.height..'&amp;widt h='..args.width..'&amp;file='..args.video" />
</body>
</html>
</return>
</function>
</extension>
'''
print str
self.wfile.write(str)

def do_POST(self):
data = self.rfile.read(int(self.headers["content-length"]))
print data
self.send_response(200)
self.send_header('Content-type',"application/xml")
# Actually parse data and get string that has to be wrapped in dekiscript
# response = '''<value type="list"><value type="str">%s</value></value>''' % dekistring
vals = self.process_string_xml(data)
response = '''<value type="list"><value type="xml">
<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
<body>
<embed
src="http://www.mywebsite.com/flashplayer/mediaplayer.swf"
width="%s"
height="%s"
allowscriptaccess="always"
allowfullscreen="true"
flashvars="height=%s&amp;width=%s&amp;file=http://mywebsite.s3.amazonaws.com/%s/%s.%s" />
</body>
</html></value></value>''' % (vals[2],vals[3],vals[3],vals[2],vals[0],vals[1],vals[4])
print response
self.send_header("Content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
self.wfile.flush()
self.connection.shutdown(1)

def main():
try:
server = HTTPServer(('', 82), MyHandler)
print 'Welcome to the machine...',
print 'Press ^C once or twice to quit.'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()

if __name__ == '__main__'
main()

Tags:
 
Images (0)
 
Comments (0)
You must login to post a comment.