@@ -5,6 +5,7 @@ import type {
55 KuviewEvent ,
66 KuviewExtra ,
77 ServiceObject ,
8+ PodObject ,
89} from "./kuview" ;
910import { useEffect } from "react" ;
1011import { calcStatus } from "./status" ;
@@ -21,6 +22,11 @@ export const kubernetesAtom = atom<
2122 "kuview.iwanhae.kr/v1/UserGroup" : atom < Record < string , KubernetesObject > > ( { } ) , // virtual resource
2223} ) ;
2324
25+ // Pod index atom: nodeName -> pod nn -> true
26+ export const podsByNodeNameIndexAtom = atom <
27+ Record < string , Record < string , true > >
28+ > ( { } ) ;
29+
2430type ObjectAtom = PrimitiveAtom <
2531 Record < string /* NamespaceName */ , KubernetesObject >
2632> ;
@@ -32,12 +38,46 @@ type _change_operation = {
3238
3339const PENDING_CHANGES = new Map < string , _change_operation > ( ) ;
3440
41+ // A dedicated queue for Pod index changes
42+ type PodIndexChange = {
43+ type : "DELETE" | "UPSERT" ;
44+ pod : PodObject ;
45+ } ;
46+
47+ const POD_INDEX_CHANGES = new Map < string , PodIndexChange > ( ) ;
48+
3549function getObjectKey ( object : KubernetesObject ) : string {
3650 // it is suprising that sometimes the uid is not unique, so we need to check the apiVersion and kind as well
3751 return `${ object . apiVersion } /${ object . kind } :${ object . metadata . namespace } /${ object . metadata . name } :${ object . metadata . uid } ` ;
3852}
3953
54+ // Function to update the Pod index
55+ function updatePodIndex ( event : KuviewEvent ) {
56+ if ( event . object . kind !== "Pod" || event . object . apiVersion !== "v1" ) {
57+ return ;
58+ }
59+
60+ const pod = event . object as PodObject ;
61+ const nodeName = pod . spec ?. nodeName ;
62+ const nn = pod . metadata . namespace
63+ ? `${ pod . metadata . namespace } /${ pod . metadata . name } `
64+ : pod . metadata . name ;
65+
66+ // If nodeName doesn't exist, no need to index, so drop it here
67+ if ( ! nodeName || ! nn ) {
68+ return ;
69+ }
70+
71+ POD_INDEX_CHANGES . set ( nn , {
72+ type : event . type === "delete" ? "DELETE" : "UPSERT" ,
73+ pod,
74+ } ) ;
75+ }
76+
4077export function handleEvent ( event : KuviewEvent ) {
78+ // Update Pod index (handled separately from the main logic)
79+ updatePodIndex ( event ) ;
80+
4181 const key = getObjectKey ( event . object ) ;
4282 switch ( event . type ) {
4383 case "create" :
@@ -235,3 +275,63 @@ export function useServiceEndpointSliceSyncHook() {
235275 // eslint-disable-next-line react-hooks/exhaustive-deps
236276 } , [ ] ) ;
237277}
278+
279+ // usePodIndexSyncHook: A hook to update the Pod index in real-time
280+ export function usePodIndexSyncHook ( ) {
281+ const [ podIndex , setPodIndex ] = useAtom ( podsByNodeNameIndexAtom ) ;
282+
283+ const sync = ( ) => {
284+ const changes : PodIndexChange [ ] = [ ] ;
285+ POD_INDEX_CHANGES . forEach ( ( change , nn ) => {
286+ changes . push ( change ) ;
287+ POD_INDEX_CHANGES . delete ( nn ) ;
288+ } ) ;
289+
290+ if ( changes . length === 0 ) return ;
291+
292+ const newPodIndex = { ...podIndex } ;
293+ let updated = false ;
294+
295+ changes . forEach ( ( change ) => {
296+ const { type, pod } = change ;
297+ const nodeName = pod . spec . nodeName ! ; // From here, we assume nodeName always exists
298+ const nn = pod . metadata . namespace
299+ ? `${ pod . metadata . namespace } /${ pod . metadata . name } `
300+ : pod . metadata . name ;
301+
302+ if ( type === "DELETE" ) {
303+ if ( newPodIndex [ nodeName ] && newPodIndex [ nodeName ] [ nn ] ) {
304+ const updatedNodePods = { ...newPodIndex [ nodeName ] } ;
305+ delete updatedNodePods [ nn ] ;
306+ if ( Object . keys ( updatedNodePods ) . length === 0 ) {
307+ delete newPodIndex [ nodeName ] ;
308+ } else {
309+ newPodIndex [ nodeName ] = updatedNodePods ;
310+ }
311+ updated = true ;
312+ }
313+ } else {
314+ // UPSERT
315+ if ( ! newPodIndex [ nodeName ] ) {
316+ newPodIndex [ nodeName ] = { } ;
317+ }
318+ newPodIndex [ nodeName ] = {
319+ ...newPodIndex [ nodeName ] ,
320+ [ nn ] : true ,
321+ } ;
322+ updated = true ;
323+ }
324+ } ) ;
325+
326+ if ( updated ) {
327+ console . log ( "Updated Pod index" , changes . length , "operations" ) ;
328+ setPodIndex ( newPodIndex ) ;
329+ }
330+ } ;
331+
332+ useEffect ( ( ) => {
333+ const interval = setInterval ( sync , DEBOUNCE_MS ) ;
334+ return ( ) => clearInterval ( interval ) ;
335+ // eslint-disable-next-line react-hooks/exhaustive-deps
336+ } , [ ] ) ;
337+ }
0 commit comments