| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
- import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
- import { EditorType } from '@/features/ide-react/editor/types/editor-type'
- import { putJSON } from '@/infrastructure/fetch-json'
- import { debugConsole } from '@/utils/debugging'
- import { useCallback, useEffect, useRef } from 'react'
- import useEventListener from '@/shared/hooks/use-event-listener'
- import useDomEventListener from '@/shared/hooks/use-dom-event-listener'
- import {
- IdeLayout,
- IdeView,
- useLayoutContext,
- } from '@/shared/context/layout-context'
- import {
- RailTabKey,
- useRailContext,
- } from '@/features/ide-react/context/rail-context'
- function createEditingSessionHeartbeatData(
- editorType: EditorType,
- view: IdeView | null,
- layout: IdeLayout,
- railOpen: boolean,
- railTab: RailTabKey,
- hasDetachedPdf: boolean
- ) {
- const newEditorSegmentation = { railOpen, railTab }
- return {
- editorType,
- editorView: view,
- editorLayout: layout,
- hasDetachedPdf,
- ...newEditorSegmentation,
- }
- }
- function sendEditingSessionHeartbeat(
- projectId: string,
- segmentation: Record<string, unknown>
- ) {
- putJSON(`/editingSession/${projectId}`, {
- body: { segmentation },
- }).catch(debugConsole.error)
- }
- export function useEditingSessionHeartbeat() {
- const { projectId } = useIdeReactContext()
- const { getEditorType } = useEditorManagerContext()
- const { view, pdfLayout: layout, detachIsLinked } = useLayoutContext()
- const { isOpen: railIsOpen, selectedTab: selectedRailTab } = useRailContext()
- // Keep track of how many heartbeats we've sent so that we can calculate how
- // long to wait until the next one
- const heartBeatsSentRef = useRef(0)
- const heartBeatSentRecentlyRef = useRef(false)
- const heartBeatResetTimerRef = useRef<number>()
- useEffect(() => {
- return () => {
- window.clearTimeout(heartBeatResetTimerRef.current)
- }
- }, [])
- const editingSessionHeartbeat = useCallback(() => {
- debugConsole.log('[Event] heartbeat trigger')
- const editorType = getEditorType()
- if (editorType === null) return
- // Heartbeat already sent recently
- if (heartBeatSentRecentlyRef.current) return
- heartBeatSentRecentlyRef.current = true
- const segmentation = createEditingSessionHeartbeatData(
- editorType,
- view,
- layout,
- railIsOpen,
- selectedRailTab,
- detachIsLinked
- )
- debugConsole.log('[Event] send heartbeat request', segmentation)
- sendEditingSessionHeartbeat(projectId, segmentation)
- const heartbeatsSent = heartBeatsSentRef.current
- heartBeatsSentRef.current++
- // Send two first heartbeats at 0 and 30s then increase the backoff time
- // 1min per call until we reach 5 min
- const backoffSecs =
- heartbeatsSent <= 2
- ? 30
- : heartbeatsSent <= 6
- ? (heartbeatsSent - 2) * 60
- : 300
- heartBeatResetTimerRef.current = window.setTimeout(() => {
- heartBeatSentRecentlyRef.current = false
- }, backoffSecs * 1000)
- }, [
- getEditorType,
- projectId,
- view,
- layout,
- railIsOpen,
- selectedRailTab,
- detachIsLinked,
- ])
- // Hook the heartbeat up to editor events
- useEventListener('cursor:editor:update', editingSessionHeartbeat)
- useEventListener('scroll:editor:update', editingSessionHeartbeat)
- useDomEventListener(document, 'click', editingSessionHeartbeat)
- }
|