-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathChatRoom.ts
More file actions
153 lines (109 loc) · 5.14 KB
/
ChatRoom.ts
File metadata and controls
153 lines (109 loc) · 5.14 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { HashedObject, HashedLiteral } from '@hyper-hyper-space/core';
import { MutableSet, MutableReference } from '@hyper-hyper-space/core';
import { Identity } from '@hyper-hyper-space/core';
import { SpaceEntryPoint } from '@hyper-hyper-space/core';
import { PeerNode } from '@hyper-hyper-space/core';
import { Message } from './Message';
// A simple, unmoderated chat room implemented as an H.H.S. object.
// This chat room will automatically synchronize its local state with
// any remote instances when the method "startSync" is called.
// The ChatRoom itself inherits from HashedObject, therefore it can
// be persisted to an HHS Store, but it is immutable.
// The topic and the sets of messages and chat participants are mutable.
// HHS' native Identity class is used to represent participants, and a simple
// Message object is defined in Message.ts.
// Sync uses some implicit parameters configured via the setResources method,
// inherited from HashedObject: a local store and an intance of HHS' mesh,
// used for discovering and communicating with peers.
class ChatRoom extends HashedObject implements SpaceEntryPoint {
static className = 'hhs/v0/exampes/ChatRoom';
topic?: MutableReference<HashedLiteral>
participants?: MutableSet<Identity>;
messages?: MutableSet<Message>;
_node?: PeerNode;
constructor(topic?: string) {
super();
if (topic !== undefined) {
// When we create a chat room, we always want a new one.
// We accomplish this by giving the newly created room a random id.
this.setRandomId();
// By using addDerivedField, all the mutable members of
// the class are derived deterministically from its id.
this.addDerivedField('topic', new MutableReference());
this.addDerivedField('participants', new MutableSet());
this.addDerivedField('messages', new MutableSet());
// This is not necessary in this case, but it is nice and helps to
// catch errors.
// We set the received topic.
this.topic?.setValue(new HashedLiteral(topic));
}
}
init(): void {
}
// Upon receiving a chat room, we check that it follows the structure defined
// above before accepting it into our store. That is done by implementing a
// validate() method.
validate(_references: Map<string, HashedObject>): boolean {
return this.getId() !== undefined &&
this.checkDerivedField('topic') &&
this.checkDerivedField('participants') &&
this.checkDerivedField('messages');
}
async join(id: Identity): Promise<void> {
await this.participants?.add(id);
await this.participants?.saveQueuedOps();
//this.getStore().save(this.participants as HashedObject);
//this.participants?.saveQueuedOps();
}
async leave(id: Identity): Promise<void> {
await this.participants?.delete(id);
await this.participants?.saveQueuedOps();
}
async say(author: Identity, text: string): Promise<void>{
let message = new Message(author, text);
await this.messages?.add(message);
await this.messages?.saveQueuedOps();
}
getParticipants() : MutableSet<Identity> {
if (this.participants === undefined) {
throw new Error('The chat room has not been initialized, participants are unavailable.');
}
return this.participants;
}
getMessages() : MutableSet<Message> {
if (this.messages === undefined) {
throw new Error('The chat room has not been initialized, messages are unavailable.');
}
return this.messages;
}
// The following method will do two things:
// - it will broadcast this chat room over the network, helping other peers that
// know its 3-word code discover it.
// - it will start exchanging operations and syncrhonizing the state in the local
// store with the group of peers that is also synchronizing the chat room.
// Any other client that opens this chat room on the local store will see its
// state updated as new data is fetched, and conversely any changes that are
// persisted on the local state will be sent over to peers automatically.
async startSync(): Promise<void> {
let resources = this.getResources();
if (resources === undefined) {
throw new Error('Cannot start sync: resources not configured.');
}
this._node = new PeerNode(resources);
this._node.broadcast(this);
this._node.sync(this);
}
// Stop the broadcast / sync processes described above.
async stopSync(): Promise<void> {
this._node?.stopBroadcast(this);
this._node?.stopSync(this);
}
// The class name used to register this object with the HHS library.
getClassName(): string {
return ChatRoom.className;
}
}
// Registering the ChatRoom class with HHS is necessary so the library will know it has
// to use this class when a chat room object is received:
HashedObject.registerClass(ChatRoom.className, ChatRoom);
export { ChatRoom };