-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
entities.service.ts
115 lines (106 loc) · 3.27 KB
/
entities.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
import { Entity } from './entity.dto';
import { EntityProxyHandler } from './entity.proxy';
import { InjectEventEmitter } from 'nest-emitter';
import { EntitiesEventEmitter } from './entities.events';
import { EntityCustomization } from './entity-customization.interface';
import { ClusterService } from '../cluster/cluster.service';
import { ConfigService } from '../config/config.service';
import { EntitiesConfig } from './entities.config';
@Injectable()
export class EntitiesService implements OnApplicationBootstrap {
private readonly config: EntitiesConfig;
private readonly entities: Map<string, Entity> = new Map<string, Entity>();
private readonly logger: Logger;
constructor(
private readonly clusterService: ClusterService,
private readonly configService: ConfigService,
@InjectEventEmitter() private readonly emitter: EntitiesEventEmitter
) {
this.config = configService.get('entities');
this.logger = new Logger(EntitiesService.name);
}
/**
* Lifecycle hook, called once the application has started.
*/
onApplicationBootstrap(): void {
this.clusterService.on('elected', () => {
this.refreshStates();
});
}
/**
* Checks whether a given entity ID has already been registered.
*
* @param id - Entity id
* @returns Registered or not
*/
has(id: string): boolean {
return this.entities.has(id);
}
/**
* Retrieves the entity instance for a registered ID.
*
* @param id - Entity id
* @returns Entity or undefined if not found
*/
get(id: string): Entity {
return this.entities.get(id);
}
/**
* Retrieves all registered entities.
*
* @returns Registered entities
*/
getAll(): Entity[] {
return Array.from(this.entities.values());
}
/**
* Adds a new entity and applies ES6 proxies to watch for state/attribute changes.
*
* @param entity - Entity to register
* @param customizations - Customization objects to be used by other integrations
* @returns Entity with applied state/attributes watcher
*/
add(
entity: Entity,
customizations?: Array<EntityCustomization<any>>
): Entity {
if (this.entities.has(entity.id)) {
throw new Error(`Entity with id ${entity.id} already exists!`);
}
this.logger.debug(`Adding new entity ${entity.id}`);
const proxy = new Proxy<Entity>(
entity,
new EntityProxyHandler(
this.emitter,
this.clusterService.isMajorityLeader.bind(this.clusterService),
this.config.behaviors[entity.id]
)
);
this.entities.set(entity.id, proxy);
this.emitter.emit('newEntity', proxy, customizations);
return proxy;
}
/**
* Emits the current states of all entities that this instance has power over.
*/
refreshStates(): void {
this.logger.log('Refreshing entity states');
this.entities.forEach((entity) => {
if (!entity.distributed || this.clusterService.isMajorityLeader()) {
this.emitter.emit(
'stateUpdate',
entity.id,
entity.state,
entity.distributed
);
this.emitter.emit(
'attributesUpdate',
entity.id,
entity.attributes,
entity.distributed
);
}
});
}
}