Merge pull request #355 from shocknet/disconn-fix

Disconnection (+ requests improvement + dead code removal)
This commit is contained in:
CapDog 2021-05-02 12:58:46 -04:00 committed by GitHub
commit c23da4a781
8 changed files with 102 additions and 1147 deletions

View file

@ -3,5 +3,9 @@
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"debug.node.autoAttach": "on", "debug.node.autoAttach": "on",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode",
"cSpell.words": [
"ISEA",
"Reqs"
]
} }

View file

@ -12,7 +12,6 @@ Gun.log = () => {}
require('gun/lib/open') require('gun/lib/open')
// @ts-ignore // @ts-ignore
require('gun/lib/load') require('gun/lib/load')
const debounce = require('lodash/debounce')
//@ts-ignore //@ts-ignore
const { encryptedEmit, encryptedOn } = require('../../../utils/ECC/socket') const { encryptedEmit, encryptedOn } = require('../../../utils/ECC/socket')
const Key = require('../contact-api/key') const Key = require('../contact-api/key')
@ -215,14 +214,9 @@ mySEA.secret = async (recipientOrSenderEpub, recipientOrSenderSEA) => {
return sec return sec
} }
const auth = require('../../auth/auth')
const { Constants } = require('shock-common') const { Constants } = require('shock-common')
const { Action, Event } = Constants
const API = require('../contact-api/index') const API = require('../contact-api/index')
const Config = require('../config')
// const { nonEncryptedRoutes } = require('../../../utils/protectedRoutes')
/** /**
* @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode * @typedef {import('../contact-api/SimpleGUN').GUNNode} GUNNode
@ -385,12 +379,8 @@ const authenticate = async (alias, pass, __user) => {
API.Jobs.onOrders(_user, gun, mySEA) API.Jobs.onOrders(_user, gun, mySEA)
API.Jobs.lastSeenNode(_user) API.Jobs.lastSeenNode(_user)
API.Events.onAvatar(() => {}, user)()
API.Events.onBio(() => {}, user)
API.Events.onBlacklist(() => {}, user)
API.Events.onChats(() => {})() API.Events.onChats(() => {})()
API.Events.onCurrentHandshakeAddress(() => {}, user)() API.Events.onCurrentHandshakeAddress(() => {}, user)()
API.Events.onDisplayName(() => {}, user)()
API.Events.onOutgoing(() => {})() API.Events.onOutgoing(() => {})()
API.Events.onSeedBackup(() => {}, user, mySEA) API.Events.onSeedBackup(() => {}, user, mySEA)
API.Events.onSimplerReceivedRequests(() => {})() API.Events.onSimplerReceivedRequests(() => {})()
@ -443,12 +433,9 @@ const authenticate = async (alias, pass, __user) => {
API.Jobs.onOrders(_user, gun, mySEA) API.Jobs.onOrders(_user, gun, mySEA)
API.Jobs.lastSeenNode(_user) API.Jobs.lastSeenNode(_user)
API.Events.onAvatar(() => {}, user)()
API.Events.onBio(() => {}, user)
API.Events.onBlacklist(() => {}, user)
API.Events.onChats(() => {})() API.Events.onChats(() => {})()
API.Events.onCurrentHandshakeAddress(() => {}, user)() API.Events.onCurrentHandshakeAddress(() => {}, user)()
API.Events.onDisplayName(() => {}, user)()
API.Events.onOutgoing(() => {})() API.Events.onOutgoing(() => {})()
API.Events.onSeedBackup(() => {}, user, mySEA) API.Events.onSeedBackup(() => {}, user, mySEA)
API.Events.onSimplerReceivedRequests(() => {})() API.Events.onSimplerReceivedRequests(() => {})()
@ -499,811 +486,6 @@ const freshGun = () => {
} }
} }
/**
* @param {string} token
* @returns {Promise<boolean>}
*/
const isValidToken = async token => {
const validation = await auth.validateToken(token)
if (typeof validation !== 'object') {
return false
}
if (validation === null) {
return false
}
if (typeof validation.valid !== 'boolean') {
return false
}
return validation.valid
}
/**
* @param {string} token
* @throws {Error} If the token is invalid
* @returns {Promise<void>}
*/
const throwOnInvalidToken = async token => {
const isValid = await isValidToken(token)
if (!isValid) {
throw new Error('Token expired.')
}
}
class Mediator {
/**
* @param {Readonly<SimpleSocket>} socket
*/
constructor(socket) {
this.socket = this.encryptSocketInstance(socket)
this.connected = true
this.socket.on('disconnect', this.onDisconnect)
this.socket.on(Action.ACCEPT_REQUEST, this.acceptRequest)
this.socket.on(Action.BLACKLIST, this.blacklist)
this.socket.on(
Action.GENERATE_NEW_HANDSHAKE_NODE,
this.generateHandshakeNode
)
this.socket.on('GENERATE_ORDER_ADDRESS', this.generateOrderAddress)
this.socket.on('INIT_FEED_WALL', this.initWall)
this.socket.on(Action.SEND_HANDSHAKE_REQUEST, this.sendHandshakeRequest)
this.socket.on(
Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG,
this.sendHRWithInitialMsg
)
this.socket.on(Action.SEND_MESSAGE, this.sendMessage)
this.socket.on(Action.SET_AVATAR, this.setAvatar)
this.socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName)
this.socket.on(Action.SEND_PAYMENT, this.sendPayment)
this.socket.on(Action.SET_BIO, this.setBio)
this.socket.on(Action.DISCONNECT, this.disconnect)
this.socket.on(Event.ON_AVATAR, this.onAvatar)
this.socket.on(Event.ON_BLACKLIST, this.onBlacklist)
this.socket.on(Event.ON_CHATS, this.onChats)
this.socket.on(Event.ON_DISPLAY_NAME, this.onDisplayName)
this.socket.on(Event.ON_HANDSHAKE_ADDRESS, this.onHandshakeAddress)
this.socket.on(Event.ON_RECEIVED_REQUESTS, this.onReceivedRequests)
this.socket.on(Event.ON_SENT_REQUESTS, this.onSentRequests)
this.socket.on(Event.ON_BIO, this.onBio)
this.socket.on(Event.ON_SEED_BACKUP, this.onSeedBackup)
this.socket.on(Constants.Misc.IS_GUN_AUTH, this.isGunAuth)
this.socket.on(Action.SET_LAST_SEEN_APP, this.setLastSeenApp)
Object.values(Action).forEach(actionConstant =>
this.socket.on(actionConstant, this.setLastSeenApp)
)
}
/** @param {SimpleSocket} socket */
encryptSocketInstance = socket => {
const emit = encryptedEmit(socket)
const on = encryptedOn(socket)
return {
/**
* @type {SimpleSocket['on']}
*/
on,
/** @type {SimpleSocket['emit']} */
emit
}
}
/** @param {{ token: string }} body */
setLastSeenApp = async body => {
logger.info('setLastSeen Called')
try {
await throwOnInvalidToken(body.token)
await API.Actions.setLastSeenApp()
this.socket.emit(Action.SET_LAST_SEEN_APP, {
ok: true,
msg: null,
origBody: body
})
} catch (e) {
this.socket.emit(Action.SET_LAST_SEEN_APP, {
ok: false,
msg: e.message,
origBody: body
})
}
}
isGunAuth = () => {
try {
const isGunAuth = isAuthenticated()
this.socket.emit(Constants.Misc.IS_GUN_AUTH, {
ok: true,
msg: {
isGunAuth
},
origBody: {}
})
} catch (err) {
this.socket.emit(Constants.Misc.IS_GUN_AUTH, {
ok: false,
msg: err.message,
origBody: {}
})
}
}
/**
* @param {Readonly<{ requestID: string , token: string }>} body
*/
acceptRequest = async body => {
try {
const { requestID, token } = body
await throwOnInvalidToken(token)
await API.Actions.acceptRequest(requestID, gun, user, mySEA)
this.socket.emit(Action.ACCEPT_REQUEST, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.ACCEPT_REQUEST, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ publicKey: string , token: string }>} body
*/
blacklist = async body => {
try {
const { publicKey, token } = body
await throwOnInvalidToken(token)
await API.Actions.blacklist(publicKey, user)
this.socket.emit(Action.BLACKLIST, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.BLACKLIST, {
ok: false,
msg: err.message,
origBody: body
})
}
}
onDisconnect = () => {
this.connected = false
}
/**
* @param {Readonly<{ token: string }>} body
*/
generateHandshakeNode = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
await API.Actions.generateHandshakeAddress()
this.socket.emit(Action.GENERATE_NEW_HANDSHAKE_NODE, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.GENERATE_NEW_HANDSHAKE_NODE, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
generateOrderAddress = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
await API.Actions.generateOrderAddress(user)
this.socket.emit('GENERATE_ORDER_ADDRESS', {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit('GENERATE_ORDER_ADDRESS', {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
initWall = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
await API.Actions.initWall()
this.socket.emit('INIT_FEED_WALL', {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit('INIT_FEED_WALL', {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ recipientPublicKey: string , token: string }>} body
*/
sendHandshakeRequest = async body => {
try {
if (Config.SHOW_LOG) {
logger.info('\n')
logger.info('------------------------------')
logger.info('will now try to send a handshake request')
logger.info('------------------------------')
logger.info('\n')
}
const { recipientPublicKey, token } = body
await throwOnInvalidToken(token)
await API.Actions.sendHandshakeRequest(
recipientPublicKey,
gun,
user,
mySEA
)
if (Config.SHOW_LOG) {
logger.info('\n')
logger.info('------------------------------')
logger.info('handshake request successfuly sent')
logger.info('------------------------------')
logger.info('\n')
}
this.socket.emit(Action.SEND_HANDSHAKE_REQUEST, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
if (Config.SHOW_LOG) {
logger.info('\n')
logger.info('------------------------------')
logger.info('handshake request send fail: ' + err.message)
logger.info('------------------------------')
logger.info('\n')
}
this.socket.emit(Action.SEND_HANDSHAKE_REQUEST, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ initialMsg: string , recipientPublicKey: string , token: string }>} body
*/
sendHRWithInitialMsg = async body => {
try {
const { initialMsg, recipientPublicKey, token } = body
await throwOnInvalidToken(token)
await API.Actions.sendHRWithInitialMsg(
initialMsg,
recipientPublicKey,
gun,
user,
mySEA
)
this.socket.emit(Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.SEND_HANDSHAKE_REQUEST_WITH_INITIAL_MSG, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ body: string , recipientPublicKey: string , token: string }>} reqBody
*/
sendMessage = async reqBody => {
try {
const { body, recipientPublicKey, token } = reqBody
await throwOnInvalidToken(token)
this.socket.emit(Action.SEND_MESSAGE, {
ok: true,
msg: await API.Actions.sendMessage(
recipientPublicKey,
body,
user,
mySEA
),
origBody: reqBody
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.SEND_MESSAGE, {
ok: false,
msg: err.message,
origBody: reqBody
})
}
}
/**
* @param {Readonly<{ uuid: string, recipientPub: string, amount: number, memo: string, token: string, feeLimit:number }>} reqBody
*/
sendPayment = async reqBody => {
try {
const { recipientPub, amount, memo, feeLimit, token } = reqBody
await throwOnInvalidToken(token)
const preimage = await API.Actions.sendPayment(
recipientPub,
amount,
memo,
feeLimit
)
this.socket.emit(Action.SEND_PAYMENT, {
ok: true,
msg: preimage,
origBody: reqBody
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.SEND_PAYMENT, {
ok: false,
msg: err.message,
origBody: reqBody
})
}
}
/**
* @param {Readonly<{ avatar: string|null , token: string }>} body
*/
setAvatar = async body => {
try {
const { avatar, token } = body
await throwOnInvalidToken(token)
await API.Actions.setAvatar(avatar, user)
this.socket.emit(Action.SET_AVATAR, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.SET_AVATAR, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ displayName: string , token: string }>} body
*/
setDisplayName = async body => {
try {
const { displayName, token } = body
await throwOnInvalidToken(token)
await API.Actions.setDisplayName(displayName, user)
this.socket.emit(Action.SET_DISPLAY_NAME, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.SET_DISPLAY_NAME, {
ok: false,
msg: err.message,
origBody: body
})
}
}
//////////////////////////////////////////////////////////////////////////////
/**
* @param {Readonly<{ token: string }>} body
*/
onAvatar = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
API.Events.onAvatar(avatar => {
if (Config.SHOW_LOG) {
logger.info('---avatar---')
logger.info(avatar || 'null')
logger.info('-----------------------')
}
this.socket.emit(Event.ON_AVATAR, {
msg: avatar,
ok: true,
origBody: body
})
}, user)
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_AVATAR, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onBlacklist = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
API.Events.onBlacklist(blacklist => {
if (Config.SHOW_LOG) {
logger.info('---blacklist---')
logger.info(blacklist.join(','))
logger.info('-----------------------')
}
this.socket.emit(Event.ON_BLACKLIST, {
msg: blacklist,
ok: true,
origBody: body
})
}, user)
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_BLACKLIST, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onChats = async body => {
try {
const { token } = body
// logger.info('ON_CHATS', body)
await throwOnInvalidToken(token)
API.Events.onChats(chats => {
if (Config.SHOW_LOG) {
logger.info('---chats---')
logger.info(JSON.stringify(chats))
logger.info('-----------------------')
}
this.socket.emit(Event.ON_CHATS, {
msg: chats,
ok: true,
origBody: body
})
})
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_CHATS, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onDisplayName = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
API.Events.onDisplayName(displayName => {
if (Config.SHOW_LOG) {
logger.info('---displayName---')
logger.info(displayName || 'null or empty string')
logger.info('-----------------------')
}
this.socket.emit(Event.ON_DISPLAY_NAME, {
msg: displayName,
ok: true,
origBody: body
})
}, user)
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_DISPLAY_NAME, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onHandshakeAddress = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
API.Events.onCurrentHandshakeAddress(addr => {
if (Config.SHOW_LOG) {
logger.info('---addr---')
logger.info(addr || 'null or empty string')
logger.info('-----------------------')
}
this.socket.emit(Event.ON_HANDSHAKE_ADDRESS, {
ok: true,
msg: addr,
origBody: body
})
}, user)
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_HANDSHAKE_ADDRESS, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onReceivedRequests = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
API.Events.onSimplerReceivedRequests(receivedRequests => {
this.socket.emit(Event.ON_RECEIVED_REQUESTS, {
msg: receivedRequests,
ok: true,
origBody: body
})
})
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_RECEIVED_REQUESTS, {
msg: err.message,
ok: false,
origBody: body
})
}
}
onSentRequestsSubbed = false
/**
* @param {Readonly<{ token: string }>} body
*/
onSentRequests = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
if (!this.onSentRequestsSubbed) {
this.onSentRequestsSubbed = true
API.Events.onSimplerSentRequests(
debounce(sentRequests => {
// logger.info(
// `new Reqss in mediator: ${JSON.stringify(sentRequests)}`
// )
this.socket.emit(Event.ON_SENT_REQUESTS, {
msg: sentRequests,
ok: true,
origBody: body
})
}, 1000)
)
}
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_SENT_REQUESTS, {
msg: err.message,
ok: false,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onBio = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
API.Events.onBio(bio => {
this.socket.emit(Event.ON_BIO, {
msg: bio,
ok: true,
origBody: body
})
}, user)
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_BIO, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ bio: string|null , token: string }>} body
*/
setBio = async body => {
try {
const { bio, token } = body
await throwOnInvalidToken(token)
await API.Actions.setBio(bio, user)
this.socket.emit(Action.SET_BIO, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
logger.info(err)
this.socket.emit(Action.SET_BIO, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/**
* @param {Readonly<{ token: string }>} body
*/
onSeedBackup = async body => {
try {
const { token } = body
await throwOnInvalidToken(token)
await API.Events.onSeedBackup(
seedBackup => {
this.socket.emit(Event.ON_SEED_BACKUP, {
ok: true,
msg: seedBackup,
origBody: body
})
},
user,
mySEA
)
} catch (err) {
logger.info(err)
this.socket.emit(Event.ON_SEED_BACKUP, {
ok: false,
msg: err.message,
origBody: body
})
}
}
/** @param {Readonly<{ pub: string, token: string }>} body */
disconnect = async body => {
try {
const { pub, token } = body
await throwOnInvalidToken(token)
await API.Actions.disconnect(pub)
this.socket.emit(Action.DISCONNECT, {
ok: true,
msg: null,
origBody: body
})
} catch (err) {
this.socket.emit(Action.DISCONNECT, {
ok: false,
msg: err.message,
origBody: body
})
}
}
}
/** /**
* Creates an user for gun. Returns a promise containing the public key of the * Creates an user for gun. Returns a promise containing the public key of the
* newly created user. * newly created user.
@ -1422,25 +604,9 @@ const register = async (alias, pass) => {
}) })
} }
/**
* @param {SimpleSocket} socket
* @throws {Error} If gun is not authenticated or is in the process of
* authenticating. Use `isAuthenticating()` and `isAuthenticated()` to check for
* this first.
* @returns {Mediator}
*/
const createMediator = socket => {
// if (isAuthenticating() || !isAuthenticated()) {
// throw new Error("Gun must be authenticated to create a Mediator");
// }
return new Mediator(socket)
}
module.exports = { module.exports = {
authenticate, authenticate,
logoff, logoff,
createMediator,
isAuthenticated, isAuthenticated,
isAuthenticating, isAuthenticating,
isRegistering, isRegistering,

View file

@ -80,85 +80,6 @@ const __onUserToIncoming = (cb, user, SEA) => {
}) })
} }
/** @type {Set<(av: string|null) => void>} */
const avatarListeners = new Set()
/** @type {string|null} */
let currentAvatar = null
const getAvatar = () => currentAvatar
/** @param {string|null} av */
const setAvatar = av => {
currentAvatar = av
avatarListeners.forEach(l => l(currentAvatar))
}
let avatarSubbed = false
/**
* @param {(avatar: string|null) => void} cb
* @param {UserGUNNode} user Pass only for testing purposes.
* @throws {Error} If user hasn't been auth.
* @returns {() => void}
*/
const onAvatar = (cb, user) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
avatarListeners.add(cb)
cb(currentAvatar)
if (!avatarSubbed) {
avatarSubbed = true
user
.get(Key.PROFILE_BINARY)
.get(Key.AVATAR)
.on(avatar => {
if (typeof avatar === 'string' || avatar === null) {
setAvatar(avatar)
}
})
}
return () => {
avatarListeners.delete(cb)
}
}
/**
* @param {(blacklist: string[]) => void} cb
* @param {UserGUNNode} user
* @returns {void}
*/
const onBlacklist = (cb, user) => {
/** @type {string[]} */
const blacklist = []
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
const callb = debounce(cb, DEBOUNCE_WAIT_TIME)
// Initial value if no items are in blacklist in gun
callb(blacklist)
user
.get(Key.BLACKLIST)
.map()
.on(publicKey => {
if (typeof publicKey === 'string' && publicKey.length > 0) {
blacklist.push(publicKey)
callb(blacklist)
} else {
logger.warn('Invalid public key received for blacklist')
}
})
}
/** @type {Set<(addr: string|null) => void>} */ /** @type {Set<(addr: string|null) => void>} */
const addressListeners = new Set() const addressListeners = new Set()
@ -210,54 +131,6 @@ const onCurrentHandshakeAddress = (cb, user) => {
} }
} }
/** @type {Set<(dn: string|null) => void>} */
const dnListeners = new Set()
/** @type {string|null} */
let currentDn = null
const getDisplayName = () => currentDn
/** @param {string|null} dn */
const setDn = dn => {
currentDn = dn
dnListeners.forEach(l => l(currentDn))
}
let dnSubbed = false
/**
* @param {(displayName: string|null) => void} cb
* @param {UserGUNNode} user Pass only for testing purposes.
* @throws {Error} If user hasn't been auth.
* @returns {() => void}
*/
const onDisplayName = (cb, user) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
cb(currentDn)
dnListeners.add(cb)
if (!dnSubbed) {
dnSubbed = true
user
.get(Key.PROFILE)
.get(Key.DISPLAY_NAME)
.on(displayName => {
if (typeof displayName === 'string' || displayName === null) {
setDn(displayName)
}
})
}
return () => {
dnListeners.delete(cb)
}
}
/** /**
* @param {(messages: Record<string, Message>) => void} cb * @param {(messages: Record<string, Message>) => void} cb
* @param {string} userPK Public key of the user from whom the incoming * @param {string} userPK Public key of the user from whom the incoming
@ -465,11 +338,9 @@ const notifyChatsListeners = () => {
const processChats = debounce(() => { const processChats = debounce(() => {
const Streams = require('../streams') const Streams = require('../streams')
const pubToAvatar = Streams.getPubToAvatar() const currentOutgoings = getCurrentOutgoings()
const pubToDn = Streams.getPubToDn()
const pubToLastSeenApp = Streams.getPubToLastSeenApp()
const existingOutgoings = /** @type {[string, Outgoing][]} */ (Object.entries( const existingOutgoings = /** @type {[string, Outgoing][]} */ (Object.entries(
getCurrentOutgoings() currentOutgoings
).filter(([_, o]) => o !== null)) ).filter(([_, o]) => o !== null))
const pubToFeed = Streams.getPubToFeed() const pubToFeed = Streams.getPubToFeed()
@ -477,19 +348,6 @@ const processChats = debounce(() => {
const newChats = [] const newChats = []
for (const [outID, out] of existingOutgoings) { for (const [outID, out] of existingOutgoings) {
if (typeof pubToAvatar[out.with] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onAvatar(() => {}, out.with)()
}
if (typeof pubToDn[out.with] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onDisplayName(() => {}, out.with)()
}
if (typeof pubToLastSeenApp[out.with] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onPubToLastSeenApp(() => {}, out.with)()
}
/** @type {ChatMessage[]} */ /** @type {ChatMessage[]} */
let msgs = Object.entries(out.messages) let msgs = Object.entries(out.messages)
.map(([mid, m]) => ({ .map(([mid, m]) => ({
@ -515,7 +373,7 @@ const processChats = debounce(() => {
messages: msgs, messages: msgs,
recipientAvatar: null, recipientAvatar: null,
recipientDisplayName: null, recipientDisplayName: null,
lastSeenApp: pubToLastSeenApp[out.with] || null lastSeenApp: null
} }
newChats.push(chat) newChats.push(chat)
@ -547,10 +405,7 @@ const onChats = cb => {
if (!onChatsSubbed) { if (!onChatsSubbed) {
const Streams = require('../streams') const Streams = require('../streams')
onOutgoing(processChats) onOutgoing(processChats)
Streams.onAvatar(processChats)
Streams.onDisplayName(processChats)
Streams.onPubToFeed(processChats) Streams.onPubToFeed(processChats)
Streams.onPubToLastSeenApp(processChats)
onChatsSubbed = true onChatsSubbed = true
} }
@ -561,32 +416,6 @@ const onChats = cb => {
} }
} }
/** @type {string|null} */
let currentBio = null
/**
* @param {(bio: string|null) => void} cb
* @param {UserGUNNode} user Pass only for testing purposes.
* @throws {Error} If user hasn't been auth.
* @returns {void}outgoingsListeners.forEach()
*/
const onBio = (cb, user) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
const callb = debounce(cb, DEBOUNCE_WAIT_TIME)
// Initial value if avvatar is undefined in gun
callb(currentBio)
user.get(Key.BIO).on(bio => {
if (typeof bio === 'string' || bio === null) {
currentBio = bio
callb(bio)
}
})
}
/** @type {string|null} */ /** @type {string|null} */
let currentSeedBackup = null let currentSeedBackup = null
@ -617,10 +446,7 @@ const onSeedBackup = (cb, user, SEA) => {
module.exports = { module.exports = {
__onUserToIncoming, __onUserToIncoming,
onAvatar,
onBlacklist,
onCurrentHandshakeAddress, onCurrentHandshakeAddress,
onDisplayName,
onIncomingMessages, onIncomingMessages,
onOutgoing, onOutgoing,
getCurrentOutgoings, getCurrentOutgoings,
@ -628,11 +454,8 @@ module.exports = {
onSimplerSentRequests: require('./onSentReqs').onSentReqs, onSimplerSentRequests: require('./onSentReqs').onSentReqs,
getCurrentSentReqs: require('./onSentReqs').getCurrentSentReqs, getCurrentSentReqs: require('./onSentReqs').getCurrentSentReqs,
getCurrentReceivedReqs: require('./onReceivedReqs').getReceivedReqs, getCurrentReceivedReqs: require('./onReceivedReqs').getReceivedReqs,
onBio,
onSeedBackup, onSeedBackup,
onChats, onChats,
getAvatar,
getDisplayName,
getHandshakeAddress, getHandshakeAddress,
getChats getChats
} }

View file

@ -44,22 +44,11 @@ const react = debounce(() => {
const newReceivedReqsMap = {} const newReceivedReqsMap = {}
const pubToFeed = Streams.getPubToFeed() const pubToFeed = Streams.getPubToFeed()
const pubToAvatar = Streams.getPubToAvatar()
const pubToDn = Streams.getPubToDn()
for (const [id, req] of Object.entries(currAddressData)) { for (const [id, req] of Object.entries(currAddressData)) {
const inContact = Array.isArray(pubToFeed[req.from]) const inContact = Array.isArray(pubToFeed[req.from])
const isDisconnected = pubToFeed[req.from] === 'disconnected' const isDisconnected = pubToFeed[req.from] === 'disconnected'
if (typeof pubToAvatar[req.from] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onAvatar(() => {}, req.from)()
}
if (typeof pubToDn[req.from] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onDisplayName(() => {}, req.from)()
}
if (!inContact && !isDisconnected) { if (!inContact && !isDisconnected) {
newReceivedReqsMap[req.from] = { newReceivedReqsMap[req.from] = {
id, id,
@ -95,7 +84,7 @@ const listenerForAddr = addr => data => {
} }
} }
logger.info('data for address length: ' + size(addr)) logger.info('data for address length: ' + size(currAddressData))
react() react()
} }
@ -133,8 +122,6 @@ const onReceivedReqs = cb => {
} }
}, user) }, user)
Streams.onAvatar(react)
Streams.onDisplayName(react)
Streams.onPubToFeed(react) Streams.onPubToFeed(react)
subbed = true subbed = true

View file

@ -51,10 +51,6 @@ const react = debounce(() => {
// maps a pk to a feed, messages if subbed and pk is pubbing, null / // maps a pk to a feed, messages if subbed and pk is pubbing, null /
// 'disconnected' otherwise // 'disconnected' otherwise
const pubToFeed = Streams.getPubToFeed() const pubToFeed = Streams.getPubToFeed()
// pk to avatar
const pubToAvatar = Streams.getPubToAvatar()
// pk to display name
const pubToDN = Streams.getPubToDn()
logger.info(`pubToLastSentREqID length: ${size(pubToLastSentReqID)}`) logger.info(`pubToLastSentREqID length: ${size(pubToLastSentReqID)}`)
@ -80,18 +76,6 @@ const react = debounce(() => {
// eslint-disable-next-line no-empty-function // eslint-disable-next-line no-empty-function
Streams.onAddresses(() => {}, recipientPub)() Streams.onAddresses(() => {}, recipientPub)()
} }
// no avatar for this pk? let's ask the corresponding stream to sub to
// gun.user(pk).get('avatar')
if (typeof pubToAvatar[recipientPub] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onAvatar(() => {}, recipientPub)()
}
// no display name for this pk? let's ask the corresponding stream to sub to
// gun.user(pk).get('displayName')
if (typeof pubToDN[recipientPub] === 'undefined') {
// eslint-disable-next-line no-empty-function
Streams.onDisplayName(() => {}, recipientPub)()
}
newReqs.push({ newReqs.push({
id: sentReqID, id: sentReqID,
@ -129,8 +113,6 @@ const onSentReqs = cb => {
Streams.onStoredReqs(react) Streams.onStoredReqs(react)
Streams.onLastSentReqIDs(react) Streams.onLastSentReqIDs(react)
Streams.onPubToFeed(react) Streams.onPubToFeed(react)
Streams.onAvatar(react)
Streams.onDisplayName(react)
subbed = true subbed = true
} }

View file

@ -36,7 +36,7 @@ const onAcceptedRequests = (user, SEA) => {
user user
.get(Key.STORED_REQS) .get(Key.STORED_REQS)
.map() .map()
.once(async (storedReq, id) => { .on(async (storedReq, id) => {
logger.info( logger.info(
`------------------------------------\nPROCID:${procid} (used for debugging memory leaks in jobs)\n---------------------------------------` `------------------------------------\nPROCID:${procid} (used for debugging memory leaks in jobs)\n---------------------------------------`
) )

View file

@ -3,99 +3,6 @@ const { Schema, Utils: CommonUtils } = require('shock-common')
const Key = require('../key') const Key = require('../key')
const Utils = require('../utils') const Utils = require('../utils')
/**
* @typedef {Record<string, string|null|undefined>} Avatars
* @typedef {(avatars: Avatars) => void} AvatarListener
*/
/** @type {Avatars} */
const pubToAvatar = {}
const getPubToAvatar = () => pubToAvatar
/** @type {Set<AvatarListener>} */
const avatarListeners = new Set()
const notifyAvatarListeners = () => {
avatarListeners.forEach(l => l(pubToAvatar))
}
/** @type {Set<string>} */
const pubsWithAvatarListeners = new Set()
/**
* @param {AvatarListener} cb
* @param {string=} pub
*/
const onAvatar = (cb, pub) => {
avatarListeners.add(cb)
cb(pubToAvatar)
if (pub && pubsWithAvatarListeners.add(pub)) {
require('../../Mediator')
.getGun()
.user(pub)
.get(Key.PROFILE_BINARY)
.get(Key.AVATAR)
.on(av => {
if (typeof av === 'string' || av === null) {
pubToAvatar[pub] = av || null
} else {
pubToAvatar[pub] = null
}
notifyAvatarListeners()
})
}
return () => {
avatarListeners.delete(cb)
}
}
/**
* @typedef {Record<string, string|null|undefined>} DisplayNames
* @typedef {(avatars: Avatars) => void} DisplayNameListener
*/
/** @type {DisplayNames} */
const pubToDisplayName = {}
const getPubToDn = () => pubToDisplayName
/** @type {Set<DisplayNameListener>} */
const displayNameListeners = new Set()
const notifyDisplayNameListeners = () => {
displayNameListeners.forEach(l => l(pubToDisplayName))
}
/** @type {Set<string>} */
const pubsWithDisplayNameListeners = new Set()
/**
* @param {DisplayNameListener} cb
* @param {string=} pub
*/
const onDisplayName = (cb, pub) => {
displayNameListeners.add(cb)
cb(pubToDisplayName)
if (pub && pubsWithDisplayNameListeners.add(pub)) {
require('../../Mediator')
.getGun()
.user(pub)
.get(Key.PROFILE)
.get(Key.DISPLAY_NAME)
.on(dn => {
if (typeof dn === 'string' || dn === null) {
pubToDisplayName[pub] = dn || null
} else {
pubToDisplayName[pub] = null
}
notifyDisplayNameListeners()
})
}
return () => {
displayNameListeners.delete(cb)
}
}
/** /**
* @typedef {import('shock-common').Schema.StoredRequest} StoredRequest * @typedef {import('shock-common').Schema.StoredRequest} StoredRequest
@ -171,11 +78,6 @@ const onStoredReqs = cb => {
} }
module.exports = { module.exports = {
onAvatar,
getPubToAvatar,
onDisplayName,
getPubToDn,
onPubToIncoming: require('./pubToIncoming').onPubToIncoming, onPubToIncoming: require('./pubToIncoming').onPubToIncoming,
getPubToIncoming: require('./pubToIncoming').getPubToIncoming, getPubToIncoming: require('./pubToIncoming').getPubToIncoming,
setPubToIncoming: require('./pubToIncoming').setPubToIncoming, setPubToIncoming: require('./pubToIncoming').setPubToIncoming,

91
testcript.js Normal file
View file

@ -0,0 +1,91 @@
/**
* @format
*/
// @ts-check
const Gun = require('gun')
require('gun/nts')
require('gun/lib/open')
require('gun/lib/load')
const args = process.argv.slice(2)
const [fileName, alias, pass, method, path] = args
// @ts-expect-error
const gun = /** @type {import('./services/gunDB/contact-api/SimpleGUN').GUNNode} */ (Gun(
{
axe: false,
multicast: false,
peers: ['https://gun.shock.network:8765/gun'],
file: `TESTCRIPT-RADATA/${fileName}`
}
))
const user = gun.user()
/**
* @param {any} data
* @param {string} key
*/
const cb = (data, key) => {
console.log('\n')
console.log(`key: ${key}`)
console.log('\n')
console.log(data)
console.log('\n')
}
;(async () => {
try {
console.log(`Alias: ${alias}`)
console.log(`Pass: ${pass}`)
console.log('\n')
// gun
// .get('handshakeNodes')
// .map()
// .once(cb)
// wait for user data to be received
// await new Promise(res => setTimeout(res, 10000))
const ack = await new Promise(res => {
user.auth(alias, pass, _ack => {
res(_ack)
})
})
if (typeof ack.err === 'string') {
throw new Error(ack.err)
} else if (typeof ack.sea === 'object') {
// clock skew
await new Promise(res => setTimeout(res, 2000))
} else {
throw new Error('Unknown error.')
}
const [root, ...keys] = path.split('.')
let node = (() => {
if (root === 'gun') {
return gun
}
if (root === 'user') {
return user
}
return gun.user(root)
})()
keys.forEach(key => (node = node.get(key)))
if (method === 'once') node.once(cb)
if (method === 'load') node.load(cb)
if (method === 'on') node.on(cb)
if (method === 'map.once') node.map().once(cb)
if (method === 'map.on') node.map().on(cb)
} catch (e) {
console.log(`\nCaught error in app:\n`)
console.log(e)
}
})()