Browse Source

Merge pull request #46 from stakwork/better-replay

better-tribes
feature/dockerfile-arm v0.9.13
Evan Feenstra 5 years ago
committed by GitHub
parent
commit
5d95336c40
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      api/controllers/chatTribes.ts
  2. 6
      api/controllers/chats.ts
  3. 30
      api/controllers/media.ts
  4. 21
      api/controllers/messages.ts
  5. 6
      api/helpers.ts
  6. 39
      api/hub.ts
  7. 3
      api/models/ts/message.ts
  8. 45
      api/network/modify.ts
  9. 23
      api/network/receive.ts
  10. 11
      dist/api/controllers/chatTribes.js
  11. 2
      dist/api/controllers/chatTribes.js.map
  12. 8
      dist/api/controllers/chats.js
  13. 2
      dist/api/controllers/chats.js.map
  14. 27
      dist/api/controllers/media.js
  15. 2
      dist/api/controllers/media.js.map
  16. 23
      dist/api/controllers/messages.js
  17. 2
      dist/api/controllers/messages.js.map
  18. 6
      dist/api/helpers.js
  19. 2
      dist/api/helpers.js.map
  20. 43
      dist/api/hub.js
  21. 2
      dist/api/hub.js.map
  22. 4
      dist/api/models/ts/message.js
  23. 2
      dist/api/models/ts/message.js.map
  24. 39
      dist/api/network/modify.js
  25. 2
      dist/api/network/modify.js.map
  26. 23
      dist/api/network/receive.js
  27. 2
      dist/api/network/receive.js.map

10
api/controllers/chatTribes.ts

