Skip to content

Commit

Permalink
Merge pull request #60 from stakwork/chat-seen
Browse files Browse the repository at this point in the history
Chat seen
  • Loading branch information
Evanfeenstra authored Jul 24, 2020
2 parents ec23478 + 46e5ed3 commit 8e3b70b
Show file tree
Hide file tree
Showing 30 changed files with 195 additions and 119 deletions.
4 changes: 3 additions & 1 deletion api/controllers/contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export const receiveContactKey = async (payload) => {

const owner = await models.Contact.findOne({ where: { isOwner: true }})
const sender = await models.Contact.findOne({ where: { publicKey: sender_pub_key, status: constants.contact_statuses.confirmed }})

console.log("FOUND SENDER",sender&&sender.dataValue)
if (sender_contact_key && sender) {
const objToUpdate:{[k:string]:any} = {contactKey: sender_contact_key}
if(sender_alias) objToUpdate.alias = sender_alias
Expand All @@ -219,6 +219,8 @@ export const receiveContactKey = async (payload) => {
type: 'contact',
response: jsonUtils.contactToJson(sender)
})
} else {
console.log("DID NOT FIND SENDER")
}

helpers.sendContactKeys({
Expand Down
10 changes: 9 additions & 1 deletion api/controllers/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,16 +274,24 @@ export const readMessages = async (req, res) => {

const owner = await models.Contact.findOne({ where: { isOwner: true }})

models.Message.update({ seen: true }, {
await models.Message.update({ seen: true }, {
where: {
sender: {
[Op.ne]: owner.id
},
chatId: chat_id
}
});
const chat = await models.Chat.findOne({ where: { id: chat_id } })
await chat.update({ seen: true });

success(res, {})

sendNotification(chat, '', 'badge')
socket.sendJson({
type: 'chat_seen',
response: jsonUtils.chatToJson(chat)
})
}

export const clearMessages = (req, res) => {
Expand Down
2 changes: 1 addition & 1 deletion api/crypto/rsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function encrypt(key, txt){
arr.forEach((_,i)=>{
const f = crypto.publicEncrypt({
key:pubc,
padding:crypto.constants.RSA_PKCS1_PADDING,
padding:crypto.constants.RSA_PKCS1_PADDING, // RSA_PKCS1_OAEP_PADDING
}, buf.subarray(i*MAX_CHUNK_SIZE,i*MAX_CHUNK_SIZE+MAX_CHUNK_SIZE))
finalBuf = Buffer.concat([finalBuf,f])
})
Expand Down
67 changes: 34 additions & 33 deletions api/hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const checkInviteHub = async (params = {}) => {
//console.log('[hub] checking invites ping')

const inviteStrings = await models.Invite.findAll({ where: { status: { [Op.notIn]: [constants.invite_statuses.complete, constants.invite_statuses.expired] } } }).map(invite => invite.inviteString)
if(inviteStrings.length===0) {
return // skip if no invites
}

fetch(config.hub_api_url + '/invites/check', {
method: 'POST' ,
Expand Down Expand Up @@ -95,10 +98,6 @@ const sendHubCall = (params) => {
body: JSON.stringify(params),
headers: { 'Content-Type': 'application/json' }
})
.then(res => res.json())
.then(json => {
// ?
})
.catch(error => {
console.log('[hub error]', error)
})
Expand All @@ -119,12 +118,8 @@ export function sendInvoice(payReq, amount) {
body: JSON.stringify({invoice:payReq, amount}),
headers: { 'Content-Type': 'application/json' }
})
.then(res => res.json())
.then(json => {
// ?
})
.catch(error => {
console.log('[hub error]', error)
console.log('[hub error]: sendInvoice', error)
})
}

Expand Down Expand Up @@ -193,7 +188,9 @@ const createInviteInHub = (params, onSuccess, onFailure) => {
})
}

const sendNotification = async (chat, name, type) => {
type NotificationType = 'group' | 'badge' | 'invite' | 'message'

const sendNotification = async (chat, name, type:NotificationType) => {

let message = `You have a new message from ${name}`
if(type==='invite'){
Expand All @@ -207,55 +204,58 @@ const sendNotification = async (chat, name, type) => {
message += ` on ${chat.name}`
}

console.log('[send notification]', { chat_id:chat.id, message })

if (chat.isMuted) {
console.log('[send notification] skipping. chat is muted.')
return
}

const owner = await models.Contact.findOne({ where: { isOwner: true }})

if (!owner.deviceId) {
console.log('[send notification] skipping. owner.deviceId not set.')
return
}

const unseenMessages = await models.Message.count({ where: { sender: { [Op.ne]: owner.id }, seen: false } })
const device_id = owner.deviceId

const isIOS = device_id.length===64
const isAndroid = !isIOS

const params:{[k:string]:any} = {device_id}
const notification:{[k:string]:any} = {
chat_id: chat.id,
message,
badge: unseenMessages
sound: ''
}
if(owner.notificationSound) {
notification.sound = owner.notificationSound
if(type!=='badge' && !chat.isMuted) {
notification.message = message
notification.sound = owner.notificationSound || 'default'
} else {
if(isAndroid) return // skip on Android if no actual message
}
params.notification = notification

if(type==='message' && chat.type==constants.chat_types.tribe){
debounce(()=>{
const count = tribeCounts[chat.id]?tribeCounts[chat.id]+' ':''
params.notification.message = `You have ${count}new messages in ${chat.name}`
triggerNotification(params)
params.notification.message = chat.isMuted ? '' : `You have ${count}new messages in ${chat.name}`
finalNotification(owner.id, params)
}, chat.id, 30000)
} else {
triggerNotification(params)
finalNotification(owner.id, params)
}
}

async function finalNotification(ownerID: number, params:{[k:string]:any}){
if(params.notification.message) {
console.log('[send notification]', params.notification)
}
let unseenMessages = await models.Message.count({ where: { sender: { [Op.ne]: ownerID }, seen: false } })
params.notification.badge = unseenMessages
triggerNotification(params)
}

function triggerNotification(params){
function triggerNotification(params:{[k:string]:any}){
fetch("https://hub.sphinx.chat/api/v1/nodes/notify", {
method: 'POST' ,
body: JSON.stringify(params),
headers: { 'Content-Type': 'application/json' }
})
.then(res => res.json())
.then(json => {
// console.log('[hub notification]', json)
})
.catch(error => {
console.log('[hub error]: triggerNotification', error)
})
}

export {
Expand Down Expand Up @@ -287,6 +287,7 @@ function debounce(func, id, delay) {
tribeCounts[id]+=1
bounceTimeouts[id] = setTimeout(() => {
func.apply(context, args)
setTimeout(()=> tribeCounts[id]=0, 15)
// setTimeout(()=> tribeCounts[id]=0, 15)
tribeCounts[id]=0
}, delay)
}
7 changes: 7 additions & 0 deletions api/models/ts/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,11 @@ export default class Chat extends Model<Chat> {
@Column
ownerPubkey: string

@Column({
type: DataType.BOOLEAN,
defaultValue: false,
allowNull: false
})
seen: boolean

}
1 change: 1 addition & 0 deletions api/network/receive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ async function onReceive(payload){
if(payload.chat) {
isTribe = payload.chat.type===constants.chat_types.tribe
chat = await models.Chat.findOne({where:{uuid:payload.chat.uuid}})
if(chat) chat.update({seen:false})
}
if(isTribe) {
const tribeOwnerPubKey = chat && chat.ownerPubkey
Expand Down
8 changes: 4 additions & 4 deletions api/network/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export async function sendMessage(params) {
console.log("KEYSEND ERROR", e)
no = e
}
await sleep(2)
// await sleep(2)
})
if(yes){
if(success) success(yes)
Expand Down Expand Up @@ -164,9 +164,9 @@ async function asyncForEach(array, callback) {
await callback(array[index], index, array);
}
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
// async function sleep(ms) {
// return new Promise(resolve => setTimeout(resolve, ms))
// }

// function urlBase64FromHex(ascii){
// return Buffer.from(ascii,'hex').toString('base64').replace(/\//g, '_').replace(/\+/g, '-')
Expand Down
22 changes: 15 additions & 7 deletions api/utils/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as publicIp from 'public-ip'
import password from '../utils/password'
import {checkTag, checkCommitHash} from '../utils/gitinfo'

const USER_VERSION = 4
const USER_VERSION = 5

const setupDatabase = async () => {
console.log('=> [db] starting setup...')
Expand All @@ -31,6 +31,14 @@ async function setVersion(){
}

async function migrate(){
addTableColumn('sphinx_chats', 'seen', 'BOOLEAN')

try{
await sequelize.query(`CREATE INDEX idx_messages_sender ON sphinx_messages (sender);`)
}catch(e){
console.log(e)
}

addTableColumn('sphinx_contacts', 'notification_sound')

try{
Expand All @@ -49,14 +57,14 @@ CREATE TABLE sphinx_timers (

addTableColumn('sphinx_contacts', 'private_photo', 'BOOLEAN')

addTableColumn('sphinx_media_keys', 'media_type')
addTableColumn('sphinx_media_keys', 'original_muid')
addTableColumn('sphinx_messages', 'original_muid')
// addTableColumn('sphinx_media_keys', 'media_type')
// addTableColumn('sphinx_media_keys', 'original_muid')
// addTableColumn('sphinx_messages', 'original_muid')

addTableColumn('sphinx_messages', 'uuid')
addTableColumn('sphinx_messages', 'reply_uuid')
// addTableColumn('sphinx_messages', 'uuid')
// addTableColumn('sphinx_messages', 'reply_uuid')

addTableColumn('sphinx_media_keys', 'sender', 'BIGINT')
// addTableColumn('sphinx_media_keys', 'sender', 'BIGINT')
}

async function addTableColumn(table:string, column:string, type='TEXT') {
Expand Down
12 changes: 11 additions & 1 deletion api/utils/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@ let io: any
export function connect(server) {
// srvr = new WebSocket.Server({ server, clientTracking:true })

io = socketio(server);
io = socketio(server, {
handlePreflightRequest: (req, res) => {
const headers = {
"Access-Control-Allow-Headers": "Content-Type, Accept, x-user-token, X-Requested-With",
"Access-Control-Allow-Origin": req.headers.origin, //or the specific origin you want to give access to,
"Access-Control-Allow-Credentials": true
};
res.writeHead(200, headers);
res.end();
}
});
io.use(async (socket, next) => {
let userToken = socket.handshake.headers['x-user-token'];
const isValid = await isValidToken(userToken)
Expand Down
14 changes: 4 additions & 10 deletions app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as express from 'express'
import * as bodyParser from 'body-parser'
import * as helmet from 'helmet'
import * as cookieParser from 'cookie-parser'
import * as cors from 'cors'
import * as crypto from 'crypto'
import * as path from 'path'
import {models} from './api/models'
Expand Down Expand Up @@ -59,16 +60,9 @@ async function setupApp(){
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(logger)
app.options('*', (req, res) => res.send(200));
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept');
res.setHeader('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.setHeader('Expires', '-1');
res.setHeader('Pragma', 'no-cache');
next();
});
app.use(cors({
allowedHeaders:['X-Requested-With','Content-Type','Accept','x-user-token']
}))
app.use(cookieParser())
if (env != 'development') {
app.use(authModule);
Expand Down
4 changes: 4 additions & 0 deletions dist/api/controllers/contacts.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8e3b70b

Please sign in to comment.