Skip to content

feat/push2 web #770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,091 changes: 869 additions & 1,222 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"ed2curve": "^0.3.0",
"emoji-mart": "^5.6.0",
"file-saver": "^2.0.5",
"firebase": "^10.14.1",
"hdkey": "^2.1.0",
"https-browserify": "^1.0.0",
"i": "^0.3.7",
Expand Down
87 changes: 74 additions & 13 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, getCurrentInstance, ref } from 'vue'
import { computed, watch, onBeforeUnmount, onMounted, getCurrentInstance, ref } from 'vue'
import dayjs from 'dayjs'
import WarningOnAddressesDialog from '@/components/WarningOnAddressesDialog.vue'
import UploadAttachmentExitPrompt from '@/components/UploadAttachmentExitPrompt.vue'
Expand All @@ -19,32 +19,62 @@ import { ThemeName } from './plugins/vuetify'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'

import { fcm } from './firebase'
import { getToken } from 'firebase/messaging'
import { VAPID_KEY, notificationType } from '@/lib/constants'

const store = useStore()
const isSnackbarShowing = computed(() => store.state.snackbar.show)

const showWarningOnAddressesDialog = ref(false)

const notifications = ref<Notifications | null>(null)
const isNotificationsAllowed = computed(() => {
return store.state.options.isAllowNotifications
})
const isBackgroundFetchNotification = computed(() => {
console.log(
'🚀 ~ App.vue:36 ~ isBackgroundFetchNotification ~ isNotificationsAllowed.value:',
isNotificationsAllowed.value
)
return (
isNotificationsAllowed.value &&
store.state.options.allowNotificationType === notificationType['Background Fetch']
)
})
const isPushNotification = computed(() => {
console.log(
'🚀 ~ App.vue:39 ~ isPushNotification ~ isNotificationsAllowed.value :',
isNotificationsAllowed.value
)
return (
isNotificationsAllowed.value &&
store.state.options.allowNotificationType === notificationType['Push']
)
})
const myPK = computed(() => {
return store.getters.getMyPK
})

const themeName = computed(() => {
return store.state.options.darkTheme ? ThemeName.Dark : ThemeName.Light
})

const { locale } = useI18n()

