var profiles = [] var selfID; var selfWebsocket,followingWebSockets = []; var privKey; var following; function userDataStartUp(){ console.log("StartUp"); /*document.getElementById("sendMsgInput").addEventListener("keyup",function(event){ if(event.keyCode === 13){ event.preventDefault(); sendMsg(); } });*/ getDatafromAPI().then(function (result) { console.log(result); getProfilesfromIDB().then(function (result){ profiles = arrayToObject(result); console.log(profiles); sessionStorage.profiles = JSON.stringify(profiles); getSuperNodeListfromIDB().then(function(result){ console.log(result) superNodeList = result; kBucketObj.launchKBucket().then(function(result){ console.log(result) getuserID().then(function(result){ console.log(result); selfID = result; if(superNodeList.includes(selfID)) modSuperNode = true; sessionStorage.privKey = JSON.stringify(encrypt.createShamirsSecretShares(privKey,10,10)); sessionStorage.selfID = selfID; alert(`${selfID}\nWelcome ${profiles[selfID].name}`) initselfWebSocket(); listProfiles(); getFollowinglistFromIDB().then(function(result){ following = result; if(!following.includes(selfID)) following.push(selfID); console.log(following); displayTweetsFromIDB().then(function(result){ connectToAllFollowing(); }).catch(function(error){ console.log(error.message); }) }).catch(function(error){ console.log(error.message); }) }).catch(function (error) { console.log(error.message); }); }).catch(function(error){ console.log(error.message); }); }).catch(function (error) { console.log(error.message); }); }).catch(function (error) { console.log(error.message); }); }).catch(function (error) { console.log(error.message); }); } function storedata(data){ return new Promise( function(resolve, reject) { var idb = indexedDB.open("FLO_Tweet"); idb.onerror = function(event) { console.log("Error in opening IndexedDB!"); }; idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction('profiles', "readwrite").objectStore('profiles'); objectRequest = obs.put(data); objectRequest.onerror = function(event) { reject(Error('Error occured: Unable to store data')); }; objectRequest.onsuccess = function(event) { resolve('Data saved OK'); db.close(); }; }; } ); } function getDatafromAPI(){ return new Promise( function(resolve, reject) { var addr = adminID; var idb = indexedDB.open("FLO_Tweet"); idb.onerror = function(event) { reject("Error in opening IndexedDB!"); }; idb.onupgradeneeded = function(event) { var db = event.target.result; var objectStore0 = event.target.result.createObjectStore("superNodes"); var objectStore1 = db.createObjectStore("profiles",{ keyPath: 'floID' }); objectStore1.createIndex('onionAddr', 'onionAddr', { unique: false }); objectStore1.createIndex('name', 'name', { unique: false }); objectStore1.createIndex('pubKey', 'pubKey', { unique: false }); var objectStore2 = db.createObjectStore("lastTx"); var objectStore3 = db.createObjectStore("tweets",{ keyPath: 'tweetID' }); objectStore3.createIndex('tid', 'tid', { unique: false }); objectStore3.createIndex('floID', 'floID', { unique: false }); objectStore3.createIndex('time', 'time', { unique: false }); objectStore3.createIndex('data', 'data', { unique: false }); var objectStore4 = db.createObjectStore("lastTweet"); var objectStore5 = db.createObjectStore("followers"); var objectStore6 = db.createObjectStore("following"); }; idb.onsuccess = function(event) { var db = event.target.result; //window["wait"] = addrList.length; var lastTx = db.transaction('lastTx', "readwrite").objectStore('lastTx'); //addrList.forEach(function(addr){ console.log(addr); new Promise(function(res,rej){ var lastTxReq = lastTx.get(addr); lastTxReq.onsuccess = function(event){ var lasttx = event.target.result; if(lasttx === undefined){ lasttx = 0; } res(lasttx); } }).then(function(lasttx){ var response = ajax("GET",`api/addrs/${addr}/txs`); var nRequired = JSON.parse(response).totalItems - lasttx; console.log(nRequired); while(true && nRequired){ var response = ajax("GET",`api/addrs/${addr}/txs?from=0&to=${nRequired}`); response = JSON.parse(response); if (nRequired + lasttx != response.totalItems ){ nRequired = response.totalItems - lasttx; continue; } response.items.reverse().forEach(function(tx){ try { if (tx.vin[0].addr == addr){ var data = JSON.parse(tx.floData).FLO_Tweet_SuperNode; if(data !== undefined){ storeSuperNodeData(data).then(function (response) { }).catch(function (error) { console.log(error.message); }); } }else{ var data = JSON.parse(tx.floData).FLO_Tweet; if(data !== undefined){ if(encrypt.getFLOIDfromPubkeyHex(data.pubKey)!=tx.vin[0].addr) throw("PublicKey doesnot match with floID") data = {floID : tx.vin[0].addr, onionAddr : data.onionAddr, name : data.name, pubKey:data.pubKey}; storedata(data).then(function (response) { }).catch(function (error) { console.log(error.message); }); } } } catch (e) { //console.log(e) } }); var obs = db.transaction('lastTx', "readwrite").objectStore('lastTx'); obs.put(response.totalItems,addr); break; } db.close(); resolve('retrived data from API'); }); }; } ); } function storeSuperNodeData(data){ return new Promise( function(resolve, reject) { var idb = indexedDB.open("FLO_Tweet"); idb.onerror = function(event) { reject("Error in opening IndexedDB!"); }; idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction('superNodes', "readwrite").objectStore('superNodes'); if(data.addNodes) for(var i=0; i{ if(result[0].floID == selfID) SuperNode_sendTweetsFromIDB(data.floID,data.tid,data.requestor); }).catch(e => { console.log(e.message); }); }else if(data.newSuperNodeTweet){ kBucketObj.determineClosestSupernode(data.floID).then(result=>{ if(result[0].floID == selfID) storeSuperNodeTweet(data.data,data.tid); }).catch(e => { console.log(e.message); }); } } }catch(error){ console.log(error.message); } } }; selfWebsocket.onerror = function(evt){ console.log(evt); }; } function postTweet(){ var tweetBox = document.getElementById("tweetBox"); var tweet = tweetBox.value; tweetBox.value = ""; var time = (new Date).getTime(); var sign = encrypt.sign(tweet,privKey); var data = JSON.stringify({floID:selfID,time:time,tweet:tweet,sign:sign}); console.log(data); selfWebsocket.send(data); getLastTweetCount(selfID).then(function(result){ sendTweetToSuperNode(data,result+1); }).catch(function(error){ console.log(error.message); }); } function storeTweet(data,tid){ var idb = indexedDB.open("FLO_Tweet"); idb.onerror = function(event) { console.log("Error in opening IndexedDB!"); }; idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction("tweets", "readwrite").objectStore("tweets"); data.tweetID = `${data.time}_${data.floID}`; data.tid = tid; obs.add(data); var obsL = db.transaction("lastTweet", "readwrite").objectStore("lastTweet"); obsL.put(tid,data.floID); db.close(); }; } function sendTweetToSuperNode(data,tid){ kBucketObj.determineClosestSupernode(selfID).then(result=>{ var superNodeWS = new WebSocket("ws://"+profiles[result[0].floID].onionAddr+"/ws"); superNodeWS.onopen = function(ev){ console.log(`Connected to self SuperNode!`); data = JSON.stringify({newSuperNodeTweet:true,floID:selfID,tid:tid,data:data}) console.log(data) superNodeWS.send(data); }; superNodeWS.onerror = function(ev) {console.log(`self SuperNode is offline!`);}; superNodeWS.onclose = function(ev) {console.log(`Disconnected from self SuperNode!`);}; }).catch(e => { console.log(e.message); }); } function getFollowinglistFromIDB(){ return new Promise( function(resolve,reject){ var idb = indexedDB.open("FLO_Tweet"); idb.onerror = function(event) { reject("Error in opening IndexedDB!"); }; idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction("following", "readwrite").objectStore("following"); var getReq = obs.getAllKeys(); getReq.onsuccess = function(event){ resolve(event.target.result); } getReq.onerror = function(event){ reject('Unable to read following list!') } db.close(); }; } ); } function displayTweetsFromIDB(){ return new Promise( function(resolve,reject){ var idb = indexedDB.open("FLO_Tweet"); idb.onerror = function(event) { reject("Error in opening IndexedDB!"); }; idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction("tweets", "readwrite").objectStore("tweets"); var curReq = obs.openCursor(); curReq.onsuccess = function(event) { var cursor = event.target.result; if(cursor) { //console.log(cursor.value) if(cursor.value.floID == selfID || following.includes(cursor.value.floID)) createTweetElement(cursor.value.floID,cursor.value.time,cursor.value.data); cursor.continue(); }else{ resolve("Displayed Tweets from IDB!"); } } curReq.onerror = function(event){ reject("Error in Reading tweets from IDB!"); } db.close(); }; } ); } function createTweetElement(floID,time,tweet){ var tweetDisplay = document.getElementById("tweetsContainer"); var element = document.createElement("div"); element.setAttribute("class", "media"); element.innerHTML = `

${profiles[floID].name} @${floID}

${tweet}

`; tweetDisplay.insertBefore(element, tweetDisplay.firstChild); } function connectToAllFollowing(){ console.log("Connecting to All following servers...") following.forEach(floid => { console.log(floid) followingWebSockets[floid] = new WebSocket("ws://"+profiles[floid].onionAddr+"/ws"); followingWebSockets[floid].onopen = function(ev){ console.log(`Connected to ${floid} Server!`); getLastTweetCount(floid).then(function(result){ followingWebSockets[floid].send(`>${result}`); }).catch(function(error){ console.log(error.message); }); }; followingWebSockets[floid].onerror = function(ev) { console.log(`${floid} Server is offline!`); //Ping SuperNode for any new tweets pingSuperNodeforNewTweets(floid); }; followingWebSockets[floid].onclose = function(ev) { console.log(`Disconnected from ${floid} Server!`); }; followingWebSockets[floid].onmessage = function(evt){ console.log(evt.data); try{ var data = JSON.parse(evt.data); var id = data.id; data = data.data; if( floid!=data.floID || !encrypt.verify(data.tweet,data.sign,profiles[floid].pubKey)) return storeTweet({floID:data.floID,time:data.time,data:data.tweet},id); createTweetElement(data.floID,data.time,data.tweet); }catch(error){ console.log(error.message); } }; }); } function getLastTweetCount(floid){ return new Promise( function(resolve,reject){ var idb = indexedDB.open("FLO_Tweet"); idb.onsuccess = function(event) { var db = event.target.result; var lastTweet = db.transaction('lastTweet', "readwrite").objectStore('lastTweet'); var lastTweetReq = lastTweet.get(floid); lastTweetReq.onsuccess = function(event){ var result = event.target.result; if(result === undefined) result = 0; resolve(result); } db.close(); }; } ); } function pingSuperNodeforNewTweets(floID){ kBucketObj.determineClosestSupernode(floID).then(result=>{ var superNodeWS = new WebSocket("ws://"+profiles[result[0].floID].onionAddr+"/ws"); superNodeWS.onopen = function(ev){ console.log(`Connected to ${floID}'s SuperNode!`); getLastTweetCount(floID).then(function(result){ var data = JSON.stringify({reqNewTweets:true,floID:floID,tid:result,requestor:selfID}) superNodeWS.send(data); }).catch(function(error){ console.log(error.message); }); }; superNodeWS.onerror = function(ev) {console.log(`${floid}'s SuperNode is offline!`);}; superNodeWS.onclose = function(ev) {console.log(`Disconnected from ${floid}'s SuperNode!`);}; }).catch(e => { console.log(e.message); }); } function storeSuperNodeTweet(data,tid){ var idb = indexedDB.open("FLO_Tweet",2); idb.onerror = function(event) { console.log("Error in opening IndexedDB!"); }; idb.onupgradeneeded = function(event){ var objectStore = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' }); objectStore.createIndex('floID', 'floID', { unique: false }); objectStore.createIndex('tid', 'tid', { unique: false }); objectStore.createIndex('data', 'data', { unique: false }); } idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction("superNodeTweet", "readwrite").objectStore("superNodeTweet"); var parsedData = JSON.parse(data); var tweetID = ''+parsedData.floID+'_'+parsedData.time; obs.add({tweetID:tweetID,floID:parsedData.floID,tid:tid,data:data}); db.close(); }; } function SuperNode_sendTweetsFromIDB(floID,tid,requestor){ return new Promise( function(resolve,reject){ var requestorWS = new WebSocket("ws://"+profiles[requestor].onionAddr+"/ws"); requestorWS.onopen = function(ev){ console.log(`sending ${floID} tweets to ${requestor} Server!`); var idb = indexedDB.open("FLO_Tweet",2); idb.onerror = function(event) { reject("Error in opening IndexedDB!"); }; idb.onupgradeneeded = function(event){ var objectStore = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' }); objectStore.createIndex('floID', 'floID', { unique: false }); objectStore.createIndex('tid', 'tid', { unique: false }); objectStore.createIndex('data', 'data', { unique: false }); } idb.onsuccess = function(event) { var db = event.target.result; var obs = db.transaction("superNodeTweet", "readwrite").objectStore("superNodeTweet"); var curReq = obs.openCursor(); curReq.onsuccess = function(event) { var cursor = event.target.result; if(cursor) { if(cursor.value.floID == floID && cursor.value.tid > tid){ data = JSON.stringify({fromSuperNode:true, floID:cursor.value.floID,tid:cursor.value.tid,data:cursor.value.data}) requestorWS.send(data); } cursor.continue(); }else{ resolve("Displayed Tweets from IDB!"); } } curReq.onerror = function(event){ reject("Error in Reading tweets from IDB!"); } db.close(); }; }; requestorWS.onerror = function(ev) { console.log(`${requestor} Server is offline!`); }; requestorWS.onclose = function(ev) { console.log(`Disconnected from ${requestor} Server!`); }; } ); }