You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

chat.service.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import PubNub from 'pubnub'
  2. import { ChatMessage } from '../entities/index.js'
  3. const MAIN_CHANNEL = 'Channel-Siimee'
  4. /**
  5. * Provider method holder
  6. * We always reference this object so
  7. * we don't have to hardcode provider specific
  8. * methods for doing chat things.
  9. *
  10. * This gets overloaded later in the program
  11. */
  12. const _providerMethods = {
  13. publish: () => console.error('no provider publish method set'),
  14. subscribe: () => console.error('no provider subscribe method set'),
  15. listen: () => console.error('no provider listen method set'),
  16. }
  17. /**
  18. * Breaking out as much pubnub specific flavor
  19. */
  20. const _setPubnubKeys = testing => {
  21. let keys = {}
  22. if (testing) {
  23. keys = testing
  24. } else {
  25. ;(keys.publishKey = import.meta.env.VITE_PUBNUB_PUBLISH_KEY),
  26. (keys.subscribeKey = import.meta.env.VITE_PUBNUB_SUBSCRIBE_KEY)
  27. }
  28. return keys
  29. }
  30. const _setupPubnub = async (uuid, testing) => {
  31. if (!uuid) return console.error('no pubnub uuid set')
  32. const keys = _setPubnubKeys(testing)
  33. const pubnubClient = await new PubNub({
  34. publishKey: keys.publishKey,
  35. subscribeKey: keys.subscribeKey,
  36. logVerbosity: false,
  37. uuid,
  38. })
  39. // Pass pubnub specific methods to our placeholder obj
  40. _providerMethods['publish'] = pubnubClient.publish
  41. _providerMethods['subscribe'] = pubnubClient.subscribe
  42. _providerMethods['listen'] = pubnubClient.addListener
  43. return pubnubClient
  44. }
  45. /** Singleton that holds all our chat information */
  46. class Chatter {
  47. /**
  48. * Create our chatter instance
  49. * @return {Chatter} our chatter instance object
  50. */
  51. constructor() {
  52. // Our pubnub instance
  53. this.provider = null
  54. this.uuid = null
  55. this._subscriptions = [MAIN_CHANNEL]
  56. this.listeners = {
  57. status: async e => {
  58. if (e.category !== 'PNConnectedCategory') return
  59. },
  60. message: null, // Set manually in chat view
  61. presence: this._onPresence,
  62. }
  63. }
  64. get subscriptions() {
  65. let truncated = this._subscriptions
  66. // Do NOT include the main channel as part of subscriptions
  67. const mainChanIndex = truncated.indexOf(MAIN_CHANNEL)
  68. if (mainChanIndex > -1) {
  69. truncated.splice(mainChanIndex, 1)
  70. }
  71. return truncated
  72. }
  73. async _onPresence(e) {
  74. console.log('presence :', e)
  75. return
  76. }
  77. setOnMessage(cb) {
  78. this.listeners.message = cb
  79. }
  80. async setup(uuid, groupings, testing = false) {
  81. this.uuid = `${uuid}`
  82. // Pass api keys in ugle fasion for testing purposes
  83. // TODO: refactor this with a mock
  84. this.provider = await _setupPubnub(this.uuid, testing)
  85. // step_1: build the this.groupings object from the backend
  86. // await for the groupings to be fetched before subscribing to channels
  87. await this._setupAllChannels(groupings)
  88. this._listenFor({ listeners: this.listeners })
  89. this.subscribe({ channels: this._subscriptions })
  90. return this.subscriptions
  91. }
  92. async getHistory(channel, count = 10) {
  93. console.warn('[chatter] grabbing history for channel:', channel)
  94. let pastMessages = null
  95. try {
  96. pastMessages = await this.provider.fetchMessages({
  97. channels: [channel],
  98. count: count,
  99. includeMessageType: true,
  100. includeUUID: true,
  101. includeMeta: true,
  102. includeMessageActions: false,
  103. })
  104. } catch (error) {
  105. console.error('[chatter]', error)
  106. }
  107. const channelHistory = pastMessages && pastMessages.channels ? pastMessages.channels[channel] : null
  108. console.log('channelHistory :>> ', channelHistory)
  109. return channelHistory
  110. ? channelHistory.map(msg => ({
  111. publisher: msg.uuid,
  112. message: new ChatMessage(msg.message.description),
  113. timetoken: msg.timetoken,
  114. }))
  115. : []
  116. }
  117. /**
  118. * Send a message to a channel
  119. * example = new ChatMessage({ title: 'example', description: 'ni' })
  120. * Facade so we can hide provider specific methods
  121. * @param {string} channel
  122. * @param {ChatMessage} message
  123. * @return {object} timestamp
  124. */
  125. async publish(channel, message) {
  126. return _providerMethods.publish({
  127. channel,
  128. message: new ChatMessage(message),
  129. })
  130. }
  131. /**
  132. * Subscribe to a channels
  133. * Facade so we can hide provider specific methods
  134. * @param {array} channels grouping name
  135. */
  136. subscribe({ channels }) {
  137. _providerMethods.subscribe({ channels })
  138. }
  139. /**
  140. * Listen to events and set callbacks
  141. * Facade so we can hide provider specific methods
  142. */
  143. _listenFor({ listeners }) {
  144. _providerMethods.listen(listeners)
  145. }
  146. /**
  147. * Get all groupings for this profile and
  148. * then store them as subscriptions
  149. */
  150. async _setupAllChannels(groupings) {
  151. groupings.forEach(grouping => {
  152. this._subscriptions.push(grouping.grouping_name)
  153. })
  154. }
  155. stop() {
  156. this._subscriptions = [MAIN_CHANNEL]
  157. console.warn('chatter stop not implemented')
  158. }
  159. }
  160. export { Chatter, MAIN_CHANNEL }