diff --git a/db.js b/db.js index 308321c..c0253e4 100644 --- a/db.js +++ b/db.js @@ -66,8 +66,9 @@ exports.init = function (dir, ssbId) { function validateAndAdd(msg, cb) { const knownAuthor = msg.author in SSB.state.feeds const earlierMessage = knownAuthor && msg.sequence < SSB.state.feeds[msg.author].sequence + const skippingMessages = knownAuthor && msg.sequence > SSB.state.feeds[msg.author].sequence + 1 - if (!knownAuthor || earlierMessage) + if (!knownAuthor || earlierMessage || skippingMessages) SSB.state = validate.appendOOO(SSB.state, hmac_key, msg) else SSB.state = validate.append(SSB.state, hmac_key, msg) @@ -98,7 +99,12 @@ exports.init = function (dir, ssbId) { if (ok) { add(msg, cb) - } else { + + if (skippingMessages) + store.last.setPartialLogState(msg.author, true) + } + else + { if (updateLast) store.last.setPartialLogState(msg.author, true) cb() diff --git a/dist/bundle-core.js b/dist/bundle-core.js index 3b8c655..25ffab0 100644 --- a/dist/bundle-core.js +++ b/dist/bundle-core.js @@ -1297,7 +1297,7 @@ const validate=require("ssb-validate"),keys=require("ssb-keys"),pull=require("pu exports.init=function(e,i){const r=require("pull-stream"),s=require("events");if(SSB={events:new s},"undefined"==typeof localStorage||null===localStorage){const i=require("path"),r=require("fs");r.existsSync(e)||r.mkdirSync(e);var o=require("node-localstorage").LocalStorage;localStorage=new o(i.join(e,"localstorage"))}require("sodium-browserify").events.on("sodium-browserify:wasm loaded",function(){console.log("wasm loaded");var s=require("./net").init(e,i),o=require("./db").init(e,s.id);console.log("my id: ",s.id);var t=require("./core-helpers"),n=require("ssb-validate"),l=n.initial(),a=o.last.get();for(var d in a)l.feeds[d]={id:a[d].id,timestamp:a[d].timestamp,sequence:a[d].sequence,queue:[]};SSB=Object.assign(SSB,{db:o,net:s,dir:e,validate:n,state:l,connected:t.connected,removeFeedState:function(e){o.last.removeFeed(e),delete SSB.state.feeds[e],delete SSB.profiles[this.feedId],t.saveProfiles()},removeDB:t.removeDB,removeBlobs:t.removeBlobs,initialSync:t.initialSync,sync:t.sync,box:require("ssb-keys").box,blobFiles:require("ssb-blob-files"),rawConnect:require("./raw-connect"),publish:function(e,i){l.queue=[],l=n.appendNew(l,null,s.config.keys,e,Date.now()),console.log(l.queue[0]),o.add(l.queue[0].value,(e,r)=>{o.last.update(r.value),s.post(r.value),i(e,r)})},messagesByType:function(e){return r(o.query.read({reverse:e.reverse,limit:e.limit,query:[{$filter:{value:{content:{type:e.type}}}},{$map:!0}]}))},validMessageTypes:["post","peer-invite/confirm","peer-invite/accept","peer-invite"],privateMessages:!0,syncOnlyFeedsFollowing:!1,remoteAddress:"",saveProfiles:t.saveProfiles,loadProfiles:t.loadProfiles,profiles:{}}),SSB.events.emit("SSB: loaded")})}; },{"./core-helpers":184,"./db":186,"./net":190,"./raw-connect":624,"events":89,"fs":1,"node-localstorage":387,"path":121,"pull-stream":470,"sodium-browserify":556,"ssb-blob-files":568,"ssb-keys":579,"ssb-validate":603}],186:[function(require,module,exports){ -const Store=require("./store"),pull=require("pull-stream"),hash=require("ssb-keys/util").hash,validate=require("ssb-validate"),keys=require("ssb-keys");function getId(e){return"%"+hash(JSON.stringify(e,null,2))}exports.init=function(e,t){const n=Store(e,t);function a(e,t){var a=getId(e);0==n.since.value||SSB.isInitialSync?n.add(a,e,t):n.keys.get(a,(s,r)=>{r?t(null,r.value):n.add(a,e,t)})}const s=null;return{get:function(e,t){n.keys.get(e,(e,n)=>{n?t(null,n.value):t(e)})},add:a,validateAndAdd:function(e,t){const r=e.author in SSB.state.feeds,i=r&&e.sequence{n.del(e.key,n=>{t(n,e.key)})}),pull.collect(t))},backlinks:n.backlinks,query:n.query,last:n.last,clock:n.clock,friends:n.friends,peerInvites:n["peer-invites"],getStatus:n.getStatus}}; +const Store=require("./store"),pull=require("pull-stream"),hash=require("ssb-keys/util").hash,validate=require("ssb-validate"),keys=require("ssb-keys");function getId(e){return"%"+hash(JSON.stringify(e,null,2))}exports.init=function(e,t){const n=Store(e,t);function a(e,t){var a=getId(e);0==n.since.value||SSB.isInitialSync?n.add(a,e,t):n.keys.get(a,(s,r)=>{r?t(null,r.value):n.add(a,e,t)})}const s=null;return{get:function(e,t){n.keys.get(e,(e,n)=>{n?t(null,n.value):t(e)})},add:a,validateAndAdd:function(e,t){const r=e.author in SSB.state.feeds,i=r&&e.sequenceSSB.state.feeds[e.author].sequence+1;if(SSB.state=!r||i||o?validate.appendOOO(SSB.state,s,e):validate.append(SSB.state,s,e),SSB.state.error)return t(SSB.state.error);const l=!i;l&&n.last.update(e);var u=!0,S="string"==typeof e.content;S&&!SSB.privateMessages?u=!1:S||"about"!=e.content.type||e.content.about!=e.author?S||SSB.validMessageTypes.includes(e.content.type)?S&&(function(e){return keys.unbox(e.content,SSB.net.config.keys.private)}(e)||(u=!1)):u=!1:function(e){SSB.profiles||(SSB.profiles={}),SSB.profiles[e.author]||(SSB.profiles[e.author]={}),e.content.name&&(SSB.profiles[e.author].name=e.content.name),e.content.description&&(SSB.profiles[e.author].description=e.content.description),e.content.image&&"string"==typeof e.content.image.link?SSB.profiles[e.author].image=e.content.image.link:"string"==typeof e.content.image&&(SSB.profiles[e.author].image=e.content.image)}(e);u?(a(e,t),o&&n.last.setPartialLogState(e.author,!0)):(l&&n.last.setPartialLogState(e.author,!0),t())},del:n.del,deleteFeed:function(e,t){pull(n.query.read({query:[{$filter:{value:{author:e}}}]}),pull.asyncMap((e,t)=>{n.del(e.key,n=>{t(n,e.key)})}),pull.collect(t))},backlinks:n.backlinks,query:n.query,last:n.last,clock:n.clock,friends:n.friends,peerInvites:n["peer-invites"],getStatus:n.getStatus}}; },{"./store":629,"pull-stream":470,"ssb-keys":579,"ssb-keys/util":583,"ssb-validate":603}],187:[function(require,module,exports){ const Reduce=require("flumeview-reduce");module.exports=function(){const e=Reduce(2,function(e,n,u){return e||(e={}),e[[n.value.author,n.value.sequence]]=u,e});return function(n,u){const t=e(n,u),o=t.get;return t.get=function(e,u){o(function(t,o){t?u(t):o&&null!=o[e]?n.get(o[e],u):u(new Error("not found:"+e))})},t}}; diff --git a/tests/validate.js b/tests/validate.js index 98cd604..479cbb3 100644 --- a/tests/validate.js +++ b/tests/validate.js @@ -101,4 +101,31 @@ SSB.events.on('SSB: loaded', function() { }) }) + // we might get some messages from an earlier thread, and then get the latest 25 messages from the user + test('Add with holes', t => { + const validate = require('ssb-validate') + var state = validate.initial() + var keys = require('ssb-keys').generate() + + state = validate.appendNew(state, null, keys, { type: 'post', text: 'test1' }, Date.now()) // ooo + state = validate.appendNew(state, null, keys, { type: 'post', text: 'test2' }, Date.now()) // missing + state = validate.appendNew(state, null, keys, { type: 'post', text: 'test3' }, Date.now()) // start + + SSB.db.validateAndAdd(state.queue[0].value, (err) => { + if (err) console.error(err) + + SSB.db.validateAndAdd(state.queue[2].value, (err, msg) => { + if (err) console.error(err) + + t.equal(msg.value.content.text, 'test3', 'text correct') + + const last = SSB.db.last.get()[keys.id] + t.equal(last.partial, true, 'is partial') + t.equal(last.sequence, 3, 'correct seq') + + t.end() + }) + }) + }) + })