diff --git a/exec/load/json-db.js b/exec/load/json-db.js index e35c7d56bfb1500609cebdfeb4e9945983084e46..52b10b64af06af93bd8e7806d8e6c2b500b67528 100644 --- a/exec/load/json-db.js +++ b/exec/load/json-db.js @@ -27,12 +27,25 @@ */ -if(!this.Database) { - -Database = new (function() { - +function JSONdb (fileName) { this.VERSION = "$Revision$".split(' ')[1]; + + /* database storage file */ + if(fileName) + this.file=new File(fileName); + else + this.file=undefined; + + /* master database object */ + this.data={}; + /* database record subscription and locking object */ + this.shadow={}; + + /* queued array of data requests (get/put/create/delete) */ + this.queue=[]; + + /* database settings */ this.settings={ /* record lock constants, incremental (do not change the order or value) */ @@ -57,76 +70,6 @@ Database = new (function() { ERROR_DUPLICATE_LOCK:5 }; - /**************************** database objects *****************************/ - /* locking object generated by Database.lock() method - contains the type of lock requested, and the time at which the request came in - TODO: possibly "expire" unfulfilled lock requests after a certain period */ - function Lock(lock_type,timestamp) { - this.type=lock_type; - this.timestamp=timestamp; - } - - /* error object containing a description of the error */ - function Error(error_num,error_desc) { - this.operation="ERROR"; - this.error_num=error_num; - this.error_desc=error_desc; - } - - /* shadow properties generated by composite_sketch() - contains a relative object's subscribers, locks, and child name */ - function Shadow() { - this._lock=[]; - this._lock_pending=false; - this._subscribers=[]; - } - - /* record object returned by identify_remains() - contains the requested object, its shadow object, - the prevailing lock state of that object (affected by parents/children), - and a list of subscribers associated with that object or its parents */ - function Record(data,shadow,parent_name,child_name,info) { - this.data=data; - this.shadow=shadow; - this.parent_name=parent_name; - this.child_name=child_name; - this.info=info; - } - - /* request object generated by Database.queue() method - contains the requested object parent, the specific child property requested, - data (in the case of a PUT operation ) */ - function Request(client,operation,parent_name,child_name,data) { - this.client=client; - this.operation=operation; - this.parent_name=parent_name; - this.child_name=child_name; - this.data=data; - } - - /* in the event of a corrupt JSON object or database problem, - it would be beneficial to be able to single-out the affected - module for correction, rather than destroy the entire database - - it would also allow for a much simpler mechanism for removing - games you no longer wish to host (simply delete the db file and edit your service inis) */ - - /*************************** database data ******************************/ - /* database storage file */ - if(argv[0]) - this.file=new File(argv[0]); - else - this.file=undefined; - - /* master database object */ - this.data={}; - - /* database record subscription and locking object */ - this.shadow={}; - - /* queued array of data requests (get/put/create/delete) */ - this.queue=[]; - /*************************** database methods ****************************/ /* subscribe a client to an object */ this.subscribe = function(client,record) { @@ -211,7 +154,7 @@ Database = new (function() { if(client_lock) { /* if this was a write lock, send an update to all record subscribers */ if(client_lock.type == this.settings.LOCK_WRITE) - send_updates(record); + send_updates(client,record); delete record.shadow[record.child_name]._lock[client.id]; return true; } @@ -229,8 +172,7 @@ Database = new (function() { this.read = function(client,record) { /* if this client has this record locked, read */ if(record.info.lock[client.id]) { - var data = clone(record.data[record.child_name]); - send_packet(client,data,"RESPONSE"); + send_packet(client,record.data[record.child_name],"RESPONSE"); return true; } /* if there is no lock for this client, error */ @@ -298,24 +240,33 @@ Database = new (function() { var parent_name = query.location.substring(0,query.location.lastIndexOf(".")); /* store the child name */ var child_name = query.location.substr(query.location.lastIndexOf(".")+1); + + /* if the data request is invalid or empty, return an error */ + if(!parent_name || !child_name) { + this.error(client,this.settings.ERROR_INVALID_REQUEST); + return false; + } + /* temporary array for queue additions */ var q=[]; - + /* if an operation is requested */ if(query.operation !== undefined) { request = new Request(client,query.operation,parent_name,child_name,query.data); /* push this query into a queue to be processed at the next response cycle (this.cycle()) */; q.push(request); } + /* if there is an attached lock operation, process accordingly */ if(query.lock !== undefined) { - request = new Request(client,"LOCK",parent_name,child_name,query.lock); - /* if this is a read or write lock, put it ahead of the operation in the request queue */ - if(query.lock == this.settings.LOCK_UNLOCK) - q.unshift(request); - /* if this is an unlock, process it after the operation in the request queue */ - else if(query.lock == this.settings.LOCK_READ || query.lock == this.settings.LOCK_WRITE) - q.push(request); + /* put lock ahead of the operation in request queue */ + q.unshift(new Request( + client,"LOCK",parent_name,child_name,query.lock + )); + /* put unlock after the operation in the request queue */ + q.push(new Request( + client,"LOCK",parent_name,child_name,this.settings.LOCK_UNLOCK + )); } /* add the temporary queue to the main queue */ this.queue=this.queue.concat(q); @@ -413,7 +364,11 @@ Database = new (function() { var result=false; /* locate the requested record within the database */ - var record=identify_remains.call(this,request.client,request.parent_name,request.child_name); + var record=identify_remains.call( + this,request.client,request.parent_name,request.child_name + ); + + log("r: " + record.data.toSource()); if(!record) { log(LOG_DEBUG,"db: bad request removed from queue"); @@ -464,6 +419,53 @@ Database = new (function() { } }; + /**************************** database objects *****************************/ + /* locking object generated by Database.lock() method + contains the type of lock requested, and the time at which the request came in + TODO: possibly "expire" unfulfilled lock requests after a certain period */ + function Lock(lock_type,timestamp) { + this.type=lock_type; + this.timestamp=timestamp; + } + + /* error object containing a description of the error */ + function Error(error_num,error_desc) { + this.operation="ERROR"; + this.error_num=error_num; + this.error_desc=error_desc; + } + + /* shadow properties generated by composite_sketch() + contains a relative object's subscribers, locks, and child name */ + function Shadow() { + this._lock=[]; + this._lock_pending=false; + this._subscribers=[]; + } + + /* record object returned by identify_remains() + contains the requested object, its shadow object, + the prevailing lock state of that object (affected by parents/children), + and a list of subscribers associated with that object or its parents */ + function Record(data,shadow,parent_name,child_name,info) { + this.data=data; + this.shadow=shadow; + this.parent_name=parent_name; + this.child_name=child_name; + this.info=info; + } + + /* request object generated by Database.queue() method + contains the requested object parent, the specific child property requested, + data (in the case of a PUT operation ) */ + function Request(client,operation,parent_name,child_name,data) { + this.client=client; + this.operation=operation; + this.parent_name=parent_name; + this.child_name=child_name; + this.data=data; + } + /*************************** database functions ****************************/ /* traverse object and create a shadow copy of the object structure for record locking and subscribers, and create location names for database objects */ @@ -490,12 +492,6 @@ Database = new (function() { function identify_remains(client,parent_name,child_name) { var p=parent_name.split(/\./); - /* if the data request is invalid or empty, return an error */ - if(!p) { - this.error(client,this.settings.ERROR_INVALID_REQUEST); - return false; - } - var data=this.data; var shadow=this.shadow; var info={ @@ -560,12 +556,6 @@ Database = new (function() { } } - /* make a copy of an object to avoid modifying the original */ - function clone(obj) { - var newobj=eval(obj.toSource()); - return newobj; - } - /* return the prevailing lock type and pending lock status for an object */ function investigate(shadow, info) { /* if we havent found a write locked record yet, keep searching */ @@ -596,8 +586,11 @@ Database = new (function() { } /* send updates of this object to all subscribers */ - function send_updates(record) { + function send_updates(client,record) { for each(var c in record.info.subscribers) { + /* do not send updates to request originator */ + if(c.id == client.id) + continue; var data = { location:record.parent_name + "." + record.child_name, data:record.data[record.child_name] @@ -617,9 +610,7 @@ Database = new (function() { /* constructor */ this.init(); -})(); - -} +};