// pdu.js // protocol data unit // manage a network string // such that updates reduce bandwidth usage // can take apart a string // and put it back together function PDU(name) { // public this.update=function(socket, msg, k, sk) { console.log('PDU::update - undefined update function, new msg:', msg, 'key', k, 'subkey', sk) } this.buildPacketString=function(socket, msg, k, sk) { console.log('PDU::buildPacketString - undefined update function, new msg:', msg, 'key', k, 'subkey', sk) } this.getSubscribers=function(data, cb) { console.log('PDU::router - undefined router function, update to:', data.key, '=', data.val) cb([]) // returns a list of objects } // optional this.maxBytesPerSec=1024 // private this.name=name this.timer=null this.store={} this.state={} this.previousCommands={} // debug // this.activeSockets=[] // bandwidth resets hard on 1s var ref=this this.timerFunc=function() { var start=Date.now() //console.log('megud:class.pdu.js:::PDU::this.timer - ', ref.activeSockets.length) for(var i in ref.activeSockets) { var socket=ref.activeSockets[i] // reset bytes used, we're on 1sec timer if (socket.pduBytesUsed) { //console.log('megud:class.pdu.js:::PDU::this.timer - sending data, remaining', socket.pduBytesUsed, 'sending', ref.maxBytesPerSec) socket.pduBytesUsed-=ref.maxBytesPerSec if (socket.pduBytesUsed<0) socket.pduBytesUsed=0 } } var diff=Date.now()-start if (diff>1000) { // could cancel and reinterval at X*2 console.log('PDU::timer - took than 1 sec', diff, 'ms') } ref.dispatch() } //this.timer=setInterval(this.timerFunc, 1000) this.timer=null // examine socket's usage // is it time to send things to this socket // will next packet fit the bill // send and track it // if queue is empty remove active socket this.dispatch=function() { //console.log('PDU::dispatch, start') // maybe put limiter here var ref=this var start=Date.now() //console.log('PDU::dispatch - activeSockets', ref.activeSockets.length) var activeDataSockets=0 for(var i in ref.activeSockets) { var socket=ref.activeSockets[i] for(var k in socket.pduData) { // does this socket have changes? if (typeof(socket.pduLast[k])=='undefined' || socket.pduLast[k]!=socket.pduChanges[k]) { if (socket.pduLastData[k]===undefined) socket.pduLastData[k]='' //console.log('spliting', socket.pduData, 'vs', socket.pduLastData) var start=Date.now() var op=ref.split(socket.pduData[k], socket.pduLastData[k]) var diff=Date.now()-start // if the res.ops > set.op use set.op //console.log('op', res, 'took', diff) // we can't fusion last packet with new first // because we wont know the locality of the last change // since we scan left to right (and edit could be on the left) // push to queue if (socket.pduQueue===undefined) socket.pduQueue=[] op.k=k if (socket.pduSubKey) { op.sk=socket.pduSubKey[k] } socket.pduQueue.push(op) // mark as sent socket.pduLastData[k]=socket.pduData[k] socket.pduLast[k]=socket.pduChanges[k] } } if (socket.pduBytesUsed===undefined) socket.pduBytesUsed=0 //console.log('PDU::dispatch, socket queue is', socket.pduQueue.length) //console.log('PDU::dispatch socket bytes used', socket.pduBytesUsed, '/', ref.maxBytesPerSec) // send/track what we can from the queue while(socket.pduQueue.length && socket.pduBytesUsed1000) { console.log('pdu::dispatch took', diff, 'ms') } } // this.split=function(str1, str2, m, n) { if (!str1 && str2) { // delete all return { t: 'da' } } if (!str2 && str1) { // insert all return { t: 'ia', s: str1} } if (str1===str2) return {} if (m===undefined) m=str1.length if (n===undefined) n=str2.length // sort var a=str1, b=str2 if (m > n) { var tmp = a a = b b = tmp } //console.log('a', a, 'b', b) var la = a.length var lb = b.length // if the shortest string has chars left // from the right, look for different chars while (la > 0 && (a.charCodeAt(la - 1) === b.charCodeAt(lb - 1))) { la-- lb-- } //console.log('la', la, 'lb', lb) var ola=la var olb=lb var offset = 0 // from the left, look for different chars while (offset < la && (a.charCodeAt(offset) === b.charCodeAt(offset))) { offset++ } //console.log('offset', offset) la -= offset lb -= offset if (la === 0 || lb === 1) { // 1 or more chars can change here //console.log('changes', lb, 'o', ola, olb) // deletion or insertion // usually at the end of str2 // or beginning of str1 var obj={ t: '?' } if (lb>m || lb>n) { //console.log('lb', lb, 'larger than', m, 'or', n) var tlb1=Math.min(m, lb) var tlb2=Math.min(n, lb) var sm=Math.min(tlb1, tlb2) //console.log('sm', sm) //console.log(str1.substr(0, sm), '==', str2.substr(0, sm)) var leftSame=str1.substr(0, sm)===str2.substr(0, sm) //console.log(str1.substr(str1.length-sm), '==', str2.substr(str2.length-sm)) var rightSame=str1.substr(str1.length-sm)===str2.substr(str2.length-sm) } else { //console.log(str1.substr(0, lb), '==', str2.substr(0, lb)) var leftSame=str1.substr(0, lb)===str2.substr(0, lb) //console.log(str1.substr(str1.length-lb), '==', str2.substr(str2.length-lb)) var rightSame=str1.substr(str1.length-lb)===str2.substr(str2.length-lb) } //console.log('leftSame', leftSame, 'rightSame', rightSame) if (leftSame && rightSame) { //console.log('left and right by', lb, 'are same', la, 'o', ola, olb) // grabbing too many //console.log('from', offset, 'to', str1.length-offset) //console.log('from', offset, 'to', str2.length-offset) // at least one char if (m>n) { // obj={ t: 'i', p: offset, s: str1.substr(offset, lb) } } else if (mn) { obj={ t: 'ie', s: str1.substring(n) } } else if (mn) { obj={ t: 'is', s: str1.substr(0, lb) } } else if (mn) { obj={ t: 'is', s: str1.substr(0, lb) } } else if (m