onMounted(() => {
const instance = getCurrentInstance()

if (instance) {
const notifications = new Notifications(instance.proxy)
notifications.start()
watch(myPK, (newVal, oldVal) => {
if (newVal && !oldVal) {
const channel = new BroadcastChannel('adm_notifications')
channel.postMessage({ isCheckPK: true })
channel.onmessage = async (event) => {
const data = event.data
if (data && data.isNoPrivateKey) {
const privateKey = newVal
if (privateKey) channel.postMessage({ privateKey })
}
}
Comment on lines +63 to +73
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a little over engineering. Did you try just watching the value of store.state.passphrase from Vuex?

watch(() => store.state.passphrase, () => {
  channel.postMessage(passphrase)
})

Note: You can retrieve the privateKey and publicKey from passphrase.

}
})

onBeforeUnmount(() => {
notifications.value?.stop()
store.dispatch('stopInterval')
})
const { locale } = useI18n()

const onKeydownHandler = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
Expand All @@ -66,15 +96,46 @@ const setLocale = () => {
dayjs.locale(localeFromStorage)
}

const registerCustomWorker = async () => {
try {
const worker = await navigator.serviceWorker.register(
import.meta.env.MODE === 'production' ? '/firebase-messagin-sw.js' : '/dev-sw.js?dev-sw',
{
type: import.meta.env.MODE === 'production' ? 'classic' : 'module'
}
)
const token = await getToken(fcm, {
vapidKey: VAPID_KEY,
serviceWorkerRegistration: worker
})
console.log('🚀 107 ~ registerCustomWorker ~ token:', token)
} catch (error) {
console.log('🚀 125 ~ registerCustomWorker ~ error:', error)
}
}

onMounted(() => {
if (isBackgroundFetchNotification.value) {
const instance = getCurrentInstance()

if (instance) {
const notifications = new Notifications(instance.proxy)
notifications.start()
}
}

window.addEventListener('keydown', onKeydownHandler, true)
})

onBeforeUnmount(() => {
notifications.value?.stop()
store.dispatch('stopInterval')

window.removeEventListener('keydown', onKeydownHandler, true)
})

setLocale()
if (isPushNotification.value) registerCustomWorker()
</script>

<style lang="scss" scoped>
Expand Down
62 changes: 62 additions & 0 deletions src/firebase-messaging-sw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* eslint-disable */

console.log('custom sw ts from src')

const swSelf = globalThis as unknown as ServiceWorkerGlobalScope

swSelf.addEventListener('install', (event) => {
event.waitUntil(swSelf.skipWaiting())
})

import { initializeApp } from 'firebase/app'
import { getMessaging, onBackgroundMessage } from 'firebase/messaging/sw'
import utils from '@/lib/adamant'

const firebaseApp = initializeApp({
apiKey: 'AIzaSyDgtB_hqwL1SS_YMYepRMmXYhmc7154wmU',
authDomain: 'adamant-messenger.firebaseapp.com',
databaseURL: 'https://adamant-messenger.firebaseio.com',
projectId: 'adamant-messenger',
storageBucket: 'adamant-messenger.appspot.com',
messagingSenderId: '987518845753',
appId: '1:987518845753:web:6585b11ca36bac4c251ee8'
})

let privateKey: string = ''
const channel = new BroadcastChannel('adm_notifications')
channel.onmessage = (event) => {
console.log('🚀 ~ :35 ~ event:', event)
const data = event.data
if (data && data.isCheckPK) channel.postMessage({ isNoPrivateKey: true })
else if (data && data.privateKey) {
privateKey = data.privateKey
console.log('🚀 ~ firebase-messaging-sw.ts:40 ~ privateKey:', privateKey)
}
}
if (!privateKey) {
channel.postMessage({ isNoPrivateKey: true })
}

const messaging = getMessaging(firebaseApp)
onBackgroundMessage(messaging, (payload: any) => {
console.log('🚀 ~ :37 ~ privateKey:', privateKey)
console.log('🚀 ~ :40 ~ onBackgroundMessage ~ payload:', payload)
const txn = payload.data?.txn || ''
const _txn = JSON.parse(txn)
const { senderPublicKey } = _txn
const asset = _txn.asset
const chat = asset.chat
let decoded_message = ''
const { message, own_message } = chat
if (privateKey) {
decoded_message = utils.decodeMessage(message, senderPublicKey, privateKey, own_message)
console.log('🚀 ~ :60 ~ onBackgroundMessage ~ decoded_message:', decoded_message)
const notificationTitle = 'ADAMANT Messenger'
const notificationBody = payload.notification?.title + ' sw: ' + decoded_message
const notificationOptions = {
body: notificationBody,
icon: '/icon.png'
}
swSelf.registration.showNotification(notificationTitle, notificationOptions)
}
})
29 changes: 29 additions & 0 deletions src/firebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { initializeApp } from 'firebase/app'
import { getMessaging } from 'firebase/messaging'
import { getId, getInstallations } from 'firebase/installations'

const firebaseConfig = {
apiKey: 'AIzaSyDgtB_hqwL1SS_YMYepRMmXYhmc7154wmU',
authDomain: 'adamant-messenger.firebaseapp.com',
databaseURL: 'https://adamant-messenger.firebaseio.com',
projectId: 'adamant-messenger',
storageBucket: 'adamant-messenger.appspot.com',
messagingSenderId: '987518845753',
appId: '1:987518845753:web:6585b11ca36bac4c251ee8'
}
Comment on lines +5 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use same config in the app and in the Service Worker. Let's move the const into another place and import it.


const firebaseApp = initializeApp(firebaseConfig)
const fcm = getMessaging(firebaseApp)

console.log('Firebase app initialized', firebaseApp)
console.log('FCM instance initialized', fcm)

window.firebaseApp = firebaseApp
window.fcm = fcm

export function getDeviceId() {
console.log('🚀 ~ getDeviceId ~ getInstallations(firebaseApp):', getInstallations(firebaseApp))
return getId(getInstallations(firebaseApp))
}

export { firebaseApp, fcm }
9 changes: 9 additions & 0 deletions src/lib/adamant-api/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,12 @@ export function attachmentAsset(
storage: { id: 'ipfs' }
}
}

export function signalAsset(deviceId: string, token: string, provider: string, action: string) {
return {
deviceId,
token,
provider,
action
}
}
9 changes: 9 additions & 0 deletions src/lib/adamant-api/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ export function getCurrentAccount(): Promise<CurrentAccount>

export function isReady(): boolean

export type KeyPair = {
publicKey: Buffer
privateKey: Buffer
}

export function getMyPK(): string

export function getPublicKey(address: string): Promise<string>

export type SendMessageParams = {
Expand Down Expand Up @@ -169,6 +176,8 @@ export function decodeTransaction(
address: string
): DecodedChatMessageTransaction

// export function decodeNotificationMessage(message: string, senderPublicKey: string, own_message: string): string

export function getI18nMessage(message: string, senderId: string): string

export function loginOrRegister(): Promise<ReturnType<typeof getCurrentAccount>>
Expand Down
Loading