Merge pull request #217 from shocknet/rpc-auto-sets

Rpc auto sets
This commit is contained in:
Daniel Lugo 2020-10-18 16:47:41 -04:00 committed by GitHub
commit 5962a03efa
3 changed files with 76 additions and 21 deletions

View file

@ -1,7 +1,7 @@
/** /**
* @prettier * @prettier
*/ */
type Primitive = boolean | string | number export type Primitive = boolean | string | number
export interface Data { export interface Data {
[K: string]: ValidDataValue [K: string]: ValidDataValue

View file

@ -1,21 +1,25 @@
/** /**
* @format * @format
*/ */
/* eslint-disable no-use-before-define */
// @ts-check // @ts-check
const { makePromise, Constants, Schema } = require('shock-common') const { makePromise, Constants, Schema } = require('shock-common')
const mapValues = require('lodash/mapValues') const mapValues = require('lodash/mapValues')
const Bluebird = require('bluebird') const Bluebird = require('bluebird')
const Gun = require('gun')
const { pubToEpub } = require('./contact-api/utils') const { pubToEpub } = require('../contact-api/utils')
const { const {
getGun, getGun,
getUser, getUser,
mySEA: SEA, mySEA: SEA,
getMySecret, getMySecret,
$$__SHOCKWALLET__ENCRYPTED__ $$__SHOCKWALLET__ENCRYPTED__
} = require('./Mediator') } = require('../Mediator')
/** /**
* @typedef {import('./contact-api/SimpleGUN').ValidDataValue} ValidDataValue * @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 * @param {ValidRPCDataValue} value
* @returns {Promise<ValidDataValue>} * @returns {Promise<ValidRPCDataValue>}
*/ */
const deepEncryptIfNeeded = async value => { // eslint-disable-next-line func-style
async function deepEncryptIfNeeded(value) {
const u = getUser() const u = getUser()
if (!u.is) { if (!u.is) {
@ -69,6 +74,10 @@ const deepEncryptIfNeeded = async value => {
return value return value
} }
if (Array.isArray(value)) {
return Promise.all(value.map(v => deepEncryptIfNeeded(v)))
}
const pk = /** @type {string|undefined} */ (value.$$__ENCRYPT__FOR) const pk = /** @type {string|undefined} */ (value.$$__ENCRYPT__FOR)
if (!pk) { if (!pk) {
@ -92,7 +101,7 @@ const deepEncryptIfNeeded = async value => {
/** /**
* @param {string} rawPath * @param {string} rawPath
* @param {ValidDataValue} value * @param {ValidRPCDataValue} value
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
const put = async (rawPath, value) => { const put = async (rawPath, value) => {
@ -125,10 +134,17 @@ const put = async (rawPath, value) => {
return _node return _node
})() })()
const encryptedIfNeededValue = await deepEncryptIfNeeded(value) const theValue = await deepEncryptIfNeeded(value)
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) => { await makePromise((res, rej) => {
node.put(encryptedIfNeededValue, ack => { node.put(/** @type {ValidDataValue} */ (theValue), ack => {
if (ack.err && typeof ack.err !== 'number') { if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err)) rej(new Error(ack.err))
} else { } else {
@ -137,13 +153,15 @@ const put = async (rawPath, value) => {
}) })
}) })
} }
}
/** /**
* @param {string} rawPath * @param {string} rawPath
* @param {ValidDataValue} value * @param {ValidRPCDataValue} value
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
const set = async (rawPath, value) => { // eslint-disable-next-line func-style
async function set(rawPath, value) {
const [root, ...path] = rawPath.split('.') const [root, ...path] = rawPath.split('.')
const node = (() => { const node = (() => {
@ -173,10 +191,39 @@ const set = async (rawPath, value) => {
return _node 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 id = await makePromise((res, rej) => {
const subNode = node.set(encryptedIfNeededValue, ack => { const subNode = node.set(theValue, ack => {
if (ack.err && typeof ack.err !== 'number') { if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err)) rej(new Error(ack.err))
} else { } else {

View file

@ -0,0 +1,8 @@
import {Primitive} from '../contact-api/SimpleGUN'
export interface RPCData {
[K: string]: ValidRPCDataValue
}
export type ValidRPCDataValue = Primitive | null | RPCData | Array<ValidRPCDataValue>