diff --git a/packages/livedata/livedata_client.js b/packages/livedata/livedata_client.js index 740991e4fa..e331e07068 100644 --- a/packages/livedata/livedata_client.js +++ b/packages/livedata/livedata_client.js @@ -91,7 +91,7 @@ Sky = window.Sky || {}; // XXX mutates the object passed in. that is not cool. if (obj._id) console.log("WARNING: trying to insert object w/ _id set"); - var _id = Sky.genId(); + var _id = Collection.uuid(); obj._id = _id; if (this._name) @@ -161,9 +161,6 @@ Sky = window.Sky || {}; }; _.extend(Sky, { - // XXX don't get this out of minimongo.. - genId: Collection._genId, - is_server: false, is_client: true, @@ -189,7 +186,7 @@ Sky = window.Sky || {}; } else { // new sub, add object. // generate our own id so we can know it w/ a find afterwards. - id = Sky.genId(); + id = Collection.uuid(); subs.insert({_id: id, name: name, args: args, count: 1}); sub_ready_callbacks[id] = []; diff --git a/packages/livedata/livedata_server.js b/packages/livedata/livedata_server.js index bf81402793..aaa86f93ef 100644 --- a/packages/livedata/livedata_server.js +++ b/packages/livedata/livedata_server.js @@ -103,25 +103,6 @@ _.extend(Sky, { is_server: true, is_client: false, - /** - * Returns a unique identifier as a string. - * - * XXX copied from minimongo/genid.js - */ - _genId_counter:0, // XXX namespace pollution - genId: function () { - var key = (Sky._genId_counter++) + "#"; - key += (new Date()).getTime() + "#"; - key += Math.random() + "#"; - key += Math.random() + "#"; - key += Math.random() + "#"; - // XXX XXX eliminate require (easy, in this case..) - var md5 = __skybreak_bootstrap__.require('crypto').createHash('md5'); - md5.update(key); - var id = md5.digest('hex'); - return id; - }, - /** * Defines a live dataset that clients can subscribe to. * @@ -201,7 +182,7 @@ Sky.Collection = function (name) { new_doc = {}; _.extend(new_doc, doc); doc = new_doc; - doc._id = Sky.genId(); + doc._id = Sky.uuid(); } Sky._mongo_driver.insert(this._name, doc); diff --git a/packages/livedata/package.js b/packages/livedata/package.js index e442cf8ea6..16d116102f 100644 --- a/packages/livedata/package.js +++ b/packages/livedata/package.js @@ -24,5 +24,6 @@ Package.client_file('livedata_client.js'); // out of everyone? Package.server_file('../../app/lib/third/underscore.js'); +Package.server_file('uuid.js'); Package.server_file('livedata_server.js'); Package.server_file('mongo_driver.js'); diff --git a/packages/livedata/uuid.js b/packages/livedata/uuid.js new file mode 100644 index 0000000000..ac9e69c33a --- /dev/null +++ b/packages/livedata/uuid.js @@ -0,0 +1,122 @@ +// XXX dups packages/minimongo/uuid.js + +// Sky.random() -- known good PRNG, replaces Math.random() +// Sky.uuid() -- returns RFC 4122 v4 UUID. + +// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript +// for a full discussion and Alea implementation. + +// Copyright (C) 2010 by Johannes Baagøe +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +Sky = global.Sky || {}; + +Sky._Alea = function () { + function Mash() { + var n = 0xefc8249d; + + var mash = function(data) { + data = data.toString(); + for (var i = 0; i < data.length; i++) { + n += data.charCodeAt(i); + var h = 0.02519603282416938 * n; + n = h >>> 0; + h -= n; + h *= n; + n = h >>> 0; + h -= n; + n += h * 0x100000000; // 2^32 + } + return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 + }; + + mash.version = 'Mash 0.9'; + return mash; + } + + return (function (args) { + var s0 = 0; + var s1 = 0; + var s2 = 0; + var c = 1; + + if (args.length == 0) { + args = [+new Date]; + } + var mash = Mash(); + s0 = mash(' '); + s1 = mash(' '); + s2 = mash(' '); + + for (var i = 0; i < args.length; i++) { + s0 -= mash(args[i]); + if (s0 < 0) { + s0 += 1; + } + s1 -= mash(args[i]); + if (s1 < 0) { + s1 += 1; + } + s2 -= mash(args[i]); + if (s2 < 0) { + s2 += 1; + } + } + mash = null; + + var random = function() { + var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 + s0 = s1; + s1 = s2; + return s2 = t - (c = t | 0); + }; + random.uint32 = function() { + return random() * 0x100000000; // 2^32 + }; + random.fract53 = function() { + return random() + + (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 + }; + random.version = 'Alea 0.9'; + random.args = args; + return random; + + } (Array.prototype.slice.call(arguments))); +} + +// instantiate RNG. use the default seed, which is current time. +Sky.random = new Sky._Alea(); + +// RFC 4122 v4 UUID. +Sky.uuid = function () { + var s = []; + var hexDigits = "0123456789abcdef"; + for (var i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Sky.random() * 0x10), 1); + } + s[14] = "4"; + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); + s[8] = s[13] = s[18] = s[23] = "-"; + + var uuid = s.join(""); + return uuid; +} diff --git a/packages/minimongo/genid.js b/packages/minimongo/genid.js deleted file mode 100644 index 4e0e9f007a..0000000000 --- a/packages/minimongo/genid.js +++ /dev/null @@ -1,232 +0,0 @@ -/// Return an id that is likely to be universally unique. This is -/// definitely not the way to get a compact id, but it'll do for now. -/// -/// XXX find a way to generate more compact ids. either have the -/// client generate temporary ids and keep an alias table for the -/// duration of the session (based on the actual id the server -/// picked), or have the server allocate blocks of id space to us -/// -/// XXX probably needs to be nuked from orbit for minimongo -/// -/// XXX this code is linked to from Sky.genId on the client, and copied -/// to sky_server.js for the server. -Collection._genId_counter = 0; -Collection._genId = function () { - var key = (Collection._genId_counter++) + "#"; - key += (new Date()).getTime() + "#"; - key += Math.random() + "#"; - key += Math.random() + "#"; - key += Math.random() + "#"; - var id = Collection._MD5(key); - return id; -}; - -/////////////////////////////////////////////////////////////////////////////// - -/** -* -* MD5 (Message-Digest Algorithm) -* http://www.webtoolkit.info/ -* -**/ - -Collection._MD5 = function (string) { - - function RotateLeft(lValue, iShiftBits) { - return (lValue<>>(32-iShiftBits)); - } - - function AddUnsigned(lX,lY) { - var lX4,lY4,lX8,lY8,lResult; - lX8 = (lX & 0x80000000); - lY8 = (lY & 0x80000000); - lX4 = (lX & 0x40000000); - lY4 = (lY & 0x40000000); - lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF); - if (lX4 & lY4) { - return (lResult ^ 0x80000000 ^ lX8 ^ lY8); - } - if (lX4 | lY4) { - if (lResult & 0x40000000) { - return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); - } else { - return (lResult ^ 0x40000000 ^ lX8 ^ lY8); - } - } else { - return (lResult ^ lX8 ^ lY8); - } - } - - function F(x,y,z) { return (x & y) | ((~x) & z); } - function G(x,y,z) { return (x & z) | (y & (~z)); } - function H(x,y,z) { return (x ^ y ^ z); } - function I(x,y,z) { return (y ^ (x | (~z))); } - - function FF(a,b,c,d,x,s,ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - }; - - function GG(a,b,c,d,x,s,ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - }; - - function HH(a,b,c,d,x,s,ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - }; - - function II(a,b,c,d,x,s,ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - }; - - function ConvertToWordArray(string) { - var lWordCount; - var lMessageLength = string.length; - var lNumberOfWords_temp1=lMessageLength + 8; - var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64; - var lNumberOfWords = (lNumberOfWords_temp2+1)*16; - var lWordArray=Array(lNumberOfWords-1); - var lBytePosition = 0; - var lByteCount = 0; - while ( lByteCount < lMessageLength ) { - lWordCount = (lByteCount-(lByteCount % 4))/4; - lBytePosition = (lByteCount % 4)*8; - lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<>>29; - return lWordArray; - }; - - function WordToHex(lValue) { - var WordToHexValue="",WordToHexValue_temp="",lByte,lCount; - for (lCount = 0;lCount<=3;lCount++) { - lByte = (lValue>>>(lCount*8)) & 255; - WordToHexValue_temp = "0" + lByte.toString(16); - WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2); - } - return WordToHexValue; - }; - - function Utf8Encode(string) { - string = string.replace(/\r\n/g,"\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } - else if((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } - else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } - - } - - return utftext; - }; - - var x=Array(); - var k,AA,BB,CC,DD,a,b,c,d; - var S11=7, S12=12, S13=17, S14=22; - var S21=5, S22=9 , S23=14, S24=20; - var S31=4, S32=11, S33=16, S34=23; - var S41=6, S42=10, S43=15, S44=21; - - string = Utf8Encode(string); - - x = ConvertToWordArray(string); - - a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; - - for (k=0;k +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +Collection._Alea = function () { + function Mash() { + var n = 0xefc8249d; + + var mash = function(data) { + data = data.toString(); + for (var i = 0; i < data.length; i++) { + n += data.charCodeAt(i); + var h = 0.02519603282416938 * n; + n = h >>> 0; + h -= n; + h *= n; + n = h >>> 0; + h -= n; + n += h * 0x100000000; // 2^32 + } + return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 + }; + + mash.version = 'Mash 0.9'; + return mash; + } + + return (function (args) { + var s0 = 0; + var s1 = 0; + var s2 = 0; + var c = 1; + + if (args.length == 0) { + args = [+new Date]; + } + var mash = Mash(); + s0 = mash(' '); + s1 = mash(' '); + s2 = mash(' '); + + for (var i = 0; i < args.length; i++) { + s0 -= mash(args[i]); + if (s0 < 0) { + s0 += 1; + } + s1 -= mash(args[i]); + if (s1 < 0) { + s1 += 1; + } + s2 -= mash(args[i]); + if (s2 < 0) { + s2 += 1; + } + } + mash = null; + + var random = function() { + var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 + s0 = s1; + s1 = s2; + return s2 = t - (c = t | 0); + }; + random.uint32 = function() { + return random() * 0x100000000; // 2^32 + }; + random.fract53 = function() { + return random() + + (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 + }; + random.version = 'Alea 0.9'; + random.args = args; + return random; + + } (Array.prototype.slice.call(arguments))); +} + +// instantiate RNG. use the default seed, which is current time. +Collection.random = new Collection._Alea(); + +// RFC 4122 v4 UUID. +Collection.uuid = function () { + var s = []; + var hexDigits = "0123456789abcdef"; + for (var i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Collection.random() * 0x10), 1); + } + s[14] = "4"; + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); + s[8] = s[13] = s[18] = s[23] = "-"; + + var uuid = s.join(""); + return uuid; +}