Skip to content
Snippets Groups Projects
Commit d5e55b69 authored by mcmlxxix's avatar mcmlxxix
Browse files

remove clone function (no longer needed), reject root object requests, no...

remove clone function (no longer needed), reject root object requests, no longer self-instantiate, bundle LOCK/operation/UNLOCK requests when a lock is specified on an operation
parent 396d041c
No related branches found
No related tags found
No related merge requests found
...@@ -27,12 +27,25 @@ ...@@ -27,12 +27,25 @@
*/ */
if(!this.Database) { function JSONdb (fileName) {
Database = new (function() {
this.VERSION = "$Revision$".split(' ')[1]; 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={ this.settings={
/* record lock constants, incremental (do not change the order or value) */ /* record lock constants, incremental (do not change the order or value) */
...@@ -57,76 +70,6 @@ Database = new (function() { ...@@ -57,76 +70,6 @@ Database = new (function() {
ERROR_DUPLICATE_LOCK:5 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 ****************************/ /*************************** database methods ****************************/
/* subscribe a client to an object */ /* subscribe a client to an object */
this.subscribe = function(client,record) { this.subscribe = function(client,record) {
...@@ -211,7 +154,7 @@ Database = new (function() { ...@@ -211,7 +154,7 @@ Database = new (function() {
if(client_lock) { if(client_lock) {
/* if this was a write lock, send an update to all record subscribers */ /* if this was a write lock, send an update to all record subscribers */
if(client_lock.type == this.settings.LOCK_WRITE) if(client_lock.type == this.settings.LOCK_WRITE)
send_updates(record); send_updates(client,record);
delete record.shadow[record.child_name]._lock[client.id]; delete record.shadow[record.child_name]._lock[client.id];
return true; return true;
} }
...@@ -229,8 +172,7 @@ Database = new (function() { ...@@ -229,8 +172,7 @@ Database = new (function() {
this.read = function(client,record) { this.read = function(client,record) {
/* if this client has this record locked, read */ /* if this client has this record locked, read */
if(record.info.lock[client.id]) { if(record.info.lock[client.id]) {
var data = clone(record.data[record.child_name]); send_packet(client,record.data[record.child_name],"RESPONSE");
send_packet(client,data,"RESPONSE");
return true; return true;
} }
/* if there is no lock for this client, error */ /* if there is no lock for this client, error */
...@@ -298,24 +240,33 @@ Database = new (function() { ...@@ -298,24 +240,33 @@ Database = new (function() {
var parent_name = query.location.substring(0,query.location.lastIndexOf(".")); var parent_name = query.location.substring(0,query.location.lastIndexOf("."));
/* store the child name */ /* store the child name */
var child_name = query.location.substr(query.location.lastIndexOf(".")+1); 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 */ /* temporary array for queue additions */
var q=[]; var q=[];
/* if an operation is requested */ /* if an operation is requested */
if(query.operation !== undefined) { if(query.operation !== undefined) {
request = new Request(client,query.operation,parent_name,child_name,query.data); 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()) */; /* push this query into a queue to be processed at the next response cycle (this.cycle()) */;
q.push(request); q.push(request);
} }
/* if there is an attached lock operation, process accordingly */ /* if there is an attached lock operation, process accordingly */
if(query.lock !== undefined) { if(query.lock !== undefined) {
request = new Request(client,"LOCK",parent_name,child_name,query.lock); /* put lock ahead of the operation in request queue */
/* if this is a read or write lock, put it ahead of the operation in the request queue */ q.unshift(new Request(
if(query.lock == this.settings.LOCK_UNLOCK) client,"LOCK",parent_name,child_name,query.lock
q.unshift(request); ));
/* if this is an unlock, process it after the operation in the request queue */ /* put unlock after the operation in the request queue */
else if(query.lock == this.settings.LOCK_READ || query.lock == this.settings.LOCK_WRITE) q.push(new Request(
q.push(request); client,"LOCK",parent_name,child_name,this.settings.LOCK_UNLOCK
));
} }
/* add the temporary queue to the main queue */ /* add the temporary queue to the main queue */
this.queue=this.queue.concat(q); this.queue=this.queue.concat(q);
...@@ -413,7 +364,11 @@ Database = new (function() { ...@@ -413,7 +364,11 @@ Database = new (function() {
var result=false; var result=false;
/* locate the requested record within the database */ /* 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) { if(!record) {
log(LOG_DEBUG,"db: bad request removed from queue"); log(LOG_DEBUG,"db: bad request removed from queue");
...@@ -464,6 +419,53 @@ Database = new (function() { ...@@ -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 ****************************/ /*************************** database functions ****************************/
/* traverse object and create a shadow copy of the object structure /* traverse object and create a shadow copy of the object structure
for record locking and subscribers, and create location names for database objects */ for record locking and subscribers, and create location names for database objects */
...@@ -490,12 +492,6 @@ Database = new (function() { ...@@ -490,12 +492,6 @@ Database = new (function() {
function identify_remains(client,parent_name,child_name) { function identify_remains(client,parent_name,child_name) {
var p=parent_name.split(/\./); 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 data=this.data;
var shadow=this.shadow; var shadow=this.shadow;
var info={ var info={
...@@ -560,12 +556,6 @@ Database = new (function() { ...@@ -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 */ /* return the prevailing lock type and pending lock status for an object */
function investigate(shadow, info) { function investigate(shadow, info) {
/* if we havent found a write locked record yet, keep searching */ /* if we havent found a write locked record yet, keep searching */
...@@ -596,8 +586,11 @@ Database = new (function() { ...@@ -596,8 +586,11 @@ Database = new (function() {
} }
/* send updates of this object to all subscribers */ /* 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) { for each(var c in record.info.subscribers) {
/* do not send updates to request originator */
if(c.id == client.id)
continue;
var data = { var data = {
location:record.parent_name + "." + record.child_name, location:record.parent_name + "." + record.child_name,
data:record.data[record.child_name] data:record.data[record.child_name]
...@@ -617,9 +610,7 @@ Database = new (function() { ...@@ -617,9 +610,7 @@ Database = new (function() {
/* constructor */ /* constructor */
this.init(); this.init();
})(); };
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment