Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor improvement Chelonia #1618

Merged
Merged
2 changes: 1 addition & 1 deletion backend/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ if (!fs.existsSync(dataFolder)) {
}

sbp('sbp/selectors/register', {
'backend/db/streamEntriesSince': async function (contractID: string, hash: string): Promise<*> {
'backend/db/streamEntriesAfter': async function (contractID: string, hash: string): Promise<*> {
let currentHEAD = await sbp('chelonia/db/latestHash', contractID)
if (!currentHEAD) {
throw Boom.notFound(`contractID ${contractID} doesn't exist!`)
Expand Down
4 changes: 2 additions & 2 deletions backend/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ route.POST('/event', {
}
})

route.GET('/eventsSince/{contractID}/{since}', {}, async function (request, h) {
route.GET('/eventsAfter/{contractID}/{since}', {}, async function (request, h) {
try {
const { contractID, since } = request.params
const stream = await sbp('backend/db/streamEntriesSince', contractID, since)
const stream = await sbp('backend/db/streamEntriesAfter', contractID, since)
// "On an HTTP server, make sure to manually close your streams if a request is aborted."
// From: http://knexjs.org/#Interfaces-Streams
// https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams
Expand Down
2 changes: 1 addition & 1 deletion cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"baseUrl": "http://localhost:8000",
"viewportWidth": 1201,
"viewportHeight": 900,
"defaultCommandTimeout": 10000,
"defaultCommandTimeout": 10000,
"fixturesFolder": "test/cypress/fixtures",
"integrationFolder": "test/cypress/integration",
"pluginsFile": "test/cypress/plugins",
Expand Down
18 changes: 9 additions & 9 deletions shared/domains/chelonia/chelonia.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ export default (sbp('sbp/selectors/register', {
// TODO: r.body is a stream.Transform, should we use a callback to process
// the events one-by-one instead of converting to giant json object?
// however, note if we do that they would be processed in reverse...
'chelonia/out/eventsSince': async function (contractID: string, since: string) {
const events = await fetch(`${this.config.connectionURL}/eventsSince/${contractID}/${since}`)
'chelonia/out/eventsAfter': async function (contractID: string, since: string) {
const events = await fetch(`${this.config.connectionURL}/eventsAfter/${contractID}/${since}`)
.then(handleFetchResult('json'))
if (Array.isArray(events)) {
return events.reverse().map(b64ToStr)
Expand Down Expand Up @@ -352,7 +352,7 @@ export default (sbp('sbp/selectors/register', {
}
},
'chelonia/latestContractState': async function (contractID: string) {
const events = await sbp('chelonia/out/eventsSince', contractID, contractID)
const events = await sbp('chelonia/out/eventsAfter', contractID, contractID)
let state = {}
// fast-path
try {
Expand Down Expand Up @@ -393,7 +393,7 @@ export default (sbp('sbp/selectors/register', {
],
manifestHash
)
hooks && hooks.prepublishContract && hooks.prepublishContract(contractMsg)
hooks?.prepublishContract?.(contractMsg)
await sbp('chelonia/private/out/publishEvent', contractMsg, publishOptions)
const msg = await sbp('chelonia/out/actionEncrypted', {
action: contractName,
Expand Down Expand Up @@ -431,7 +431,7 @@ export default (sbp('sbp/selectors/register', {

function contractNameFromAction (action: string): string {
const regexResult = ACTION_REGEX.exec(action)
const contractName = regexResult && regexResult[2]
const contractName = regexResult?.[2]
if (!contractName) throw new Error(`Poorly named action '${action}': missing contract name.`)
return contractName
}
Expand All @@ -451,17 +451,17 @@ async function outEncryptedOrUnencryptedAction (
contract.metadata.validate(meta, { state, ...gProxy, contractID })
contract.actions[action].validate(data, { state, ...gProxy, meta, contractID })
const unencMessage = ({ action, data, meta }: GIOpActionUnencrypted)
const message = GIMessage.createV1_0(contractID, previousHEAD,
let message = GIMessage.createV1_0(contractID, previousHEAD,
[
opType,
opType === GIMessage.OP_ACTION_UNENCRYPTED ? unencMessage : this.config.encryptFn(unencMessage)
],
manifestHash
// TODO: add the signature function here to sign the message whether encrypted or not
)
hooks && hooks.prepublish && hooks.prepublish(message)
await sbp('chelonia/private/out/publishEvent', message, publishOptions)
hooks && hooks.postpublish && hooks.postpublish(message)
hooks?.prepublish?.(message)
message = await sbp('chelonia/private/out/publishEvent', message, publishOptions)
hooks?.postpublish?.(message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I love this simplification of using ?. and how you added it to many places in the code that needs it!

return message
}

Expand Down
26 changes: 20 additions & 6 deletions shared/domains/chelonia/internals.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default (sbp('sbp/selectors/register', {
}
})
if (r.ok) {
return r.text()
return entry
}
if (r.status === 409) {
if (attempt + 1 > maxAttempts) {
Expand Down Expand Up @@ -222,8 +222,8 @@ export default (sbp('sbp/selectors/register', {
}
if (processOp && !config.skipProcessing) {
opFns[opT](opV)
config.postOp && config.postOp(message, state)
config[`postOp_${opT}`] && config[`postOp_${opT}`](message, state)
config.postOp?.(message, state)
config[`postOp_${opT}`]?.(message, state)
Comment on lines +225 to +226
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful 👍

}
},
'chelonia/private/in/enqueueHandleEvent': function (event: GIMessage) {
Expand Down Expand Up @@ -253,7 +253,21 @@ export default (sbp('sbp/selectors/register', {
if (latest !== recent) {
console.debug(`[chelonia] Synchronizing Contract ${contractID}: our recent was ${recent || 'undefined'} but the latest is ${latest}`)
// TODO: fetch events from localStorage instead of server if we have them
const events = await sbp('chelonia/out/eventsSince', contractID, recent || contractID)
const events = await sbp('chelonia/out/eventsAfter', contractID, recent || contractID)
// Sanity check: verify event with latest hash exists in list of events
// TODO: using findLastIndex, it will be more clean but it needs Cypress 9.7+ which has bad performance
// https://docs.cypress.io/guides/references/changelog#9-7-0
// https://github.com/cypress-io/cypress/issues/22868
let latestHashFound = false
for (let i = events.length - 1; i >= 0; i--) {
if (GIMessage.deserialize(events[i]).hash() === latest) {
latestHashFound = true
break
}
}
if (!latestHashFound) {
throw new ChelErrorUnrecoverable(`expected hash ${latest} in list of events for contract ${contractID}`)
}
// remove the first element in cases where we are not getting the contract for the first time
state.contracts[contractID] && events.shift()
for (let i = 0; i < events.length; i++) {
Expand Down Expand Up @@ -281,7 +295,7 @@ export default (sbp('sbp/selectors/register', {
// Errors in mutations result in ignored messages
// Errors in side effects result in dropped messages to be reprocessed
try {
preHandleEvent && await preHandleEvent(message)
await preHandleEvent?.(message)
// verify we're expecting to hear from this contract
if (!state.pending.includes(contractID) && !state.contracts[contractID]) {
console.warn(`[chelonia] WARN: ignoring unexpected event ${message.description()}:`, message.serialize())
Expand Down Expand Up @@ -327,7 +341,7 @@ export default (sbp('sbp/selectors/register', {
this.config.hooks.sideEffectError?.(e, message)
}
try {
postHandleEvent && await postHandleEvent(message)
await postHandleEvent?.(message)
sbp('okTurtles.events/emit', hash, contractID, message)
sbp('okTurtles.events/emit', EVENT_HANDLED, contractID, message)
} catch (e) {
Expand Down
4 changes: 2 additions & 2 deletions test/backend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ sbp('sbp/selectors/register', {
'backend.tests/postEntry': async function (entry) {
console.log(bold.yellow('sending entry with hash:'), entry.hash())
const res = await sbp('chelonia/private/out/publishEvent', entry)
should(res).equal(entry.hash())
return res
should(res.id()).equal(entry.id())
return res.hash()
}
})

Expand Down