@ -6,6 +6,7 @@ import * as rsa from '../crypto/rsa'
import * as tribes from '../utils/tribes'
import * as path from 'path'
import {personalizeMessage, decryptMessage} from '../utils/msg'
import { Op } from 'sequelize'
const constants = require(path.join(__dirname,'../../config/constants.json'))
@ -150,10 +151,11 @@ async function replayChatHistory(chat, contact) {
return console.log('[tribes] cant replay history')
}
const msgs = await models.Message.findAll({
where:{chatId:chat.id},
order: [['id', 'asc']],
where:{chatId:chat.id, type:{[Op.in]:network.typesToReplay}},
order: [['id', 'desc']],
limit: 40
})
msgs.reverse()
const owner = await models.Contact.findOne({ where: { isOwner: true } })
asyncForEach(msgs, async m=>{
if(!network.typesToReplay.includes(m.type)) return // only for message for now
@ -164,6 +166,7 @@ async function replayChatHistory(chat, contact) {
let content = ''
try {content = JSON.parse(m.remoteMessageContent)} catch(e) {}
const dateString = m.date&&m.date.toISOString()
let mediaKeyMap
let newMediaTerms
if(m.type===constants.message_types.attachment) {
@ -172,7 +175,7 @@ async function replayChatHistory(chat, contact) {
const mediaKey = await models.MediaKey.findOne({where:{
muid, chatId: chat.id,
}})
console.log("FOUND MEDIA KEY!!",mediaKey.dataValues)
// console.log("FOUND MEDIA KEY!!",mediaKey.dataValues)
mediaKeyMap = {chat: mediaKey.key}
newMediaTerms = {muid: mediaKey.muid}
}
@ -182,6 +185,7 @@ async function replayChatHistory(chat, contact) {
...mediaKeyMap && {mediaKey: mediaKeyMap},
...newMediaTerms && {mediaToken: newMediaTerms},
...m.mediaType && {mediaType: m.mediaType},
...dateString && {date: dateString}
})
msg = await decryptMessage(msg, chat)
const data = await personalizeMessage(msg, contact, true)

6
api/controllers/chats.ts

@ -198,7 +198,7 @@ const deleteChat = async (req, res) => {
async function receiveGroupJoin(payload) {
console.log('=> receiveGroupJoin')
const { sender_pub_key, sender_alias, chat_uuid, chat_members, chat_type, isTribeOwner } = await helpers.parseReceiveParams(payload)
const { sender_pub_key, sender_alias, chat_uuid, chat_members, chat_type, isTribeOwner, date_string } = await helpers.parseReceiveParams(payload)
const chat = await models.Chat.findOne({ where: { uuid: chat_uuid } })
if (!chat) return
@ -207,6 +207,7 @@ async function receiveGroupJoin(payload) {
var date = new Date()
date.setMilliseconds(0)
if(date_string) date=new Date(date_string)
let theSender: any = null
const member = chat_members[sender_pub_key]
@ -285,7 +286,7 @@ async function receiveGroupJoin(payload) {
async function receiveGroupLeave(payload) {
console.log('=> receiveGroupLeave')
const { sender_pub_key, chat_uuid, chat_type, sender_alias, isTribeOwner } = await helpers.parseReceiveParams(payload)
const { sender_pub_key, chat_uuid, chat_type, sender_alias, isTribeOwner, date_string } = await helpers.parseReceiveParams(payload)
const chat = await models.Chat.findOne({ where: { uuid: chat_uuid } })
if (!chat) return
@ -317,6 +318,7 @@ async function receiveGroupLeave(payload) {
var date = new Date();
date.setMilliseconds(0)
if(date_string) date=new Date(date_string)
const msg:{[k:string]:any} = {
chatId: chat.id,
type: constants.message_types.group_leave,

30
api/controllers/media.ts

@ -108,6 +108,8 @@ const sendAttachmentMessage = async (req, res) => {
updatedAt: date
})
console.log('saved attachment msg from me',message.id)
saveMediaKeys(muid, media_key_map, chat.id, message.id, mediaType)
const mediaTerms: {[k:string]:any} = {
@ -173,7 +175,6 @@ const purchase = async (req, res) => {
return resUtils.failure(res, e.message)
}
console.log('purchase!')
const owner = await models.Contact.findOne({ where: { isOwner: true }})
const chat = await helpers.findOrCreateChat({
chat_id,
@ -194,7 +195,8 @@ const purchase = async (req, res) => {
})
const msg={
amount, mediaToken:media_token, id:message.id, uuid:message.uuid,
mediaToken:media_token, id:message.id, uuid:message.uuid,
purchaser: owner.id, // for tribe, knows who sent
}
network.sendMessage({
chat: {...chat.dataValues, contactIds:[contact_id]},
@ -218,7 +220,7 @@ const receivePurchase = async (payload) => {
var date = new Date();
date.setMilliseconds(0)
const {owner, sender, chat, amount, mediaToken, msg_uuid, chat_type} = await helpers.parseReceiveParams(payload)
const {owner, sender, chat, amount, mediaToken, msg_uuid, chat_type, skip_payment_processing, purchaser_id} = await helpers.parseReceiveParams(payload)
if(!owner || !sender || !chat) {
return console.log('=> group chat not found!')
}
@ -239,6 +241,14 @@ const receivePurchase = async (payload) => {
response: jsonUtils.messageToJson(message, chat, sender)
})
const isTribe = chat_type===constants.chat_types.tribe
// if sats forwarded from tribe owner, for the >1 time
// dont need to send back token, because admin already has it
if(isTribe && skip_payment_processing) {
return console.log('=> skip payment processing')
}
const muid = mediaToken && mediaToken.split('.').length && mediaToken.split('.')[1]
if(!muid){
return console.log('no muid')
@ -251,8 +261,6 @@ const receivePurchase = async (payload) => {
return console.log('no original message')
}
const isTribe = chat_type===constants.chat_types.tribe
// find mediaKey for who sent
const mediaKey = await models.MediaKey.findOne({where:{
muid, receiver: isTribe?0:sender.id,
@ -305,15 +313,17 @@ const receivePurchase = async (payload) => {
meta: {amt:amount},
pubkey: sender.publicKey,
})
const msgToSend:{[k:string]:any}={
mediaToken: theMediaToken,
mediaKey: mediaKey.key,
mediaType: ogMessage.mediaType,
}
if(purchaser_id) msgToSend.purchaser=purchaser_id
network.sendMessage({
chat: {...chat.dataValues, contactIds:[sender.id]}, // only to sender
sender: owner,
type: constants.message_types.purchase_accept,
message: {
mediaToken: theMediaToken,
mediaKey: mediaKey.key,
mediaType: ogMessage.mediaType,
},
message: msgToSend,
success: async (data) => {
console.log('purchase_accept sent!')
const acceptMsg = await models.Message.create({

21
api/controllers/messages.ts

@ -108,6 +108,7 @@ const sendMessage = async (req, res) => {
chat_id,
remote_text_map,
amount,
reply_uuid,
} = req.body
var date = new Date();
@ -121,7 +122,7 @@ const sendMessage = async (req, res) => {
})
const remoteMessageContent = remote_text_map?JSON.stringify(remote_text_map) : remote_text
const msg={
const msg:{[k:string]:any}={
chatId: chat.id,
uuid: short.generate(),
type: constants.message_types.message,
@ -134,21 +135,24 @@ const sendMessage = async (req, res) => {
createdAt: date,
updatedAt: date,
}
if(reply_uuid) msg.replyUuid=reply_uuid
// console.log(msg)
const message = await models.Message.create(msg)
success(res, jsonUtils.messageToJson(message, chat))
const msgToSend:{[k:string]:any} = {
id: message.id,
uuid: message.uuid,
content: remote_text_map || remote_text || text
}
if(reply_uuid) msgToSend.replyUuid=reply_uuid
network.sendMessage({
chat: chat,
sender: owner,
amount: amount||0,
type: constants.message_types.message,
message: {
id: message.id,
uuid: message.uuid,
content: remote_text_map || remote_text || text
}
message: msgToSend,
})
}
@ -159,12 +163,14 @@ const receiveMessage = async (payload) => {
date.setMilliseconds(0)
const total_spent = 1
const {owner, sender, chat, content, remote_content, msg_id, chat_type, sender_alias, msg_uuid} = await helpers.parseReceiveParams(payload)
const {owner, sender, chat, content, remote_content, msg_id, chat_type, sender_alias, msg_uuid, date_string, reply_uuid} = await helpers.parseReceiveParams(payload)
if(!owner || !sender || !chat) {
return console.log('=> no group chat!')
}
const text = content
if(date_string) date=new Date(date_string)
const msg:{[k:string]:any} = {
chatId: chat.id,
uuid: msg_uuid,
@ -181,6 +187,7 @@ const receiveMessage = async (payload) => {
msg.senderAlias = sender_alias
if(remote_content) msg.remoteMessageContent=remote_content
}
if(reply_uuid) msg.replyUuid = reply_uuid
const message = await models.Message.create(msg)
// console.log('saved message', message.dataValues)

6
api/helpers.ts

@ -150,6 +150,10 @@ async function parseReceiveParams(payload) {
const msg_uuid = dat.message.uuid||''
const mediaKey = dat.message.mediaKey
const mediaType = dat.message.mediaType
const date_string = dat.message.date
const skip_payment_processing = dat.message.skipPaymentProcessing
const reply_uuid = dat.message.replyUuid
const purchaser_id = dat.message.purchaser
const isTribeOwner = dat.isTribeOwner?true:false
const isConversation = !chat_type || (chat_type && chat_type == constants.chat_types.conversation)
@ -172,7 +176,7 @@ async function parseReceiveParams(payload) {
}
chat = await models.Chat.findOne({ where: { uuid: chat_uuid } })
}
return { owner, sender, chat, sender_pub_key, sender_alias, isTribeOwner, chat_uuid, amount, content, mediaToken, mediaKey, mediaType, originalMuid, chat_type, msg_id, chat_members, chat_name, chat_host, chat_key, remote_content, msg_uuid }
return { owner, sender, chat, sender_pub_key, sender_alias, isTribeOwner, chat_uuid, amount, content, mediaToken, mediaKey, mediaType, originalMuid, chat_type, msg_id, chat_members, chat_name, chat_host, chat_key, remote_content, msg_uuid, date_string, reply_uuid, skip_payment_processing, purchaser_id }
}
export {

39
api/hub.ts

@ -232,6 +232,23 @@ const sendNotification = async (chat, name, type) => {
}
}
if(type==='message' && chat.type==constants.chat_types.tribe){
debounce(()=>{
const count = tribeCounts[chat.id]?tribeCounts[chat.id]+' ':''
triggerNotification({
device_id: owner.deviceId,
notification: {
chat_id: chat.id, badge: unseenMessages,
message: `You have ${count}new messages in ${chat.name}`
}
})
}, chat.id, 30000)
} else {
triggerNotification(params)
}
}
function triggerNotification(params){
fetch("https://hub.sphinx.chat/api/v1/nodes/notify", {
method: 'POST' ,
body: JSON.stringify(params),
@ -253,3 +270,25 @@ export {
payInviteInHub,
payInviteInvoice
}
// let inDebounce
// function debounce(func, delay) {
// const context = this
// const args = arguments
// clearTimeout(inDebounce)
// inDebounce = setTimeout(() => func.apply(context, args), delay)
// }
const bounceTimeouts={}
const tribeCounts = {}
function debounce(func, id, delay) {
const context = this
const args = arguments
if(bounceTimeouts[id]) clearTimeout(bounceTimeouts[id])
if(!tribeCounts[id]) tribeCounts[id]=0
tribeCounts[id]+=1
bounceTimeouts[id] = setTimeout(() => {
func.apply(context, args)
setTimeout(()=> tribeCounts[id]=0, 15)
}, delay)
}

3
api/models/ts/message.ts

@ -89,4 +89,7 @@ export default class Message extends Model<Message> {
@Column
originalMuid: string // for tribe, remember the og muid
@Column
replyUuid: string
}

45
api/network/modify.ts

@ -8,7 +8,7 @@ import * as FormData from 'form-data'
import { models } from '../models'
import * as RNCryptor from 'jscryptor'
import {sendMessage} from './send'
import { Op } from 'sequelize'
// import { Op } from 'sequelize'
const constants = require(path.join(__dirname,'../../config/constants.json'))
const msgtypes = constants.message_types
@ -55,17 +55,31 @@ export async function purchaseFromOriginalSender(payload, chat, purchaser){
mediaType:mediaKey.mediaType
}
sendMessage({
chat: {...chat.dataValues, contactIds:[purchaser.id]},
chat: {...chat.dataValues, contactIds:[purchaser.id]}, // the merchant id
sender: owner,
type: constants.message_types.purchase_accept,
message: msg,
success: ()=>{},
failure: ()=>{}
})
// PAY THE OG POSTER HERE!!!
sendMessage({
chat: {...chat.dataValues, contactIds:[mediaKey.sender]},
sender: owner,
type: constants.message_types.purchase,
amount: amount,
message: {
mediaToken: mt,
skipPaymentProcessing: true,
},
success: ()=>{},
failure: ()=>{}
})
} else {
const ogmsg = await models.Message.findOne({where:{chatId:chat.id,mediaToken:mt}})
if(!ogmsg) return
// purchase it from creator (send "purchase")
const msg={amount, mediaToken:mt}
const msg={mediaToken:mt,purchaser:purchaser.id}
sendMessage({
chat: {...chat.dataValues, contactIds:[ogmsg.sender]},
sender: {
@ -86,6 +100,7 @@ export async function sendFinalMemeIfFirstPurchaser(payload, chat, sender){
const mt = payload.message && payload.message.mediaToken
const typ = payload.message && payload.message.mediaType
const purchaserID = payload.message && payload.message.purchaser
if(!mt) return
const muid = mt && mt.split('.').length && mt.split('.')[1]
if(!muid) return
@ -93,13 +108,23 @@ export async function sendFinalMemeIfFirstPurchaser(payload, chat, sender){
const existingMediaKey = await models.MediaKey.findOne({where:{muid}})
if(existingMediaKey) return // no need, its already been sent
const host = mt.split('.')[0]
const ogPurchaseMessage = await models.Message.findOne({where:{
mediaToken: {[Op.like]: `${host}.${muid}%`},
type: msgtypes.purchase,
// const host = mt.split('.')[0]
const terms = parseLDAT(mt)
const ogPurchaser = await models.Contact.findOne({where:{
id: purchaserID
}})
const termsAndKey = await downloadAndUploadAndSaveReturningTermsAndKey(payload,chat,sender,ogPurchaseMessage.amount)
if(!ogPurchaser) return
const amt = (terms.meta&&terms.meta.amt)||0
// const ogPurchaseMessage = await models.Message.findOne({where:{
// mediaToken: {[Op.like]: `${host}.${muid}%`},
// type: msgtypes.purchase,
// }})
const termsAndKey = await downloadAndUploadAndSaveReturningTermsAndKey(payload,chat,sender,amt)
// send it to the purchaser
const owner = await models.Contact.findOne({where: {isOwner:true}})
@ -110,7 +135,7 @@ export async function sendFinalMemeIfFirstPurchaser(payload, chat, sender){
},
chat:{
...chat.dataValues,
contactIds:[ogPurchaseMessage.sender],
contactIds:[ogPurchaser.id],
},
type:msgtypes.purchase_accept,
message:{
@ -201,7 +226,7 @@ export async function downloadAndUploadAndSaveReturningTermsAndKey(payload, chat
key:encKey,
messageId: (payload.message&&payload.message.id)||0,
receiver: 0,
sender: sender.id, // the og sender
sender: sender.id, // the og sender (merchant) who is sending the completed media token
createdAt: date,
originalMuid: ogmuid,
mediaType:typ,

23
api/network/receive.ts

@ -63,25 +63,22 @@ async function onReceive(payload){
}
if(isTribeOwner && payload.type===msgtypes.purchase) {
const mt = payload.message.mediaToken
const myMediaMessage = await models.Message.findOne({ where:{
mediaToken: mt, sender: 1, type:msgtypes.attachment
const host = mt && mt.split('.').length && mt.split('.')[0]
const muid = mt && mt.split('.').length && mt.split('.')[1]
const myAttachmentMessage = await models.Message.findOne({where:{
mediaToken: {[Op.like]: `${host}.${muid}%`},
type:msgtypes.attachment, sender:1,
}})
if(!myMediaMessage) { // someone else's attachment
if(!myAttachmentMessage) { // someone else's attachment
const senderContact = await models.Contact.findOne({where:{publicKey:payload.sender.pub_key}})
purchaseFromOriginalSender(payload, chat, senderContact)
// we do pass thru, to store... so that we know who the og purchaser was
doAction = false
}
}
if(isTribeOwner && payload.type===msgtypes.purchase_accept) {
const mt = payload.message.mediaToken
const host = mt && mt.split('.').length && mt.split('.')[0]
const muid = mt && mt.split('.').length && mt.split('.')[1]
const ogPurchaseMessage = await models.Message.findOne({where:{
mediaToken: {[Op.like]: `${host}.${muid}%`},
type: msgtypes.purchase,
sender: 1,
}})
if(!ogPurchaseMessage) { // for someone else
const purchaserID = payload.message&&payload.message.purchaser
const iAmPurchaser = purchaserID&&purchaserID===1
if(!iAmPurchaser) {
const senderContact = await models.Contact.findOne({where:{publicKey:payload.sender.pub_key}})
sendFinalMemeIfFirstPurchaser(payload, chat, senderContact)
doAction = false // skip this! we dont need it

11
dist/api/controllers/chatTribes.js

@ -17,6 +17,7 @@ const rsa = require("../crypto/rsa");
const tribes = require("../utils/tribes");
const path = require("path");
const msg_1 = require("../utils/msg");
const sequelize_1 = require("sequelize");
const constants = require(path.join(__dirname, '../../config/constants.json'));
function joinTribe(req, res) {
return __awaiter(this, void 0, void 0, function* () {
@ -148,10 +149,11 @@ function replayChatHistory(chat, contact) {
return console.log('[tribes] cant replay history');
}
const msgs = yield models_1.models.Message.findAll({
where: { chatId: chat.id },
order: [['id', 'asc']],
where: { chatId: chat.id, type: { [sequelize_1.Op.in]: network.typesToReplay } },
order: [['id', 'desc']],
limit: 40
});
msgs.reverse();
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
asyncForEach(msgs, (m) => __awaiter(this, void 0, void 0, function* () {
if (!network.typesToReplay.includes(m.type))
@ -162,6 +164,7 @@ function replayChatHistory(chat, contact) {
content = JSON.parse(m.remoteMessageContent);
}
catch (e) { }
const dateString = m.date && m.date.toISOString();
let mediaKeyMap;
let newMediaTerms;
if (m.type === constants.message_types.attachment) {
@ -170,12 +173,12 @@ function replayChatHistory(chat, contact) {
const mediaKey = yield models_1.models.MediaKey.findOne({ where: {
muid, chatId: chat.id,
} });
console.log("FOUND MEDIA KEY!!", mediaKey.dataValues);
// console.log("FOUND MEDIA KEY!!",mediaKey.dataValues)
mediaKeyMap = { chat: mediaKey.key };
newMediaTerms = { muid: mediaKey.muid };
}
}
let msg = network.newmsg(m.type, chat, sender, Object.assign(Object.assign(Object.assign({ content }, mediaKeyMap && { mediaKey: mediaKeyMap }), newMediaTerms && { mediaToken: newMediaTerms }), m.mediaType && { mediaType: m.mediaType }));
let msg = network.newmsg(m.type, chat, sender, Object.assign(Object.assign(Object.assign(Object.assign({ content }, mediaKeyMap && { mediaKey: mediaKeyMap }), newMediaTerms && { mediaToken: newMediaTerms }), m.mediaType && { mediaType: m.mediaType }), dateString && { date: dateString }));
msg = yield msg_1.decryptMessage(msg, chat);
const data = yield msg_1.personalizeMessage(msg, contact, true);
const mqttTopic = `${contact.publicKey}/${chat.uuid}`;

2
dist/api/controllers/chatTribes.js.map

File diff suppressed because one or more lines are too long

8
dist/api/controllers/chats.js

@ -192,13 +192,15 @@ exports.deleteChat = deleteChat;
function receiveGroupJoin(payload) {
return __awaiter(this, void 0, void 0, function* () {
console.log('=> receiveGroupJoin');
const { sender_pub_key, sender_alias, chat_uuid, chat_members, chat_type, isTribeOwner } = yield helpers.parseReceiveParams(payload);
const { sender_pub_key, sender_alias, chat_uuid, chat_members, chat_type, isTribeOwner, date_string } = yield helpers.parseReceiveParams(payload);
const chat = yield models_1.models.Chat.findOne({ where: { uuid: chat_uuid } });
if (!chat)
return;
const isTribe = chat_type === constants.chat_types.tribe;
var date = new Date();
date.setMilliseconds(0);
if (date_string)
date = new Date(date_string);
let theSender = null;
const member = chat_members[sender_pub_key];
const senderAlias = sender_alias || (member && member.alias) || 'Unknown';
@ -276,7 +278,7 @@ exports.receiveGroupJoin = receiveGroupJoin;
function receiveGroupLeave(payload) {
return __awaiter(this, void 0, void 0, function* () {
console.log('=> receiveGroupLeave');
const { sender_pub_key, chat_uuid, chat_type, sender_alias, isTribeOwner } = yield helpers.parseReceiveParams(payload);
const { sender_pub_key, chat_uuid, chat_type, sender_alias, isTribeOwner, date_string } = yield helpers.parseReceiveParams(payload);
const chat = yield models_1.models.Chat.findOne({ where: { uuid: chat_uuid } });
if (!chat)
return;
@ -305,6 +307,8 @@ function receiveGroupLeave(payload) {
}
var date = new Date();
date.setMilliseconds(0);
if (date_string)
date = new Date(date_string);
const msg = {
chatId: chat.id,
type: constants.message_types.group_leave,

2
dist/api/controllers/chats.js.map

File diff suppressed because one or more lines are too long

27
dist/api/controllers/media.js

@ -96,6 +96,7 @@ const sendAttachmentMessage = (req, res) => __awaiter(void 0, void 0, void 0, fu
createdAt: date,
updatedAt: date
});
console.log('saved attachment msg from me', message.id);
saveMediaKeys(muid, media_key_map, chat.id, message.id, mediaType);
const mediaTerms = {
muid, ttl: TTL,
@ -153,7 +154,6 @@ const purchase = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
catch (e) {
return resUtils.failure(res, e.message);
}
console.log('purchase!');
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
const chat = yield helpers.findOrCreateChat({
chat_id,
@ -172,7 +172,8 @@ const purchase = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
updatedAt: date
});
const msg = {
amount, mediaToken: media_token, id: message.id, uuid: message.uuid,
mediaToken: media_token, id: message.id, uuid: message.uuid,
purchaser: owner.id,
};
network.sendMessage({
chat: Object.assign(Object.assign({}, chat.dataValues), { contactIds: [contact_id] }),
@ -193,7 +194,7 @@ const receivePurchase = (payload) => __awaiter(void 0, void 0, void 0, function*
console.log('=> received purchase', { payload });
var date = new Date();
date.setMilliseconds(0);
const { owner, sender, chat, amount, mediaToken, msg_uuid, chat_type } = yield helpers.parseReceiveParams(payload);
const { owner, sender, chat, amount, mediaToken, msg_uuid, chat_type, skip_payment_processing, purchaser_id } = yield helpers.parseReceiveParams(payload);
if (!owner || !sender || !chat) {
return console.log('=> group chat not found!');
}
@ -212,6 +213,12 @@ const receivePurchase = (payload) => __awaiter(void 0, void 0, void 0, function*
type: 'purchase',
response: jsonUtils.messageToJson(message, chat, sender)
});
const isTribe = chat_type === constants.chat_types.tribe;
// if sats forwarded from tribe owner, for the >1 time
// dont need to send back token, because admin already has it
if (isTribe && skip_payment_processing) {
return console.log('=> skip payment processing');
}
const muid = mediaToken && mediaToken.split('.').length && mediaToken.split('.')[1];
if (!muid) {
return console.log('no muid');
@ -222,7 +229,6 @@ const receivePurchase = (payload) => __awaiter(void 0, void 0, void 0, function*
if (!ogMessage) {
return console.log('no original message');
}
const isTribe = chat_type === constants.chat_types.tribe;
// find mediaKey for who sent
const mediaKey = yield models_1.models.MediaKey.findOne({ where: {
muid, receiver: isTribe ? 0 : sender.id,
@ -275,15 +281,18 @@ const receivePurchase = (payload) => __awaiter(void 0, void 0, void 0, function*
meta: { amt: amount },
pubkey: sender.publicKey,
});
const msgToSend = {
mediaToken: theMediaToken,
mediaKey: mediaKey.key,
mediaType: ogMessage.mediaType,
};
if (purchaser_id)
msgToSend.purchaser = purchaser_id;
network.sendMessage({
chat: Object.assign(Object.assign({}, chat.dataValues), { contactIds: [sender.id] }),
sender: owner,
type: constants.message_types.purchase_accept,
message: {
mediaToken: theMediaToken,
mediaKey: mediaKey.key,
mediaType: ogMessage.mediaType,
},
message: msgToSend,
success: (data) => __awaiter(void 0, void 0, void 0, function* () {
console.log('purchase_accept sent!');
const acceptMsg = yield models_1.models.Message.create({

2
dist/api/controllers/media.js.map

File diff suppressed because one or more lines are too long

23
dist/api/controllers/messages.js

@ -98,7 +98,7 @@ const sendMessage = (req, res) => __awaiter(void 0, void 0, void 0, function* ()
// } catch(e) {
// return failure(res, e.message)
// }
const { contact_id, text, remote_text, chat_id, remote_text_map, amount, } = req.body;
const { contact_id, text, remote_text, chat_id, remote_text_map, amount, reply_uuid, } = req.body;
var date = new Date();
date.setMilliseconds(0);
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
@ -121,19 +121,24 @@ const sendMessage = (req, res) => __awaiter(void 0, void 0, void 0, function* ()
createdAt: date,
updatedAt: date,
};
if (reply_uuid)
msg.replyUuid = reply_uuid;
// console.log(msg)
const message = yield models_1.models.Message.create(msg);
res_1.success(res, jsonUtils.messageToJson(message, chat));
const msgToSend = {
id: message.id,
uuid: message.uuid,
content: remote_text_map || remote_text || text
};
if (reply_uuid)
msgToSend.replyUuid = reply_uuid;
network.sendMessage({
chat: chat,
sender: owner,
amount: amount || 0,
type: constants.message_types.message,
message: {
id: message.id,
uuid: message.uuid,
content: remote_text_map || remote_text || text
}
message: msgToSend,
});
});
exports.sendMessage = sendMessage;
@ -142,11 +147,13 @@ const receiveMessage = (payload) => __awaiter(void 0, void 0, void 0, function*
var date = new Date();
date.setMilliseconds(0);
const total_spent = 1;
const { owner, sender, chat, content, remote_content, msg_id, chat_type, sender_alias, msg_uuid } = yield helpers.parseReceiveParams(payload);
const { owner, sender, chat, content, remote_content, msg_id, chat_type, sender_alias, msg_uuid, date_string, reply_uuid } = yield helpers.parseReceiveParams(payload);
if (!owner || !sender || !chat) {
return console.log('=> no group chat!');
}
const text = content;
if (date_string)
date = new Date(date_string);
const msg = {
chatId: chat.id,
uuid: msg_uuid,
@ -164,6 +171,8 @@ const receiveMessage = (payload) => __awaiter(void 0, void 0, void 0, function*
if (remote_content)
msg.remoteMessageContent = remote_content;
}
if (reply_uuid)
msg.replyUuid = reply_uuid;
const message = yield models_1.models.Message.create(msg);
// console.log('saved message', message.dataValues)
socket.sendJson({

2
dist/api/controllers/messages.js.map

File diff suppressed because one or more lines are too long

6
dist/api/helpers.js

@ -166,6 +166,10 @@ function parseReceiveParams(payload) {
const msg_uuid = dat.message.uuid || '';
const mediaKey = dat.message.mediaKey;
const mediaType = dat.message.mediaType;
const date_string = dat.message.date;
const skip_payment_processing = dat.message.skipPaymentProcessing;
const reply_uuid = dat.message.replyUuid;
const purchaser_id = dat.message.purchaser;
const isTribeOwner = dat.isTribeOwner ? true : false;
const isConversation = !chat_type || (chat_type && chat_type == constants.chat_types.conversation);
let sender;
@ -186,7 +190,7 @@ function parseReceiveParams(payload) {
}
chat = yield models_1.models.Chat.findOne({ where: { uuid: chat_uuid } });
}
return { owner, sender, chat, sender_pub_key, sender_alias, isTribeOwner, chat_uuid, amount, content, mediaToken, mediaKey, mediaType, originalMuid, chat_type, msg_id, chat_members, chat_name, chat_host, chat_key, remote_content, msg_uuid };
return { owner, sender, chat, sender_pub_key, sender_alias, isTribeOwner, chat_uuid, amount, content, mediaToken, mediaKey, mediaType, originalMuid, chat_type, msg_id, chat_members, chat_name, chat_host, chat_key, remote_content, msg_uuid, date_string, reply_uuid, skip_payment_processing, purchaser_id };
});
}
exports.parseReceiveParams = parseReceiveParams;

2
dist/api/helpers.js.map

File diff suppressed because one or more lines are too long

43
dist/api/hub.js

@ -222,6 +222,24 @@ const sendNotification = (chat, name, type) => __awaiter(void 0, void 0, void 0,
badge: unseenMessages
}
};
if (type === 'message' && chat.type == constants.chat_types.tribe) {
debounce(() => {
const count = tribeCounts[chat.id] ? tribeCounts[chat.id] + ' ' : '';
triggerNotification({
device_id: owner.deviceId,
notification: {
chat_id: chat.id, badge: unseenMessages,
message: `You have ${count}new messages in ${chat.name}`
}
});
}, chat.id, 30000);
}
else {
triggerNotification(params);
}
});
exports.sendNotification = sendNotification;
function triggerNotification(params) {
fetch("https://hub.sphinx.chat/api/v1/nodes/notify", {
method: 'POST',
body: JSON.stringify(params),
@ -231,6 +249,27 @@ const sendNotification = (chat, name, type) => __awaiter(void 0, void 0, void 0,
.then(json => {
// console.log('[hub notification]', json)
});
});
exports.sendNotification = sendNotification;
}
// let inDebounce
// function debounce(func, delay) {
// const context = this
// const args = arguments
// clearTimeout(inDebounce)
// inDebounce = setTimeout(() => func.apply(context, args), delay)
// }
const bounceTimeouts = {};
const tribeCounts = {};
function debounce(func, id, delay) {
const context = this;
const args = arguments;
if (bounceTimeouts[id])
clearTimeout(bounceTimeouts[id]);
if (!tribeCounts[id])
tribeCounts[id] = 0;
tribeCounts[id] += 1;
bounceTimeouts[id] = setTimeout(() => {
func.apply(context, args);
setTimeout(() => tribeCounts[id] = 0, 15);
}, delay);
}
//# sourceMappingURL=hub.js.map

2
dist/api/hub.js.map

File diff suppressed because one or more lines are too long

4
dist/api/models/ts/message.js

@ -125,6 +125,10 @@ __decorate([
sequelize_typescript_1.Column,
__metadata("design:type", String)
], Message.prototype, "originalMuid", void 0);
__decorate([
sequelize_typescript_1.Column,
__metadata("design:type", String)
], Message.prototype, "replyUuid", void 0);
Message = __decorate([
sequelize_typescript_1.Table({ tableName: 'sphinx_messages', underscored: true })
], Message);

2
dist/api/models/ts/message.js.map

@ -1 +1 @@
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../../api/models/ts/message.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,+DAAsE;AAGtE,IAAqB,OAAO,GAA5B,MAAqB,OAAQ,SAAQ,4BAAc;CAwFlD,CAAA;AAhFC;IANC,6BAAM,CAAC;QACN,IAAI,EAAE,+BAAQ,CAAC,MAAM;QACrB,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,IAAI;QACZ,aAAa,EAAE,IAAI;KACpB,CAAC;;mCACQ;AAGV;IADC,6BAAM;;qCACK;AAGZ;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;uCACV;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;qCACZ;AAGZ;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;uCACV;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;yCACR;AAGhB;IADC,6BAAM,CAAC,+BAAQ,CAAC,OAAO,CAAC;;uCACX;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,OAAO,CAAC;;2CACP;AAGlB;IADC,6BAAM;;4CACY;AAGnB;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;+CACA;AAGtB;IADC,6BAAM;8BACD,IAAI;qCAAA;AAGV;IADC,6BAAM;8BACS,IAAI;+CAAA;AAGpB;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;+CACA;AAGtB;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;qDACM;AAG5B;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;uCACV;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;0CACL;AAGjB;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;yCACR;AAGhB;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;+CACF;AAGtB;IADC,6BAAM;;yCACS;AAGhB;IADC,6BAAM;;0CACU;AAGjB;IADC,6BAAM;;2CACW;AAOlB;IALC,6BAAM,CAAC;QACN,IAAI,EAAE,+BAAQ,CAAC,OAAO;QACtB,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,KAAK;KACjB,CAAC;;qCACW;AAGb;IADC,6BAAM;8BACI,IAAI;0CAAA;AAGf;IADC,6BAAM;8BACI,IAAI;0CAAA;AAGf;IADC,6BAAM;;4CACY;AAGnB;IADC,6BAAM;;6CACa;AAvFD,OAAO;IAD3B,4BAAK,CAAC,EAAC,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,IAAI,EAAC,CAAC;GACpC,OAAO,CAwF3B;kBAxFoB,OAAO"}
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../../api/models/ts/message.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,+DAAsE;AAGtE,IAAqB,OAAO,GAA5B,MAAqB,OAAQ,SAAQ,4BAAc;CA2FlD,CAAA;AAnFC;IANC,6BAAM,CAAC;QACN,IAAI,EAAE,+BAAQ,CAAC,MAAM;QACrB,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,IAAI;QACZ,aAAa,EAAE,IAAI;KACpB,CAAC;;mCACQ;AAGV;IADC,6BAAM;;qCACK;AAGZ;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;uCACV;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;qCACZ;AAGZ;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;uCACV;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;yCACR;AAGhB;IADC,6BAAM,CAAC,+BAAQ,CAAC,OAAO,CAAC;;uCACX;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,OAAO,CAAC;;2CACP;AAGlB;IADC,6BAAM;;4CACY;AAGnB;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;+CACA;AAGtB;IADC,6BAAM;8BACD,IAAI;qCAAA;AAGV;IADC,6BAAM;8BACS,IAAI;+CAAA;AAGpB;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;+CACA;AAGtB;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;qDACM;AAG5B;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;uCACV;AAGd;IADC,6BAAM,CAAC,+BAAQ,CAAC,IAAI,CAAC;;0CACL;AAGjB;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;yCACR;AAGhB;IADC,6BAAM,CAAC,+BAAQ,CAAC,MAAM,CAAC;;+CACF;AAGtB;IADC,6BAAM;;yCACS;AAGhB;IADC,6BAAM;;0CACU;AAGjB;IADC,6BAAM;;2CACW;AAOlB;IALC,6BAAM,CAAC;QACN,IAAI,EAAE,+BAAQ,CAAC,OAAO;QACtB,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,KAAK;KACjB,CAAC;;qCACW;AAGb;IADC,6BAAM;8BACI,IAAI;0CAAA;AAGf;IADC,6BAAM;8BACI,IAAI;0CAAA;AAGf;IADC,6BAAM;;4CACY;AAGnB;IADC,6BAAM;;6CACa;AAGpB;IADC,6BAAM;;0CACU;AA1FE,OAAO;IAD3B,4BAAK,CAAC,EAAC,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,IAAI,EAAC,CAAC;GACpC,OAAO,CA2F3B;kBA3FoB,OAAO"}

39
dist/api/network/modify.js

@ -19,7 +19,7 @@ const FormData = require("form-data");
const models_1 = require("../models");
const RNCryptor = require("jscryptor");
const send_1 = require("./send");
const sequelize_1 = require("sequelize");
// import { Op } from 'sequelize'
const constants = require(path.join(__dirname, '../../config/constants.json'));
const msgtypes = constants.message_types;
function modifyPayloadAndSaveMediaKey(payload, chat, sender) {
@ -74,11 +74,26 @@ function purchaseFromOriginalSender(payload, chat, purchaser) {
success: () => { },
failure: () => { }
});
// PAY THE OG POSTER HERE!!!
send_1.sendMessage({
chat: Object.assign(Object.assign({}, chat.dataValues), { contactIds: [mediaKey.sender] }),
sender: owner,
type: constants.message_types.purchase,
amount: amount,
message: {
mediaToken: mt,
skipPaymentProcessing: true,
},
success: () => { },
failure: () => { }
});
}
else {
const ogmsg = yield models_1.models.Message.findOne({ where: { chatId: chat.id, mediaToken: mt } });
if (!ogmsg)
return;
// purchase it from creator (send "purchase")
const msg = { amount, mediaToken: mt };
const msg = { mediaToken: mt, purchaser: purchaser.id };
send_1.sendMessage({
chat: Object.assign(Object.assign({}, chat.dataValues), { contactIds: [ogmsg.sender] }),
sender: Object.assign(Object.assign({}, owner.dataValues), purchaser && purchaser.alias && { alias: purchaser.alias }),
@ -98,6 +113,7 @@ function sendFinalMemeIfFirstPurchaser(payload, chat, sender) {
return;
const mt = payload.message && payload.message.mediaToken;
const typ = payload.message && payload.message.mediaType;
const purchaserID = payload.message && payload.message.purchaser;
if (!mt)
return;
const muid = mt && mt.split('.').length && mt.split('.')[1];
@ -106,17 +122,24 @@ function sendFinalMemeIfFirstPurchaser(payload, chat, sender) {
const existingMediaKey = yield models_1.models.MediaKey.findOne({ where: { muid } });
if (existingMediaKey)
return; // no need, its already been sent
const host = mt.split('.')[0];
const ogPurchaseMessage = yield models_1.models.Message.findOne({ where: {
mediaToken: { [sequelize_1.Op.like]: `${host}.${muid}%` },
type: msgtypes.purchase,
// const host = mt.split('.')[0]
const terms = ldat_1.parseLDAT(mt);
const ogPurchaser = yield models_1.models.Contact.findOne({ where: {
id: purchaserID
} });
const termsAndKey = yield downloadAndUploadAndSaveReturningTermsAndKey(payload, chat, sender, ogPurchaseMessage.amount);
if (!ogPurchaser)
return;
const amt = (terms.meta && terms.meta.amt) || 0;
// const ogPurchaseMessage = await models.Message.findOne({where:{
// mediaToken: {[Op.like]: `${host}.${muid}%`},
// type: msgtypes.purchase,
// }})
const termsAndKey = yield downloadAndUploadAndSaveReturningTermsAndKey(payload, chat, sender, amt);
// send it to the purchaser
const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
send_1.sendMessage({
sender: Object.assign(Object.assign({}, owner.dataValues), sender && sender.alias && { alias: sender.alias }),
chat: Object.assign(Object.assign({}, chat.dataValues), { contactIds: [ogPurchaseMessage.sender] }),
chat: Object.assign(Object.assign({}, chat.dataValues), { contactIds: [ogPurchaser.id] }),
type: msgtypes.purchase_accept,
message: Object.assign(Object.assign({}, termsAndKey), { mediaType: typ, originalMuid: muid }),
success: () => { },

2
dist/api/network/modify.js.map

File diff suppressed because one or more lines are too long

23
dist/api/network/receive.js

@ -79,25 +79,22 @@ function onReceive(payload) {
}
if (isTribeOwner && payload.type === msgtypes.purchase) {
const mt = payload.message.mediaToken;
const myMediaMessage = yield models_1.models.Message.findOne({ where: {
mediaToken: mt, sender: 1, type: msgtypes.attachment
const host = mt && mt.split('.').length && mt.split('.')[0];
const muid = mt && mt.split('.').length && mt.split('.')[1];
const myAttachmentMessage = yield models_1.models.Message.findOne({ where: {
mediaToken: { [sequelize_1.Op.like]: `${host}.${muid}%` },
type: msgtypes.attachment, sender: 1,
} });
if (!myMediaMessage) { // someone else's attachment
if (!myAttachmentMessage) { // someone else's attachment
const senderContact = yield models_1.models.Contact.findOne({ where: { publicKey: payload.sender.pub_key } });
modify_1.purchaseFromOriginalSender(payload, chat, senderContact);
// we do pass thru, to store... so that we know who the og purchaser was
doAction = false;
}
}
if (isTribeOwner && payload.type === msgtypes.purchase_accept) {
const mt = payload.message.mediaToken;
const host = mt && mt.split('.').length && mt.split('.')[0];
const muid = mt && mt.split('.').length && mt.split('.')[1];
const ogPurchaseMessage = yield models_1.models.Message.findOne({ where: {
mediaToken: { [sequelize_1.Op.like]: `${host}.${muid}%` },
type: msgtypes.purchase,
sender: 1,
} });
if (!ogPurchaseMessage) { // for someone else
const purchaserID = payload.message && payload.message.purchaser;
const iAmPurchaser = purchaserID && purchaserID === 1;
if (!iAmPurchaser) {
const senderContact = yield models_1.models.Contact.findOne({ where: { publicKey: payload.sender.pub_key } });
modify_1.sendFinalMemeIfFirstPurchaser(payload, chat, senderContact);
doAction = false; // skip this! we dont need it

2
dist/api/network/receive.js.map

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save