Enhance Slicer Integration with Object Update Subscription
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Added subscription to object updates for printers, allowing real-time updates of pending slicer uploads. - Introduced a reference to prevent redundant updates when new data is received. - Updated the ApiServerContext to manage object update subscriptions, improving data consistency and responsiveness in the SlicerIntegration component.
This commit is contained in:
parent
2baf9cffab
commit
12c5cd83f4
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useEffect, useState } from 'react'
|
import { useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { Divider, Flex, Layout, Typography, Button, Badge, Modal } from 'antd'
|
import { Divider, Flex, Layout, Typography, Button, Badge, Modal } from 'antd'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
@ -18,7 +18,9 @@ const { Title } = Typography
|
|||||||
const SlicerIntegration = () => {
|
const SlicerIntegration = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const printerId = new URLSearchParams(location.search).get('printerId')
|
const printerId = new URLSearchParams(location.search).get('printerId')
|
||||||
const { updateObject } = useContext(ApiServerContext)
|
const { updateObject, subscribeToObjectUpdates } =
|
||||||
|
useContext(ApiServerContext)
|
||||||
|
const receivedPendingUploadsUpdateRef = useRef(false)
|
||||||
|
|
||||||
const [pendingSlicerUploads, setPendingSlicerUploads] = useState([])
|
const [pendingSlicerUploads, setPendingSlicerUploads] = useState([])
|
||||||
const [currentPendingSlicerUpload, setCurrentPendingSlicerUpload] =
|
const [currentPendingSlicerUpload, setCurrentPendingSlicerUpload] =
|
||||||
@ -43,11 +45,40 @@ const SlicerIntegration = () => {
|
|||||||
const [showSlicerUploadFlow, setShowSlicerUploadFlow] = useState(false)
|
const [showSlicerUploadFlow, setShowSlicerUploadFlow] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (receivedPendingUploadsUpdateRef.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
setPendingSlicerUploads(
|
setPendingSlicerUploads(
|
||||||
objectFormState.objectData?.pendingSlicerUploads || []
|
objectFormState.objectData?.pendingSlicerUploads || []
|
||||||
)
|
)
|
||||||
}, [objectFormState.objectData?.pendingSlicerUploads])
|
}, [objectFormState.objectData?.pendingSlicerUploads])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!printerId) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsubscribe = subscribeToObjectUpdates(
|
||||||
|
String(printerId).toLowerCase(),
|
||||||
|
'printer',
|
||||||
|
(object) => {
|
||||||
|
if (
|
||||||
|
!object ||
|
||||||
|
!Object.prototype.hasOwnProperty.call(object, 'pendingSlicerUploads')
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
receivedPendingUploadsUpdateRef.current = true
|
||||||
|
setPendingSlicerUploads(object.pendingSlicerUploads || [])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (unsubscribe) unsubscribe()
|
||||||
|
}
|
||||||
|
}, [printerId, subscribeToObjectUpdates])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const nextUpload = pendingSlicerUploads.find(
|
const nextUpload = pendingSlicerUploads.find(
|
||||||
(upload) => upload.new === true
|
(upload) => upload.new === true
|
||||||
|
|||||||
@ -396,6 +396,8 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
const [userSettingsLoaded, setUserSettingsLoaded] = useState(false)
|
const [userSettingsLoaded, setUserSettingsLoaded] = useState(false)
|
||||||
const subscribedCallbacksRef = useRef(new Map())
|
const subscribedCallbacksRef = useRef(new Map())
|
||||||
const subscribedActivityCallbacksRef = useRef(new Map())
|
const subscribedActivityCallbacksRef = useRef(new Map())
|
||||||
|
const subscribedObjectUpdateCallbacksRef = useRef(new Map())
|
||||||
|
const subscribedObjectUpdateServerRef = useRef(new Set())
|
||||||
const subscribedActivityServerSubscriptionsRef = useRef(new Set())
|
const subscribedActivityServerSubscriptionsRef = useRef(new Set())
|
||||||
const notificationListenersRef = useRef(new Set())
|
const notificationListenersRef = useRef(new Set())
|
||||||
const [connectionIssue, setConnectionIssue] = useState(false)
|
const [connectionIssue, setConnectionIssue] = useState(false)
|
||||||
@ -445,6 +447,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
const clearSubscriptions = useCallback(() => {
|
const clearSubscriptions = useCallback(() => {
|
||||||
subscribedCallbacksRef.current.clear()
|
subscribedCallbacksRef.current.clear()
|
||||||
subscribedActivityServerSubscriptionsRef.current.clear()
|
subscribedActivityServerSubscriptionsRef.current.clear()
|
||||||
|
subscribedObjectUpdateServerRef.current.clear()
|
||||||
notificationListenersRef.current.clear()
|
notificationListenersRef.current.clear()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -505,6 +508,45 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const resubscribeObjectUpdateListeners = useCallback(
|
||||||
|
(socket = socketRef.current) => {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribedObjectUpdateCallbacksRef.current.forEach(
|
||||||
|
(callbacks, callbacksRefKey) => {
|
||||||
|
if (!callbacks?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (subscribedObjectUpdateServerRef.current.has(callbacksRefKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const colonIndex = callbacksRefKey.indexOf(':')
|
||||||
|
if (colonIndex === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectType = callbacksRefKey.slice(0, colonIndex)
|
||||||
|
const objectId = callbacksRefKey.slice(colonIndex + 1)
|
||||||
|
subscribedObjectUpdateServerRef.current.add(callbacksRefKey)
|
||||||
|
|
||||||
|
socket.emit(
|
||||||
|
'subscribeToObjectUpdate',
|
||||||
|
{ _id: objectId, objectType },
|
||||||
|
(result) => {
|
||||||
|
if (!result?.success) {
|
||||||
|
subscribedObjectUpdateServerRef.current.delete(callbacksRefKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
const registerNotificationListener = useCallback((callback) => {
|
const registerNotificationListener = useCallback((callback) => {
|
||||||
notificationListenersRef.current.add(callback)
|
notificationListenersRef.current.add(callback)
|
||||||
return () => notificationListenersRef.current.delete(callback)
|
return () => notificationListenersRef.current.delete(callback)
|
||||||
@ -729,6 +771,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
setConnectionIssue(false)
|
setConnectionIssue(false)
|
||||||
resetReconnectState()
|
resetReconnectState()
|
||||||
resubscribeActivityListeners(newSocket)
|
resubscribeActivityListeners(newSocket)
|
||||||
|
resubscribeObjectUpdateListeners(newSocket)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -797,7 +840,8 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
getUserSettings,
|
getUserSettings,
|
||||||
resubscribeActivityListeners,
|
resubscribeActivityListeners,
|
||||||
resetReconnectState,
|
resetReconnectState,
|
||||||
markConnectionLost
|
markConnectionLost,
|
||||||
|
resubscribeObjectUpdateListeners
|
||||||
])
|
])
|
||||||
|
|
||||||
connectToServerRef.current = connectToServer
|
connectToServerRef.current = connectToServer
|
||||||
@ -861,6 +905,10 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
subscribedActivityServerSubscriptionsRef.current.clear()
|
subscribedActivityServerSubscriptionsRef.current.clear()
|
||||||
resubscribeActivityListeners(socket)
|
resubscribeActivityListeners(socket)
|
||||||
}
|
}
|
||||||
|
if (socket && subscribedObjectUpdateCallbacksRef.current.size > 0) {
|
||||||
|
subscribedObjectUpdateServerRef.current.clear()
|
||||||
|
resubscribeObjectUpdateListeners(socket)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleWindowFocus = () => {
|
const handleWindowFocus = () => {
|
||||||
@ -874,6 +922,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
|
|
||||||
logger.debug('Page restored from bfcache, reconnecting socket...')
|
logger.debug('Page restored from bfcache, reconnecting socket...')
|
||||||
subscribedActivityServerSubscriptionsRef.current.clear()
|
subscribedActivityServerSubscriptionsRef.current.clear()
|
||||||
|
subscribedObjectUpdateServerRef.current.clear()
|
||||||
setConnected(false)
|
setConnected(false)
|
||||||
teardownSocket()
|
teardownSocket()
|
||||||
connectToServer()
|
connectToServer()
|
||||||
@ -893,6 +942,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
authenticated,
|
authenticated,
|
||||||
connectToServer,
|
connectToServer,
|
||||||
resubscribeActivityListeners,
|
resubscribeActivityListeners,
|
||||||
|
resubscribeObjectUpdateListeners,
|
||||||
attemptReconnect,
|
attemptReconnect,
|
||||||
teardownSocket
|
teardownSocket
|
||||||
])
|
])
|
||||||
@ -950,7 +1000,21 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
const callbacksRefKey = `${objectType}:${id}`
|
const callbacksRefKey = `${objectType}:${id}`
|
||||||
const allCallbacksRefKey = getAllObjectUpdatesSubscriptionKey(objectType)
|
const allCallbacksRefKey = getAllObjectUpdatesSubscriptionKey(objectType)
|
||||||
|
|
||||||
if (
|
const objectUpdateCallbacks =
|
||||||
|
subscribedObjectUpdateCallbacksRef.current.get(callbacksRefKey)
|
||||||
|
if (id && objectType && objectUpdateCallbacks?.length) {
|
||||||
|
logger.debug(
|
||||||
|
`Calling ${objectUpdateCallbacks.length} callbacks for object:`,
|
||||||
|
callbacksRefKey
|
||||||
|
)
|
||||||
|
objectUpdateCallbacks.forEach((callback) => {
|
||||||
|
try {
|
||||||
|
callback(data.object)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error in object update callback:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (
|
||||||
id &&
|
id &&
|
||||||
objectType &&
|
objectType &&
|
||||||
subscribedCallbacksRef.current.has(callbacksRefKey)
|
subscribedCallbacksRef.current.has(callbacksRefKey)
|
||||||
@ -1106,28 +1170,31 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const offObjectUpdatesEvent = useCallback((id, objectType, callback) => {
|
const offObjectUpdatesEvent = useCallback((id, objectType, callback) => {
|
||||||
if (socketRef.current && socketRef.current.connected == true) {
|
const callbacksRefKey = `${objectType}:${id}`
|
||||||
const callbacksRefKey = `${objectType}:${id}`
|
if (!subscribedObjectUpdateCallbacksRef.current.has(callbacksRefKey)) {
|
||||||
// Remove callback from the subscribed callbacks map
|
return
|
||||||
if (subscribedCallbacksRef.current.has(callbacksRefKey)) {
|
}
|
||||||
const callbacks = subscribedCallbacksRef.current
|
|
||||||
.get(callbacksRefKey)
|
const callbacks = subscribedObjectUpdateCallbacksRef.current
|
||||||
.filter((cb) => cb !== callback)
|
.get(callbacksRefKey)
|
||||||
if (callbacks.length === 0) {
|
.filter((cb) => cb !== callback)
|
||||||
logger.debug(
|
|
||||||
'No callbacks found for object:',
|
if (callbacks.length === 0) {
|
||||||
callbacksRefKey,
|
subscribedObjectUpdateCallbacksRef.current.delete(callbacksRefKey)
|
||||||
'unsubscribing from object update...'
|
subscribedObjectUpdateServerRef.current.delete(callbacksRefKey)
|
||||||
)
|
if (socketRef.current?.connected) {
|
||||||
subscribedCallbacksRef.current.delete(callbacksRefKey)
|
logger.debug(
|
||||||
socketRef.current.emit('unsubscribeObjectUpdate', {
|
'No callbacks found for object:',
|
||||||
_id: id,
|
callbacksRefKey,
|
||||||
objectType: objectType
|
'unsubscribing from object update...'
|
||||||
})
|
)
|
||||||
} else {
|
socketRef.current.emit('unsubscribeObjectUpdate', {
|
||||||
subscribedCallbacksRef.current.set(callbacksRefKey, callbacks)
|
_id: id,
|
||||||
}
|
objectType
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
subscribedObjectUpdateCallbacksRef.current.set(callbacksRefKey, callbacks)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -1181,43 +1248,51 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
|
|
||||||
const subscribeToObjectUpdates = useCallback(
|
const subscribeToObjectUpdates = useCallback(
|
||||||
(id, objectType, callback) => {
|
(id, objectType, callback) => {
|
||||||
if (socketRef.current && socketRef.current.connected == true) {
|
if (!id || !objectType || typeof callback !== 'function') {
|
||||||
const callbacksRefKey = `${objectType}:${id}`
|
return undefined
|
||||||
// Add callback to the subscribed callbacks map immediately
|
|
||||||
if (!subscribedCallbacksRef.current.has(callbacksRefKey)) {
|
|
||||||
subscribedCallbacksRef.current.set(callbacksRefKey, [])
|
|
||||||
}
|
|
||||||
|
|
||||||
const callbacksLength =
|
|
||||||
subscribedCallbacksRef.current.get(callbacksRefKey).length
|
|
||||||
|
|
||||||
if (callbacksLength <= 0) {
|
|
||||||
socketRef.current.emit(
|
|
||||||
'subscribeToObjectUpdate',
|
|
||||||
{
|
|
||||||
_id: id,
|
|
||||||
objectType: objectType
|
|
||||||
},
|
|
||||||
(result) => {
|
|
||||||
if (result.success) {
|
|
||||||
logger.info('Subscribed to id:', id, 'objectType:', objectType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
logger.info(
|
|
||||||
'Adding callback id:',
|
|
||||||
id,
|
|
||||||
'objectType:',
|
|
||||||
objectType,
|
|
||||||
'callbacks length:',
|
|
||||||
callbacksLength + 1
|
|
||||||
)
|
|
||||||
subscribedCallbacksRef.current.get(callbacksRefKey).push(callback)
|
|
||||||
|
|
||||||
// Return cleanup function
|
|
||||||
return () => offObjectUpdatesEvent(id, objectType, callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const callbacksRefKey = `${objectType}:${id}`
|
||||||
|
if (!subscribedObjectUpdateCallbacksRef.current.has(callbacksRefKey)) {
|
||||||
|
subscribedObjectUpdateCallbacksRef.current.set(callbacksRefKey, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const callbacks =
|
||||||
|
subscribedObjectUpdateCallbacksRef.current.get(callbacksRefKey)
|
||||||
|
callbacks.push(callback)
|
||||||
|
|
||||||
|
const socket = socketRef.current
|
||||||
|
if (
|
||||||
|
socket?.connected &&
|
||||||
|
!subscribedObjectUpdateServerRef.current.has(callbacksRefKey)
|
||||||
|
) {
|
||||||
|
subscribedObjectUpdateServerRef.current.add(callbacksRefKey)
|
||||||
|
socket.emit(
|
||||||
|
'subscribeToObjectUpdate',
|
||||||
|
{
|
||||||
|
_id: id,
|
||||||
|
objectType
|
||||||
|
},
|
||||||
|
(result) => {
|
||||||
|
if (result?.success) {
|
||||||
|
logger.info('Subscribed to id:', id, 'objectType:', objectType)
|
||||||
|
} else {
|
||||||
|
subscribedObjectUpdateServerRef.current.delete(callbacksRefKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
'Adding callback id:',
|
||||||
|
id,
|
||||||
|
'objectType:',
|
||||||
|
objectType,
|
||||||
|
'callbacks length:',
|
||||||
|
callbacks.length
|
||||||
|
)
|
||||||
|
|
||||||
|
return () => offObjectUpdatesEvent(id, objectType, callback)
|
||||||
},
|
},
|
||||||
[offObjectUpdatesEvent]
|
[offObjectUpdatesEvent]
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user