-*- mode:org -*- Wriaki: the Riak-based Wiki
Wriaki is a wiki-like web application, intended to illustrate a few strategies for storing data in Riak.
To build Wriaki, you will need Erlang OTP release R13B03 or later, Mercurial, and Git.
To run Wriaki, you will need Riak, Python and the Wiki Creole Python package.
The easiest way to get Riak is to download a pre-built distribution from [http://downloads.basho.com/riak/]. Any version 0.9.1 or newer should work.
As of version 0.10.0, Riak offers two interfaces, HTTP and Protocol Buffers. Wriaki supports both interfaces. If you plan on using the HTTP interface you must be careful of port conflicts with Wriaki if they are run on the same machine. By default, Riak uses port 8098 on localhost while Wriaki uses port 8000. If you leave the default settings you do not need to worry about port conflicts.
Wriaki can also use features of Riak Search, if you have that installed. See the Configuration section for more information.
The easiest way to get Wiki Creole is by using easy_install:
$ easy_install Genshi $ easy_install Creoleparser
To setup Wriaki, first clone the source:
$ git clone git://github.com/basho/wriaki
Next, change to the source directory and run make:
$ cd wriaki $ make rel
After building, you should have a rel/wriaki/
subdirectory under the
source directory. Configuration for wriaki is stored in
rel/wriaki/etc/app.config
.
The settings that Wriaki knows about are:
salt
- the “salt” used for encrypting user passwords
riak
- the connection information for Riak
For Protocol Buffers, use:
{pb, {Host, Port}}
For HTTP, use:{http, {Host, Port, Prefix}}
http://<Host>:<Port>/<Prefix>/Bucket/Key
web_ip
- the IP to bind Wriaki’s webserver to
web_port
- the TCP port Wriaki should listen on
log_dir
- the directory to write Wriaki’s access log in
search_enabled
- expose full-text article search through use of Riak Search features. Only set to ‘true’ if you are running Riak Search instead of vanilla Riak.
Before running Wriaki, ensure that your Riak cluster is started and reachable.
Next, run the wriaki script in your rel/wriaki/bin/
subdirectory:
$ rel/wriaki/bin/wriaki console
To start Wriaki in the background, use start
instead of console
on
that command line.
There are four basic objects in the Wriaki system: article, archive, history, and user.
One article object exists for each page on the wiki.
The key for an article object is the title of the wiki page, base64 encoded.
Articles are stored in the article
Riak bucket. The article
bucket is configured for allow_mult=true
. This is done to allow
multiple users to edit an article concurrently. If they save at the
“same” time, the article object will contain siblings on the next
read, and Wriaki will warn the viewer that there are multiple versions
of the article that are currently considered “the latest.”
The value of an article object is JSON, with the fields:
text
- (string) content in wiki markup format
message
- (string) commit message
version
- (string) version hash
timestamp
- (int) edit date
Articles use one link to track which user created that version of the
object. The link will be to an object in the user
bucket, and will
be tagged editor
.
When conflicting writes to an article are found, the user will be given the option to view the version they want. Editing the article will resolve the conflict.
One archive object exists for each version (past and present) of each article.
The key for an archive object is the version hash appended with the article object key, separated by a dot.
Archive objects are stored in the archive
bucket. The bucket is
left as allow_mult=false
.
The value of an archive object is exactly the same as that of an article object.
The archive object has the same link header as the article object.
Archive objects should be write-once, due to their key generation, and thus will not need a merge strategy.
One history object exists for each page on the wiki. The purpose of the history object is to hold links to all versions of each article object.
The key for the history object is the same as the key for the article object.
History objects are stored in the history
bucket. The bucket is
configured for allow_mult=true
to allow multiple users to add
article versions (thus updating the history) concurrently.
History objects have no data in their bodies.
History object have one link for each version an article has had. The
links will target objects in the archive
bucket, and will be tagged
with the timestamp of the article version.
Merging two versions of an archive object is simply set-unioning the list of links.
One user object exists for each registered user of the wiki. This object keeps track of the user’s password and other data.
User objects are keyed by url-encoded usernames.
User objects are stored in the user
bucket. The bucket is left as
allow_mult=false
because only the user should be updating that
user’s object (no concurrent writing).
The value of a user object is JSON with the fields:
email
- (string) email address
password
- (string, base64) encrypted
bio
- (string) short biography
User object have no headers.
No merge is needed for user objects. They should only be edited by their owners, and last-write-wins will be good enough to handle that.
One session object exists for each logged-in user. This object keeps track of when the user last pinged the wiki, and when they will be automatically logged out.
Session objects are keyed by a randomly-generated session token.
Session objects are stored in the session
bucket. This bucket is
left as allow_mult=false
because only the active session should be
updating it.
The value of a session object is JSON with the fields:
username
- (string) username for the user of this session
expiry
- (integer) time at which the session will expire
Session objects have no headers.
No merge is needed for session objects. They should only be editred by the active session, and last-write-wins will be good enough to handle that.
Wriaki exposes the following resources:
/user
- login page, GET-only
/user/<username>
- User’s settings
GET: with no query parameters returns a page of public information about the user
with query parameter
?edit
, returns a form for the user to update their information (user is redirected to non-query-parameter URL if this is not their login)PUT: change user data
POST: login
/user/<username>/<sessionid>
- Session information
GET: get expiry time of the session, also extends the session’s expiry
DELETE: remove the session, “logout”
/wiki/<page name>
- Wiki page
GET: with no query parameters returns the rendered wiki page
with query parameter
?edit
, returns a form for the user to edit the pagewith query parameter
?history
, returns a list of the known versions of the objectwith query parameter
?v=<version>
, returns the page rendered for the requested versionwith query paramaters
?diff&l=<left_version>&r=<right_version>
returns a line-by-line difference of the given versionsPUT: store a new version of the wiki page
POST: preview a new version of the wiki page
/static/*
- serve static files from disk
GET: retrieve the specified file