Orinoco is a CMS or wiki to handle PUT requests from a front end client such as Octavo. The majority of the code is a Python 3 package, used in CGI.
This page was created using Orinoco on Apache.
Download the source from Github.
Pages are sent to the server using HTTP PUT requests. Users are not authenticated using Orinoco, so any authentication method compatible with the server can be used. Orinoco does the following:
Appending to a log file is apparently atomic on POSIX systems, with some caveats.
The versioned filename format is:
<unixtime>_<user>_<filename>
So for example, orinoco.html
might be versioned as 1362267866_sbp_orinoco.html
Similarly, the change log entry format is:
<unixtime> <user> <filename>
Which, continuing the example above, would store 1362267866 sbp orinoco.html
Unix time is used instead of a human readable format because it is compact, unlikely to incur timezone confusion, and sorts well until 20 November 2286.
These two formats make it possible to do things such as showing all versions of a page, computing a delta between two specific revisions, etc. It is also possible to tidy away the versioned files using tar and bzip2, for example.
The version control system does not use git because state must be easy to recover, and race conditions and conflicts requiring manual merges must be avoided. In fact, no repository states that need manual attention must occur.
The creation of a temporary file avoids race conditions when, for example, two people are editing the same file simultaneously, or one person is loading a file whilst another edits. Copying and moving files on POSIX are atomic operations.
The links database uses the python shelve module. Shelves modify and require certain permissions on themselves, for some inexplicable reason, which can be a problem when you have a finely tuned permissions setup on your server. For example, if you run tools on the shelf as one user, then you may find that the HTTP server can no longer access the shelf because Python changed the permissions on the file. Stranger still, nobody else on the web seems to have noticed this.
os.remove(temp_path)
in appropriate places in put.py
[DONE]Code for checking duplicates:
if os.path.isfile(page_path): old_size = os.path.getsize(page_path) new_size = os.path.getsize(temp_path) if old_size == new_size: import zlib old_check = 0 with open(page_path, "rb") as f: for line in f: old_check = zlib.adler32(line, old_check) new_check = 0 with open(temp_path, "rb") as f: for line in f: new_check = zlib.adler32(line, new_check) if old_check == new_check: os.remove(temp_path) server.error(500, "Won't save duplicate pages")