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)}}
/content/body/p[4]/span, reference to undefined name 'bioscreencast': line 1, column 1 (click for details)MindTouch.Deki.Script.DekiScriptUndefinedNameException: reference to undefined name 'bioscreencast': line 1, column 1
at MindTouch.Deki.Script.DekiScriptVar.Evaluate (MindTouch.Deki.Script.DekiScriptEnv env) [0x00000]
at MindTouch.Deki.Script.DekiScriptAccess.Evaluate (MindTouch.Deki.Script.DekiScriptEnv env, Boolean evaluateProperties) [0x00000]
at MindTouch.Deki.Script.DekiScriptAccess.Evaluate (MindTouch.Deki.Script.DekiScriptEnv env) [0x00000]
at MindTouch.Deki.Script.DekiScriptCall.Evaluate (MindTouch.Deki.Script.DekiScriptEnv env) [0x00000]
at MindTouch.Deki.Script.Dom.DekiScriptDomExpr.Evaluate (MindTouch.Deki.Script.DekiScriptEvalContext context, System.Xml.XmlNode parent, MindTouch.Deki.Script.DekiScriptEnv env) [0x00000]
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..'&width='..args.width..'&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&width=672&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..'&widt h='..args.width..'&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&width=%s&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()