Commit abe4d766 authored by Sven Franck's avatar Sven Franck

README: updated to current documentation

parent ef828373
Javascript Input/Output
jIO - Javascript Input/Output
=======================
Powerful, Intelligent, and Intuitive back-end to write over the internet
========================================================================
A client-side library to manage documents across local and cloud storages.
====================================================================
How easy is it to get, save or remove a document?
Getting Started
-------------------------------------------------
To set up jIO, include the source file, dependencies and connectors for the storages you plan to use in your page header (dependencies vary depending on the types of storages being used):
```
<!-- jio core-->
<script src="jio.js"></script>
<!-- jio dependencies-->
<script src="md5.js"></script>
<!-- jio storage connectors -->
<script src="localstorage.js">
<script ...>
<!-- jio complex queries -->
<script src="jio.complex_queries.js"></script>
```
Then create your jIO instance like this:
```
var jio = jIO.newJio({
"type": "local",
"username": "your_username",
"application_name": "your_application_name"
});
```
Documents and Methods
-------------------------------------------------
Documents are JSON strings that contain <em><u>meta-data</u></em>
(properties, e.g. filename) and <em><u>attachments</u></em> (optional content, e.g. a base64-encoded image).
jIO exposes the following methods to <em><u>create</u></em>,
<em><u>read</u></em>, <em><u>update</u></em> and <em><u>delete</u></em> documents:
```
// get 'document.txt'
jio.get('document.txt',function (err, val) {
console.log (err || val.content);
// create and store new document
jio.post({"title":"some title"}, function (err, response) {
// console.log(response):
// {"ok":"true", "id":"cabc9...826" }
});
// update 'document.txt'
jio.put({_id:'document.txt',content:'newcontent'}, function (err, val) {
console.log (err || val);
// create or update an existing document
jio.put({"_id":"demoID", "title":"new title"}, function (err, response) {
// console.log(response):
// {"ok":"true", "id":"demoID" }
});
// get a list of documents
jio.allDocs(function (err, val) {
console.log (err || val.total_rows);
// add an attachement to a document (Note: no underscore on id!)
jio.putAttachment({"id":"demoID/myImg", "data":"abc"}, function(err, response){
// console.log(response):
// {"ok":"true", "id":"demoID/myImg"}
});
// remove 'document.txt'
jio.remove ({_id:'document.txt'}, function (err, val) {
console.log (err || val);
// read a document or an attachement
jio.get("demoID/myImg", function (err, response) {
// console.log(response):
// {"data":"abc"}
});
```
Documentation Index
===================
+ [What is jIO?](#what-is-jio)
+ [How does it work?](#how-does-it-work)
+ [Getting started](#getting-started)
+ [Where can I store documents?](#where-can-i-store-documents)
[**For developers**](#for-developers)
+ [Quick start](#quick-start)
+ [How to design your own jIO Storage Library](#how-to-design-your-own-jio-storage-library)
+ [Error status](#error-status)
+ [Job rules](#job-rules)
+ [Code sample](#code-sample)
[**Authors**](#authors)
[**Copyright and license**](#copyright-and-license)
What is jIO?
------------
jIO is a JavaScript Library that stores/manipulates documents on storage servers over the internet in an asynchronous fashion.
How does it work?
-----------------
jIO is separated in 2 parts, core library and storage library(ies). The core must use some javascript objects (storages) to interact with the associated remote storage servers. jIO uses job management, so every request adds jobs in a queue which is saved on browser local storage in order to be restored later if the browser crashed or else. jIO will invoke all these jobs at the same time. Of course, adding an already ongoing job won't work, so there will be no conflicts.
Getting started
---------------
// delete a document or an attachment
jio.remove({"_id":"demoID"}, function (err, response) {
// console.log(response):
// {"ok":"true", "id":"demoID"}
});
This short tutorial is designed to help you get started using jIO. First, download the jIO core and the jIO storages scripts (git clone http://git.erp5.org/repos/jio.git) and their dependencies ([jQuery](http://jquery.com), [base64](http://www.webtoolkit.info/javascript-base64.html), [sjcl](http://crypto.stanford.edu/sjcl/), [sha2](http://anmar.eu.org/projects/jssha2/)). Then, add the scripts in your HTML page as following:
// get all documents
jio.allDocs(function(err, response){
// console.log(response):
// {
// "total-rows":1,
// "rows":[{
// "_id":"demoID",
// "title";"new text",
// "_attachments":{
// "myImg": {
// "digest":"md5-nN...",
// "data":"abc",
// "length":6
// }
// }
// }]
// }
});
```
For more information on the methods and additional options (e.g. revision management, please refer to the documentation).
Example
-------------------------------------------------
This is an example of how to store a video file with an attachment in
local storage. Note that attachments should best be added inside one of the available document callback methods (success & error or callback).
```
<!-- jIO Core -->
<script src="localorcookiestorage.js"></script>
<script src="jio.js"></script>
<!-- Some storage dependencies -->
<script src="jquery.js"></script>
<script src="base64.js"></script>
<script src="sjcl.js"></script>
<script src="sha2.js"></script>
<!-- Some storage -->
<script src="jio.storage.js"></script>
// create a new localStorage
var jio = JIO.newJio({
"type":"local",
"username":"user",
"application_name":"app"
});
// post the document
jio.post(
{
"_id" : "myVideo",
"title" : "My Video",
"videoCodec" : "vorbis",
"language" : "en",
"description" : "Images Compilation"
},
function (err, response) {
if (err) {
alert('Error when posting the document description');
} else {
// if successful, add video attachment (base64 encoded)
jio.putAttachment(
{
"id": "myVideo/video",
"data": Base64(my_video),
"mimetype":"video/ogg"
},
function (err, response) {
if (err) {
alert('Error when attaching the video');
} else {
alert('Video Stored');
}
}
);
}
}
);
```
Storage Locations
-------------------------------------------------
jIO allows to build &quot;storage trees&quot; consisting of connectors to multiple storages (webDav, xWiki, S3, localStorage) and use storage handlers to add features like revision management or indices to a child storage (sub_storage).
+ jquery.js - see http://jquery.com
+ localorcookiestorage.js - is a small library that stores persistent data on local storage even if the browser does not support HTML 5.
+ base64.js - is a small library to encrypt data into base64.
+ sjcl.js - is a powerful library to encrypt/decrypt data.
+ sha2.js - is a small library to hash data.
+ jio.js - is the jIO core.
+ jio.storage.js - is a jIO Storage library that can interact with some remote storage servers.
The jIO API provides 5 main methods:
+ `post` - Creates a new file in the storage
+ `get` - Reads a file from the storage.
+ `put` - Updates a file in the storage.
+ `remove` - Deletes a file from the storage.
+ `allDocs` - Gets a list of existant files.
The following storages are currently supported:
**DummyStorage (custom storage prototype)**
```
var my_jio_instance = jIO.newJio(storagedescription);
my_jio_instance.post (doc[, options][, callback|, success, error]);
my_jio_instance.get (docid[, options][, callback|, success, error]);
my_jio_instance.put (doc[, options][, callback|, success, error]);
my_jio_instance.remove (doc[, options][, callback|, success, error]);
my_jio_instance.allDocs ([options][, callback|, success, error]);
my_jio_instance.stop(); // stops momentarily the job manager
my_jio_instance.start(); // restart the job manager
my_jio_instance.close(); // close this instance
// initialize a dummy storage
var jio = JIO.newJio({
"type": <string>
});
```
Examples:
**LocalStorage (browser local storage)**
```
var jio = jIO.newJio({"type":"local","username":"myname","applicationname":"myappname"});
// jio.get (docid, options, callback)
jio.get ('myfile',{max_retry:3},function (err,val) {
if (err) {
console.error (err);
} else {
console.log (val.content);
}
// initialize a local storage
var jio = JIO.newJio({
"type" : "local",
"username" : <string>,
"application_name" : <string>
});
// jio.put (doc, success, error)
jio.put ({_id:'myotherfile',content:'and his content'},function (val) {
console.log ('success');
},function (err) {
console.error (err);
```
**DAVStorage (connect to webDAV)**
```
// initialize a webDAV storage
var jio = JIO.newJio({
"type" : "dav",
"username" : <string>,
"password" : <string>,
"application_name" : <string>,
"url" : <string>
});
// jio.allDocs (options, success, error)
jio.allDocs ({metadata_only:false},function (val) {
var i;
for (i=0; i < val.total_rows; i++) {
console.log ('Filename: ' + val.rows[i].id);
console.log ('Content: ' + val.rows[i].value.content);
}
}, function (err) {});
```
Where can I store documents?
----------------------------
These are the available storage descriptions provided by jio.storage.js:
- LocalStorage, to manipulate files on browser local storage.
`{"type":"local","username":<string>,"applicationname":<string>}`
- DAVStorage, to manipulate files on a webDAV storage server.
`{"type":"dav","username":<string>,"password":<string>,"applicationname":<string>}`
- ReplicateStorage, to manipulate files on several storage.
`{"type":"replicate","storagelist":[<storagedescription>, ...]}`
- IndexStorage, to index sub storage files.
`{"type":"index","storage":<storagedescription>}`
- CryptStorage, to encrypt/decrypt sub storage files.
`{"type":"crypt","username":<string>,"password":<string>,"storage":<storagedescription>}`
- ConflictManagerStorage, to manage sub storage files revision and conflicts.
`{"type":"conflictmanager","storage":<storagedescription>}`
For developers
==============
Quick start
-----------
+ **Clone repository** `git clone http://git.erp5.org/repos/jio.git`. Sources are there: `${repo}/src/`.
+ **Build** - Go to `${repo}/grunt/`, and you can execute the script `gruntall` or build everycomponent manually with `make`.
+ **Dependencies** - [Grunt](https://github.com/cowboy/grunt) - [JSHint](https://github.com/jshint/jshint) - [UglifyJS](https://github.com/mishoo/UglifyJS) - [PhantomJS](http://phantomjs.org)
+ **Tests** - Go to `${repo}/tests/`, and you can open `jiotests_withoutrequirejs.html` from localhost. (Tests with requireJS are not available yet.)
How to design your own jIO Storage Library
-----------------------------------------
jIO basicStorage interface must be inherited by all the new storages. Seven methods must be redesigned: `post, get, put, remove, allDocs, serialized, validateState`
Except 'serialized' and 'validateState', the above methods must end with 'success','retry' or 'error' inherited methods, which can have only one parameter.
This parameter is the job return value, it is very important.
The return value must seams like PouchDB return values.
**xWiki storage (connect to xWiki)**
```
var val = {
ok: <often true>, // true
id: <the file path> // 'file.js'
// You can add your own return values
};
success(val);
var err = {
status: <often http error status>, // 404
statusText: <often http error statusText>, // 'Not Found'
error: <the error name>, // 'not_found'
reason: <short description>, // 'file not found'
message: <description> // 'Cannot retreive file.....'
// You can add your own error values
};
error or retry(err);
// initialize a connection to xWiki storage
coming soon
```
The method 'serialized' is used by jIO to store a serialized version of the storage inside the localStorage in order to be restored by jIO later.
**S3 storage (connect to S3)**
```
var super_serialized = that.serialized;
serialized = function () {
var o = super_serialized();
o.important_info1 = '...';
o.important_info2 = '...';
return o;
};
// initialize a connection to S3 storage
coming soon
```
When jIO try to restore this storage, 'important_info1' and 2 will be given in the storage spec.
**CAUTION**: Don't store confidential informations like passwords!
The method 'validateState' is used by jIO to validate the storage state. For example, if the storage specifications are not correct, this method must return a non-empty string. If all is ok, it must return an empty string.
**IndexStorage (maintains indices of documents in a substorage)**
```
validate = function () {
if (spec.important_info1) {
return '';
}
return 'Where is my important information ??';
};
// initialize an indexStorage (for a local storage)
var jio = JIO.newJio({
"type": "indexed",
"sub_storage": {
"type": "local",
"username": <string>,
"application_name": <string>
},
// create two indices for the substorage with fields A and A,B
"indices": [
{"name":<string>, "fields":[<string A>]},
{"name":<string>, "fields":[<string A>, <string B>]}
],
// pass the field type into the index</span>
"field_types": {
<string A>: "string",
<string B>: "number"
}
});
```
The storage created, you must add the storage type to jIO.
jIO.addStorageType() require two parameters: the storage type (string) add a constructor (function). `jIO.addStorageType('mystoragetype', myConstructor);`
To see what this can look like, see [Code sample](#code-sample).
Error status
------------
* 0: Unknown Error
* >9 & <20: Job Errors
* 10: Stopped, The Job has been stopped by adding another one
* 11: Not Accepted, The added Job cannot be accepted
* 12: Replaced, The Job has been replaced by another one
* >19 & <30: Command Errors
* 20: Id Required, The Command needs a document id
* 21: Content Required, The Command needs a document content
* >29: Storage Errors
* >99: HTTP Errors
Job rules
---------
jIO job manager will follow several rules set at the creation of a new jIO instance. When you try to do a command, jIO will create a job and will make sure the job is really necessary. Thanks to job rules, jIO knows what to do with the new job before adding it to the queue.
You can add your own rules like this:
**CryptStorage (encrypt/decrypt substorage files)**
```
var jio = jIO.newJio(<storagedescription>);
var jio_rules = jio.getJobRules();
// When a 'put' job is on going (true), and we add a 'get' job,
// then the 'get' job must wait for the end of the 'put' job.
jio_rules.addActionRule('put', true /* on going */, 'get', jio_rules.wait);
// initialize a cryptStorage (to encrypt data on a storage)
coming soon
```
+ `wait` - wait until the end of the current job
+ `update` - replace the current job by this one
+ `eliminate` - eliminate the current job, and add the new one
+ `dontAccept` - the new job cannot be accepted
+ `none` - simply add the new job to the job queue
You can make special rules like this:
**Revision Storage (add revision management to a substorage)**
```
var putput = function(job1,job2){
if (job1.getCommand().getDocInfo('content') ===
job2.getCommand().getDocInfo('content')) {
return jio_rules.dontAccept();
} else {
return jio_rules.wait();
}
};
jio_rules.addActionRule('put', true, 'put', putput);
// initialize a revison storage on a local storage
// (revision-format 1-9ccd039de0674d935f3c6bae61afc9b7038d1df97d586507aa62336a02f9ee2a)
var jio = JIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": <string>,
"application_name": <string>
}
});
```
**Default rules**:
**Replicate Revision Storage (replicate documents across multiple storages)**
```
var putput = function(job1,job2){
if (job1.getCommand().getDocInfo('content') ===
job2.getCommand().getDocInfo('content')) {
return jio_rules.dontAccept();
} else {
return jio_rules.wait();
// initialize a replicate revision storage (with local, webDAV as substorages)
var jio = JIO.newJio({
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": <string>,
"application_name": <string>
}
};
jio_rules.addActionRule('post',true ,'post', putput);
jio_rules.addActionRule('post',true ,'put', putput);
jio_rules.addActionRule('post',true ,'get', jio_rules.wait);
jio_rules.addActionRule('post',true ,'remove',jio_rules.wait);
jio_rules.addActionRule('post',false,'post', jio_rules.update);
jio_rules.addActionRule('post',false,'put', jio_rules.update);
jio_rules.addActionRule('post',false,'get', jio_rules.wait);
jio_rules.addActionRule('post',false,'remove',jio_rules.eliminate);
jio_rules.addActionRule('put',true ,'post', putput);
jio_rules.addActionRule('put',true ,'put', putput);
jio_rules.addActionRule('put',true ,'get', jio_rules.wait);
jio_rules.addActionRule('put',true ,'remove',jio_rules.wait);
jio_rules.addActionRule('put',false,'post', jio_rules.update);
jio_rules.addActionRule('put',false,'put', jio_rules.update);
jio_rules.addActionRule('put',false,'get', jio_rules.wait);
jio_rules.addActionRule('put',false,'remove',jio_rules.eliminate);
jio_rules.addActionRule('get',true ,'post', jio_rules.wait);
jio_rules.addActionRule('get',true ,'put', jio_rules.wait);
jio_rules.addActionRule('get',true ,'get', jio_rules.dontAccept);
jio_rules.addActionRule('get',true ,'remove',jio_rules.wait);
jio_rules.addActionRule('get',false,'post', jio_rules.wait);
jio_rules.addActionRule('get',false,'put', jio_rules.wait);
jio_rules.addActionRule('get',false,'get', jio_rules.update);
jio_rules.addActionRule('get',false,'remove',jio_rules.wait);
jio_rules.addActionRule('remove',true ,'get', jio_rules.dontAccept);
jio_rules.addActionRule('remove',true ,'remove',jio_rules.dontAccept);
jio_rules.addActionRule('remove',false,'post', jio_rules.eliminate);
jio_rules.addActionRule('remove',false,'put', jio_rules.eliminate);
jio_rules.addActionRule('remove',false,'get', jio_rules.dontAccept);
jio_rules.addActionRule('remove',false,'remove',jio_rules.update);
jio_rules.addActionRule('allDocs',true ,'allDocs',jio_rules.dontAccept);
jio_rules.addActionRule('allDocs',false,'allDocs',jio_rules.update);
},{
"type": "revision",
"sub_storage": {
"type" : "dav",
"username" : <string>,
"password" : <string>,
"application_name" : <string>,
"url" : <string>
}
}]
});
```
For more information on the specific storages including guidelines on how to create your own connector, please refer to the documentation.
Code sample
-----------
Complex Queries
-------------------------------------------------
jIO includes a complex-queries manager, which can be run on top of the
<em>allDocs()</em> method to query documents in the storage tree. A
sample query would look like this (note, that <em>allDocs</em> and complex queries cannot be run on every storage and that pre-querying of documents on distant storages should best be done server-side):
Storage example:
```
(function () {
var newLittleStorage = function ( spec, my ) {
var that = my.basicStorage ( spec, my );
var super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.firstname = spec.firstname;
o.lastname = spec.lastname;
return o;
};
that.validateState = function () {
if (spec.firstname && spec.lastname) {
return '';
}
return 'This storage needs your firstname and your lastname.';
};
// run allDocs with query option on an existing jIO
jio.allDocs({
"query":{
"query":'(fieldX: >= <string> AND fieldY: < <string>)',
"filter": {
// records to display ("from to")
"limit":[0,5],
// sort by
"sort_on":[[<string A>,'descending']],
// fields to return in response
"select_list":[<string A>;,<string B>]
},
"wildcard_character":'%'
}
},function(err, response){
// console.log(response):
// [{
// "id": <string>,
// <string A>: <string>,
// <string B>: <string>
// }]
}
});
```
Task Management
-------------------------------------------------
jIO is running a task queue manager in the background which processes
incoming tasks according to set of defined rules. To find out
more and including how to define your own execution rules, please refer to the documentation.
that.post = function (command) {
// [code]
that.success({ok:true,id:command.getDocId()});
};
Conflict Management
-------------------------------------------------
As jIO allows to manage and share documents across multiple storage
locactions it is likely for conflicts to occur (= multiple versions of a single document existing in the storage tree). jIO manages conflicts by ensuring that every version of a document is available on every storage and that conflicts are accessible (and solvable) using the <em><u>conflicts:true</u></em> option when using the respective jIO methods. For more info on conflicts and available options, please refer to the documentation.
that.put = function (command) {
// [code]
that.success({ok:true,id:command.getDocId()});
};
Crash-Proof
-------------------------------------------------
All tasks are managed inside the browser local storage so no data is lost, as the task manager queue will persist through browser crashes and continues to run when the page is reloaded after a browser crash.
that.get = function (command) {
// example with jQuery
jQuery.ajax ( {
url: 'www.google.com',
type: "GET",
async: true,
success: function (content) {
that.success({
_id:command.getDocId(),content:content,
_last_modified:123,_creation_date:12
});
},
error: function (type) {
type.reason = 'error occured';
type.message = type.reason + '.';
type.error = type.statusText;
that.error(type);
}
} );
};
Authors
-------------------------------------------------
+ Francois Billioud
+ Tristan Cavelier
that.allDocs = function (command) {
// [code]
if (!can_I_reach_the_internet) {
// Oh, I can't reach the internet...
that.retry({
status:0,error:'unknown_error',
statusText:'Unknown Error',
reason:'network_not_reachable',
message:'Impossible to reach the internet.'
});
} else {
// Oh, I can't retreive any files..
that.error({
status:403,error:'forbidden',
statusText:'Forbidden',
reason:'unable to get all docs',
message:'This storage is not able to retreive anything.'
});
}
};
Copyright and license
-------------------------------------------------
jIO is an open-source library and is licensed under the LGPL license. More information on LGPL can be found <a href="http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License">here</a>.
that.remove = function (command) {
// [code]
that.success({ok:true,id:command.getDocId()});
};
Documentation
=============
You can find the full documentation here: [jIO Documentation](http://www.j-io.org/documentation).
return that;
};
For developers
==============
Quick start
-------------------------------------------------
To get started with jIO, clone one of the repositories on
<a href="http://git.erp5.org/gitweb/jio.git">git.erp5.com</a>,
<a href="https://github.com/nexedi/jio">Github</a> or
<a href="https://gitorious.org/nexedi/jio">Gitorious</a>.
jIO.addStorageType ('little', newLittleStorage);
}());
```
jIO uses a <a href="http://git.erp5.org/gitweb/jio.git/blob_plain/HEAD:/Makefile?js=1">makeFile</a> to build and compress the necessary files (jIO.js and complex-queries.js). To run the makeFile you will require the following:
Authors
=======
+ [NodeJS](http://nodejs.org/)(including NPM)
+ [JSLint](https://github.com/jslint/jslint)
+ [UglifyJS](https://github.com/mishoo/UglifyJS)
+ [Rhino](https://developer.mozilla.org/fr/docs/Rhino) (for compiling JSCC)
+ Francois Billioud
+ Tristan Cavelier
The repository also includes the built ready-to-use files, so in case you do not want to build jIO yourself, just use <em>jio.min.js</em> as well as <em>complex-queries.min.js</em> plus the storages and dependencies you need and you will be good to go.
Copyright and license
=====================
You can also check out the jIO QUnit tests (jiotests_withoutrequirejs.html) for an overview on how to create a page
[setup](http://git.erp5.org/gitweb/jio.git/blob/HEAD:/test/jiotests_withoutrequirejs.html?js=1) with required scripts as well as setting up jIO itself
[setup](http://git.erp5.org/gitweb/jio.git/blob/HEAD:/test/jiotests.js?js=1). If you want to run the QUnit tests
locally after cloning the repo, please make sure you have the above minified files in your repository.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment