From cc083e64f8a96428fd096e6a526f700012f19d55 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 18 Oct 2020 16:38:41 -0400 Subject: [PATCH 1/3] export type --- services/gunDB/contact-api/SimpleGUN.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/SimpleGUN.ts b/services/gunDB/contact-api/SimpleGUN.ts index 3a9cd77b..6d04fdf7 100644 --- a/services/gunDB/contact-api/SimpleGUN.ts +++ b/services/gunDB/contact-api/SimpleGUN.ts @@ -1,7 +1,7 @@ /** * @prettier */ -type Primitive = boolean | string | number +export type Primitive = boolean | string | number export interface Data { [K: string]: ValidDataValue From b960a17855f39d0ea0a8bd787d83b9e639a059b8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 18 Oct 2020 16:41:07 -0400 Subject: [PATCH 2/3] gun rpc as a module --- services/gunDB/{rpc.js => rpc/index.js} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename services/gunDB/{rpc.js => rpc/index.js} (96%) diff --git a/services/gunDB/rpc.js b/services/gunDB/rpc/index.js similarity index 96% rename from services/gunDB/rpc.js rename to services/gunDB/rpc/index.js index 8d56592d..67d15ca0 100644 --- a/services/gunDB/rpc.js +++ b/services/gunDB/rpc/index.js @@ -6,16 +6,16 @@ const { makePromise, Constants, Schema } = require('shock-common') const mapValues = require('lodash/mapValues') const Bluebird = require('bluebird') -const { pubToEpub } = require('./contact-api/utils') +const { pubToEpub } = require('../contact-api/utils') const { getGun, getUser, mySEA: SEA, getMySecret, $$__SHOCKWALLET__ENCRYPTED__ -} = require('./Mediator') +} = require('../Mediator') /** - * @typedef {import('./contact-api/SimpleGUN').ValidDataValue} ValidDataValue + * @typedef {import('../contact-api/SimpleGUN').ValidDataValue} ValidDataValue */ /** From 57aca4a95cf3942264f0660a210b54edf54b1518 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 18 Oct 2020 16:44:30 -0400 Subject: [PATCH 3/3] auto set creation via arrays --- services/gunDB/rpc/index.js | 81 +++++++++++++++++++++++++++++-------- services/gunDB/rpc/types.ts | 8 ++++ 2 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 services/gunDB/rpc/types.ts diff --git a/services/gunDB/rpc/index.js b/services/gunDB/rpc/index.js index 67d15ca0..38d04aa1 100644 --- a/services/gunDB/rpc/index.js +++ b/services/gunDB/rpc/index.js @@ -1,10 +1,12 @@ /** * @format */ +/* eslint-disable no-use-before-define */ // @ts-check const { makePromise, Constants, Schema } = require('shock-common') const mapValues = require('lodash/mapValues') const Bluebird = require('bluebird') +const Gun = require('gun') const { pubToEpub } = require('../contact-api/utils') const { @@ -16,6 +18,8 @@ const { } = require('../Mediator') /** * @typedef {import('../contact-api/SimpleGUN').ValidDataValue} ValidDataValue + * @typedef {import('./types').ValidRPCDataValue} ValidRPCDataValue + * @typedef {import('./types').RPCData} RPCData */ /** @@ -55,10 +59,11 @@ const deepDecryptIfNeeded = async (value, publicKey) => { } /** - * @param {ValidDataValue} value - * @returns {Promise} + * @param {ValidRPCDataValue} value + * @returns {Promise} */ -const deepEncryptIfNeeded = async value => { +// eslint-disable-next-line func-style +async function deepEncryptIfNeeded(value) { const u = getUser() if (!u.is) { @@ -69,6 +74,10 @@ const deepEncryptIfNeeded = async value => { return value } + if (Array.isArray(value)) { + return Promise.all(value.map(v => deepEncryptIfNeeded(v))) + } + const pk = /** @type {string|undefined} */ (value.$$__ENCRYPT__FOR) if (!pk) { @@ -92,7 +101,7 @@ const deepEncryptIfNeeded = async value => { /** * @param {string} rawPath - * @param {ValidDataValue} value + * @param {ValidRPCDataValue} value * @returns {Promise} */ const put = async (rawPath, value) => { @@ -125,25 +134,34 @@ const put = async (rawPath, value) => { return _node })() - const encryptedIfNeededValue = await deepEncryptIfNeeded(value) + const theValue = await deepEncryptIfNeeded(value) - await makePromise((res, rej) => { - node.put(encryptedIfNeededValue, ack => { - if (ack.err && typeof ack.err !== 'number') { - rej(new Error(ack.err)) - } else { - res() - } + if (Array.isArray(theValue)) { + await Promise.all(theValue.map(v => set(rawPath, v))) + } else if (Schema.isObj(theValue)) { + const writes = mapValues(theValue, (v, k) => put(`${rawPath}.${k}`, v)) + + await Bluebird.props(writes) + } /* is primitive */ else { + await makePromise((res, rej) => { + node.put(/** @type {ValidDataValue} */ (theValue), ack => { + if (ack.err && typeof ack.err !== 'number') { + rej(new Error(ack.err)) + } else { + res() + } + }) }) - }) + } } /** * @param {string} rawPath - * @param {ValidDataValue} value + * @param {ValidRPCDataValue} value * @returns {Promise} */ -const set = async (rawPath, value) => { +// eslint-disable-next-line func-style +async function set(rawPath, value) { const [root, ...path] = rawPath.split('.') const node = (() => { @@ -173,10 +191,39 @@ const set = async (rawPath, value) => { return _node })() - const encryptedIfNeededValue = await deepEncryptIfNeeded(value) + const theValue = await deepEncryptIfNeeded(value) + + if (Array.isArray(theValue)) { + // we'll create a set of sets + + // @ts-expect-error + const uuid = Gun.text.random() + + // here we are simulating the top-most set() + const subPath = rawPath + '.' + uuid + + const writes = theValue.map(v => set(subPath, v)) + + await Promise.all(writes) + + return uuid + } else if (Schema.isObj(theValue)) { + // @ts-expect-error + const uuid = Gun.text.random() // we'll handle UUID ourselves + + // so we can use our own put() + + const subPath = rawPath + '.' + uuid + + await put(subPath, theValue) + + return uuid + } + + /* else is primitive */ const id = await makePromise((res, rej) => { - const subNode = node.set(encryptedIfNeededValue, ack => { + const subNode = node.set(theValue, ack => { if (ack.err && typeof ack.err !== 'number') { rej(new Error(ack.err)) } else { diff --git a/services/gunDB/rpc/types.ts b/services/gunDB/rpc/types.ts new file mode 100644 index 00000000..e30bb4b8 --- /dev/null +++ b/services/gunDB/rpc/types.ts @@ -0,0 +1,8 @@ +import {Primitive} from '../contact-api/SimpleGUN' + + +export interface RPCData { + [K: string]: ValidRPCDataValue +} + +export type ValidRPCDataValue = Primitive | null | RPCData | Array \ No newline at end of file