1- import  {  Query ,  ResolveField ,  Resolver ,  Subscription  }  from  '@nestjs/graphql' ; 
1+ import  {  OnModuleInit  }  from  '@nestjs/common' ; 
2+ import  { 
3+     Parent , 
4+     Query , 
5+     Resolver , 
6+     Subscription , 
7+     ResolveField , 
8+ }  from  '@nestjs/graphql' ; 
9+ import  {  PubSub  }  from  'graphql-subscriptions' ; 
210
311import  {  Resource  }  from  '@unraid/shared/graphql.model.js' ; 
412import  { 
513    AuthActionVerb , 
614    AuthPossession , 
715    UsePermissions , 
816}  from  '@unraid/shared/use-permissions.directive.js' ; 
9- import  {  baseboard  as  getBaseboard ,  system  as  getSystem  }  from  'systeminformation' ; 
17+ import  { 
18+     baseboard  as  getBaseboard , 
19+     system  as  getSystem , 
20+ }  from  'systeminformation' ; 
1021
11- import  {  createSubscription ,  PUBSUB_CHANNEL  }  from  '@app/core/pubsub.js' ; 
1222import  {  getMachineId  }  from  '@app/core/utils/misc/get-machine-id.js' ; 
23+ import  { 
24+     createSubscription , 
25+     PUBSUB_CHANNEL , 
26+     pubsub , 
27+ }  from  '@app/core/pubsub.js' ; 
28+ 
1329import  {  DisplayService  }  from  '@app/unraid-api/graph/resolvers/display/display.service.js' ; 
1430import  { 
1531    Baseboard , 
@@ -22,16 +38,40 @@ import {
2238    Os , 
2339    System , 
2440    Versions , 
41+     CpuUtilization , 
2542}  from  '@app/unraid-api/graph/resolvers/info/info.model.js' ; 
43+ import  {  CpuDataService  }  from  '@app/unraid-api/graph/resolvers/info/cpu-data.service.js' ; 
2644import  {  InfoService  }  from  '@app/unraid-api/graph/resolvers/info/info.service.js' ; 
45+ import  {  SubscriptionTrackerService  }  from  '@app/unraid-api/graph/services/subscription-tracker.service.js' ; 
46+ 
47+ const  CPU_UTILIZATION  =  'CPU_UTILIZATION' ; 
2748
2849@Resolver ( ( )  =>  Info ) 
29- export  class  InfoResolver  { 
50+ export  class  InfoResolver  implements  OnModuleInit  { 
51+     private  cpuPollingTimer : NodeJS . Timeout ; 
52+ 
3053    constructor ( 
3154        private  readonly  infoService : InfoService , 
32-         private  readonly  displayService : DisplayService 
55+         private  readonly  displayService : DisplayService , 
56+         private  readonly  subscriptionTracker : SubscriptionTrackerService , 
57+         private  readonly  cpuDataService : CpuDataService 
3358    )  { } 
3459
60+     onModuleInit ( )  { 
61+         this . subscriptionTracker . registerTopic ( 
62+             CPU_UTILIZATION , 
63+             ( )  =>  { 
64+                 this . cpuPollingTimer  =  setInterval ( async  ( )  =>  { 
65+                     const  payload  =  await  this . infoService . generateCpuLoad ( ) ; 
66+                     pubsub . publish ( CPU_UTILIZATION ,  {  cpuUtilization : payload  } ) ; 
67+                 } ,  1000 ) ; 
68+             } , 
69+             ( )  =>  { 
70+                 clearInterval ( this . cpuPollingTimer ) ; 
71+             } 
72+         ) ; 
73+     } 
74+ 
3575    @Query ( ( )  =>  Info ) 
3676    @UsePermissions ( { 
3777        action : AuthActionVerb . READ , 
@@ -116,4 +156,57 @@ export class InfoResolver {
116156    public  async  infoSubscription ( )  { 
117157        return  createSubscription ( PUBSUB_CHANNEL . INFO ) ; 
118158    } 
159+ 
160+     @Query ( ( )  =>  CpuUtilization ) 
161+     @UsePermissions ( { 
162+         action : AuthActionVerb . READ , 
163+         resource : Resource . INFO , 
164+         possession : AuthPossession . ANY , 
165+     } ) 
166+     public  async  cpuUtilization ( ) : Promise < CpuUtilization >  { 
167+         const  {  currentLoad : load ,  cpus }  =  await  this . cpuDataService . getCpuLoad ( ) ; 
168+         return  { 
169+             id : 'info/cpu-load' , 
170+             load, 
171+             cpus, 
172+         } ; 
173+     } 
174+ 
175+     @Subscription ( ( )  =>  CpuUtilization ,  { 
176+         name : 'cpuUtilization' , 
177+         resolve : ( value )  =>  value . cpuUtilization , 
178+     } ) 
179+     @UsePermissions ( { 
180+         action : AuthActionVerb . READ , 
181+         resource : Resource . INFO , 
182+         possession : AuthPossession . ANY , 
183+     } ) 
184+     public  async  cpuUtilizationSubscription ( )  { 
185+         const  iterator  =  createSubscription ( CPU_UTILIZATION ) ; 
186+ 
187+         return  { 
188+             [ Symbol . asyncIterator ] : ( )  =>  { 
189+                 this . subscriptionTracker . subscribe ( CPU_UTILIZATION ) ; 
190+                 return  iterator [ Symbol . asyncIterator ] ( ) ; 
191+             } , 
192+             return : ( )  =>  { 
193+                 this . subscriptionTracker . unsubscribe ( CPU_UTILIZATION ) ; 
194+                 return  iterator . return ( ) ; 
195+             } , 
196+         } ; 
197+     } 
198+ } 
199+ 
200+ @Resolver ( ( )  =>  InfoCpu ) 
201+ export  class  InfoCpuResolver  { 
202+     constructor ( private  readonly  cpuDataService : CpuDataService )  { } 
203+ 
204+     @ResolveField ( ( )  =>  Number ,  { 
205+         description : 'CPU utilization in percent' , 
206+         nullable : true , 
207+     } ) 
208+     public  async  utilization ( @Parent ( )  cpu : InfoCpu ) : Promise < number >  { 
209+         const  {  currentLoad }  =  await  this . cpuDataService . getCpuLoad ( ) ; 
210+         return  currentLoad ; 
211+     } 
119212} 
0 commit comments