hackchat-engine 1.1.15 → 1.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +27 -27
- package/Client.js +8 -10
- package/README.md +174 -181
- package/events/OnlineSet.js +26 -9
- package/events/Session.js +0 -1
- package/events/UserJoin.js +4 -4
- package/events/UserLeave.js +7 -1
- package/example.js +261 -0
- package/index.js +2 -1
- package/package.json +63 -63
- package/structures/SessionStruct.js +0 -1
- package/structures/UserStruct.js +43 -33
- package/structures/WarningStruct.js +0 -4
- package/structures/WhisperStruct.js +6 -0
- package/websocket/packets/PacketRouter.js +7 -4
- package/websocket/packets/handlers/OnlineSetHandler.js +1 -0
- package/test.js +0 -45
package/.eslintrc.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es6": true,
|
|
5
|
-
"node": true
|
|
6
|
-
},
|
|
7
|
-
"extends": [
|
|
8
|
-
"airbnb-base"
|
|
9
|
-
],
|
|
10
|
-
"globals": {
|
|
11
|
-
"Atomics": "readonly",
|
|
12
|
-
"SharedArrayBuffer": "readonly"
|
|
13
|
-
},
|
|
14
|
-
"parserOptions": {
|
|
15
|
-
"ecmaVersion": 2018,
|
|
16
|
-
"sourceType": "module"
|
|
17
|
-
},
|
|
18
|
-
"rules": {
|
|
19
|
-
"import/extensions": [
|
|
20
|
-
"error",
|
|
21
|
-
"ignorePackages",
|
|
22
|
-
{
|
|
23
|
-
"js": "always"
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es6": true,
|
|
5
|
+
"node": true
|
|
6
|
+
},
|
|
7
|
+
"extends": [
|
|
8
|
+
"airbnb-base"
|
|
9
|
+
],
|
|
10
|
+
"globals": {
|
|
11
|
+
"Atomics": "readonly",
|
|
12
|
+
"SharedArrayBuffer": "readonly"
|
|
13
|
+
},
|
|
14
|
+
"parserOptions": {
|
|
15
|
+
"ecmaVersion": 2018,
|
|
16
|
+
"sourceType": "module"
|
|
17
|
+
},
|
|
18
|
+
"rules": {
|
|
19
|
+
"import/extensions": [
|
|
20
|
+
"error",
|
|
21
|
+
"ignorePackages",
|
|
22
|
+
{
|
|
23
|
+
"js": "always"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
package/Client.js
CHANGED
|
@@ -150,9 +150,6 @@ class Client extends EventEmitter {
|
|
|
150
150
|
throw new Error(Errors.INVALID_CHANNEL);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
// @todo: this will be changed with the multichannel patch
|
|
154
|
-
this.channel = channel;
|
|
155
|
-
|
|
156
153
|
this.ws.send({
|
|
157
154
|
cmd: OPCodes.JOIN,
|
|
158
155
|
nick: name,
|
|
@@ -411,13 +408,13 @@ class Client extends EventEmitter {
|
|
|
411
408
|
* Send `updateMessage` operation to the server
|
|
412
409
|
* @param {string} customId The customId of the target message
|
|
413
410
|
* @param {string} text The text to apply
|
|
414
|
-
* @param {string}
|
|
415
|
-
*
|
|
411
|
+
* @param {string} channel Target channel
|
|
412
|
+
* @param {string} [mode='overwrite|append|prepend|complete'] The update mode
|
|
416
413
|
*/
|
|
417
|
-
updateMessage(customId, text, mode = 'overwrite') {
|
|
414
|
+
updateMessage(customId, text, channel, mode = 'overwrite') {
|
|
418
415
|
this.ws.send({
|
|
419
416
|
cmd: OPCodes.UPDATE_MESSAGE,
|
|
420
|
-
channel
|
|
417
|
+
channel,
|
|
421
418
|
customId,
|
|
422
419
|
text,
|
|
423
420
|
mode,
|
|
@@ -427,11 +424,12 @@ class Client extends EventEmitter {
|
|
|
427
424
|
/**
|
|
428
425
|
* Request the public wallet address of a specific user
|
|
429
426
|
* @param {number|string} target The userid (number) or nickname (string) of the user
|
|
427
|
+
* @param {string} channel Target channel
|
|
430
428
|
*/
|
|
431
|
-
getWallet(target) {
|
|
429
|
+
getWallet(target, channel) {
|
|
432
430
|
const payload = {
|
|
433
431
|
cmd: OPCodes.GET_WALLET,
|
|
434
|
-
channel
|
|
432
|
+
channel,
|
|
435
433
|
};
|
|
436
434
|
|
|
437
435
|
if (typeof target === 'number') {
|
|
@@ -450,7 +448,7 @@ class Client extends EventEmitter {
|
|
|
450
448
|
leave(channel) {
|
|
451
449
|
this.ws.send({
|
|
452
450
|
cmd: OPCodes.LEAVE,
|
|
453
|
-
channel
|
|
451
|
+
channel,
|
|
454
452
|
});
|
|
455
453
|
}
|
|
456
454
|
}
|
package/README.md
CHANGED
|
@@ -1,181 +1,174 @@
|
|
|
1
|
-
# hackchat-engine
|
|
2
|
-
|
|
3
|
-
A modern, NodeJS and browser-friendly ES6 WebSocket library for interacting with [hack.chat](https://hack.chat) servers. This engine provides an object-oriented interface, automatic keep-alives, and structured event handling.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
### Prerequisites
|
|
8
|
-
|
|
9
|
-
* **Node.js 14+** (This package uses ES Modules)
|
|
10
|
-
* **NPM 6+**
|
|
11
|
-
|
|
12
|
-
### Install
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm install hackchat-engine
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Quick Start
|
|
22
|
-
|
|
23
|
-
This library uses **ES Modules**. You must use `import` syntax.
|
|
24
|
-
|
|
25
|
-
```javascript
|
|
26
|
-
import { Client } from 'hackchat-engine';
|
|
27
|
-
|
|
28
|
-
const botName = 'MyBot';
|
|
29
|
-
const botPass = 'secretPassword';
|
|
30
|
-
const channel = 'programming';
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
const client = new Client({
|
|
34
|
-
debug:
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
client.on(
|
|
39
|
-
console.log(
|
|
40
|
-
|
|
41
|
-
client.join(botName, botPass, channel);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
client.on(
|
|
46
|
-
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
client.on(
|
|
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
|
-
* **`client.
|
|
123
|
-
* **`client.
|
|
124
|
-
* **`client.
|
|
125
|
-
* **`client.
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## License
|
|
180
|
-
|
|
181
|
-
MIT
|
|
1
|
+
# hackchat-engine
|
|
2
|
+
|
|
3
|
+
A modern, NodeJS and browser-friendly ES6 WebSocket library for interacting with [hack.chat](https://hack.chat) servers. This engine provides an object-oriented interface, automatic keep-alives, and structured event handling.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
* **Node.js 14+** (This package uses ES Modules)
|
|
10
|
+
* **NPM 6+**
|
|
11
|
+
|
|
12
|
+
### Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install hackchat-engine
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
This library uses **ES Modules**. You must use `import` syntax.
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import { Client, Events } from 'hackchat-engine';
|
|
27
|
+
|
|
28
|
+
const botName = 'MyBot';
|
|
29
|
+
const botPass = 'secretPassword';
|
|
30
|
+
const channel = 'programming';
|
|
31
|
+
|
|
32
|
+
// initialize the client
|
|
33
|
+
const client = new Client({
|
|
34
|
+
debug: false,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// triggered when the server establishes a session
|
|
38
|
+
client.on(Events.SESSION, (session) => {
|
|
39
|
+
console.log(`Session established! Token: ${session.token}`);
|
|
40
|
+
// join the channel once the session is ready
|
|
41
|
+
client.join(botName, botPass, channel);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// triggered when the client successfully joins the channel
|
|
45
|
+
client.on(Events.ONLINE_SET, (data) => {
|
|
46
|
+
client.say(data.channel, 'Hello world! I am a bot.');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// triggered on every new message
|
|
50
|
+
client.on(Events.NEW_MESSAGE, (message) => {
|
|
51
|
+
if (message.user.username === botName) return;
|
|
52
|
+
|
|
53
|
+
if (message.content === '!ping') {
|
|
54
|
+
client.say(message.channel, 'Pong!');
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
For a more in-depth example:
|
|
61
|
+
|
|
62
|
+
**[./example.js](./example.js)**
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
You can pass an options object to the `Client` constructor to customize the connection.
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
const client = new Client({
|
|
71
|
+
// Connection details
|
|
72
|
+
ws: {
|
|
73
|
+
gateway: 'wss://hack.chat/chat-ws', // Default
|
|
74
|
+
// gateway: 'ws://127.0.0.1:6060/' // For local development
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// Set to true to see internal logs and raw packets (default: false)
|
|
78
|
+
debug: false,
|
|
79
|
+
|
|
80
|
+
// If true, identifies as a bot to the server (default: true)
|
|
81
|
+
isBot: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Events
|
|
89
|
+
|
|
90
|
+
The client extends `EventEmitter`. You can listen for the following events:
|
|
91
|
+
|
|
92
|
+
| Event | Payload | Description |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `connected` | `Client` | Socket connection established. |
|
|
95
|
+
| `session` | `SessionStruct` | Server has assigned a session ID. |
|
|
96
|
+
| `channelJoined` | `Object` | Client has successfully joined a channel and received the user list. |
|
|
97
|
+
| `message` | `MessageStruct` | A new message was received. |
|
|
98
|
+
| `userJoined` | `UserStruct` | A user joined the channel. |
|
|
99
|
+
| `userLeft` | `UserStruct` | A user left the channel. |
|
|
100
|
+
| `userUpdate` | `UserStruct` | A user changed their flair, color, or status. |
|
|
101
|
+
| `whisper` | `WhisperStruct` | Received a private whisper. |
|
|
102
|
+
| `invite` | `InviteStruct` | Received an invitation to another channel. |
|
|
103
|
+
| `emote` | `EmoteStruct` | A user sent a `/me` emote. |
|
|
104
|
+
| `warning` | `WarningStruct` | Server sent a warning (e.g., rate limit). |
|
|
105
|
+
| `gotCaptcha` | `CaptchaStruct` | Server requires a captcha solution. |
|
|
106
|
+
| `hackAttempt` | `HackAttemptStruct` | A client upgrade request attempt. |
|
|
107
|
+
| `updateMessage` | `UpdateMessageStruct` | A previously sent message was edited or deleted. |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Key Methods
|
|
112
|
+
|
|
113
|
+
### Core
|
|
114
|
+
|
|
115
|
+
* **`client.join(nick, password, channel)`**: Authenticate and join a specific channel.
|
|
116
|
+
* **`client.say(channel, text)`**: Send a message to a channel.
|
|
117
|
+
* **`client.changeColor(hex)`**: Change your nickname color (e.g., `CCCCCC`).
|
|
118
|
+
* **`client.changeUsername(newNick)`**: Request a nickname change.
|
|
119
|
+
|
|
120
|
+
### Moderation
|
|
121
|
+
|
|
122
|
+
* **`client.kick(channel, user)`**: Kick a user (requires permissions).
|
|
123
|
+
* **`client.ban(channel, user)`**: Ban a user (requires permissions).
|
|
124
|
+
* **`client.enableCaptcha(channel)`**: Turn on captcha for the channel.
|
|
125
|
+
* **`client.lockChannel(channel)`**: Lock the channel (admin only).
|
|
126
|
+
|
|
127
|
+
### Interactions
|
|
128
|
+
|
|
129
|
+
The `MessageStruct` (passed in the `message` event) has helper methods:
|
|
130
|
+
|
|
131
|
+
* **`message.reply(text)`**: Automatically replies to the channel the message originated from.
|
|
132
|
+
|
|
133
|
+
### Message Manipulation
|
|
134
|
+
|
|
135
|
+
* **`client.updateMessage(customId, text, mode)`**: Edit a message you previously sent.
|
|
136
|
+
* `mode`: `'overwrite'`, `'append'`, `'prepend'`, or `'complete'` (delete).
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Advanced Usage
|
|
143
|
+
|
|
144
|
+
### Handling Custom Commands
|
|
145
|
+
|
|
146
|
+
If the server implements custom opcodes that are not natively handled by the engine, you can register a listener for them:
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
client.onCommand('customEvent', (payload) => {
|
|
150
|
+
console.log('Received custom packet:', payload);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Accessing Users
|
|
156
|
+
|
|
157
|
+
Users are stored in an extended Map for easy access.
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
// Get a user by ID
|
|
161
|
+
const user = client.users.get(12345);
|
|
162
|
+
|
|
163
|
+
// Find a user by name
|
|
164
|
+
const user = client.users.find(u => u.username === 'Admin');
|
|
165
|
+
|
|
166
|
+
if (user) {
|
|
167
|
+
console.log(`${user.username} is currently ${user.isOnline ? 'Online' : 'Offline'}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/events/OnlineSet.js
CHANGED
|
@@ -4,8 +4,6 @@ import UserStruct from '../structures/UserStruct.js';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* This class handles an incoming `onlineSet` event from the server
|
|
7
|
-
* @todo Change user handling for multi-channel patch. What if we removed
|
|
8
|
-
* this event entirely and funneled everything through the `join` event?
|
|
9
7
|
* @private
|
|
10
8
|
*/
|
|
11
9
|
class OnlineSet extends AbstractEvent {
|
|
@@ -16,20 +14,39 @@ class OnlineSet extends AbstractEvent {
|
|
|
16
14
|
*/
|
|
17
15
|
handle(data) {
|
|
18
16
|
const { client } = this;
|
|
17
|
+
const incomingChannel = data.channel;
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
* Patch user array into online users
|
|
22
|
-
* @todo This will be changed with the multi-channel patch
|
|
23
|
-
* @legacy
|
|
24
|
-
*/
|
|
25
|
-
data.users.map((userData) => {
|
|
19
|
+
data.users.forEach((userData) => {
|
|
26
20
|
if (userData.isme) {
|
|
27
21
|
if (!client.myUser) {
|
|
22
|
+
// eslint-disable-next-line no-param-reassign
|
|
23
|
+
userData.channel = incomingChannel;
|
|
28
24
|
client.myUser = new ClientStruct(client, userData);
|
|
25
|
+
} else {
|
|
26
|
+
if (client.myUser.channels) {
|
|
27
|
+
client.myUser.channels.add(incomingChannel);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
client.myUser.updateUser(userData);
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
const existingUser = client.users.get(userData.userid);
|
|
35
|
+
|
|
36
|
+
if (existingUser) {
|
|
37
|
+
if (existingUser.channels) {
|
|
38
|
+
existingUser.channels.add(incomingChannel);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
existingUser.updateUser(userData);
|
|
42
|
+
existingUser.online = true;
|
|
43
|
+
} else {
|
|
44
|
+
// eslint-disable-next-line no-param-reassign
|
|
45
|
+
userData.channel = incomingChannel;
|
|
46
|
+
|
|
47
|
+
const newUser = new UserStruct(client, userData);
|
|
48
|
+
client.users.set(userData.userid, newUser);
|
|
49
|
+
}
|
|
33
50
|
});
|
|
34
51
|
}
|
|
35
52
|
}
|
package/events/Session.js
CHANGED
package/events/UserJoin.js
CHANGED
|
@@ -13,17 +13,17 @@ class UserJoin extends AbstractEvent {
|
|
|
13
13
|
*/
|
|
14
14
|
handle(data) {
|
|
15
15
|
const { client } = this;
|
|
16
|
-
// Check if user is already stored
|
|
17
16
|
const user = client.users.get(data.userid);
|
|
18
17
|
|
|
19
|
-
// If stored, set them to online
|
|
20
18
|
if (user) {
|
|
21
|
-
user.
|
|
19
|
+
user.channels.add(data.channel);
|
|
20
|
+
user.online = true;
|
|
21
|
+
user.channel = data.channel;
|
|
22
22
|
return user;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// If not, then add them to the records
|
|
26
25
|
const newUser = new User(client, data);
|
|
26
|
+
newUser.channel = data.channel;
|
|
27
27
|
client.users.set(data.userid, newUser);
|
|
28
28
|
return newUser;
|
|
29
29
|
}
|
package/events/UserLeave.js
CHANGED
|
@@ -14,7 +14,13 @@ class UserLeave extends AbstractEvent {
|
|
|
14
14
|
const { client } = this;
|
|
15
15
|
const user = client.users.get(data.userid);
|
|
16
16
|
|
|
17
|
-
user
|
|
17
|
+
if (user) {
|
|
18
|
+
user.channels.delete(data.channel);
|
|
19
|
+
|
|
20
|
+
if (user.channels.size === 0) {
|
|
21
|
+
user.online = false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
18
24
|
|
|
19
25
|
return user;
|
|
20
26
|
}
|
package/example.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
// remember to npm install hackchat-engine
|
|
4
|
+
// import { Client, Events } from 'hackchat-engine'; <-- use this one
|
|
5
|
+
// import { Client as HcClient, Events as HcEvents } from 'hackchat-engine'; <-- or this one
|
|
6
|
+
import { Client, Events } from './index.js'; // <-- not this one
|
|
7
|
+
|
|
8
|
+
const CONFIG = {
|
|
9
|
+
gateway: 'wss://hack.chat/chat-ws',
|
|
10
|
+
botName: 'ExampleBot',
|
|
11
|
+
password: 'botpassword',
|
|
12
|
+
homeChannel: 'test',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// init
|
|
16
|
+
let sessionToken = null;
|
|
17
|
+
|
|
18
|
+
const client = new Client({
|
|
19
|
+
ws: { gateway: CONFIG.gateway },
|
|
20
|
+
debug: false, // set to true to see internal debug logs
|
|
21
|
+
session: sessionToken,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log(`Starting ${CONFIG.botName}`);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 1. Connection & session events
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fired when the WebSocket successfully opens
|
|
32
|
+
*/
|
|
33
|
+
client.on(Events.CONNECTED, () => {
|
|
34
|
+
console.log('[Connection] WebSocket connected. Negotiating session...');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Fired when the server provides a session token
|
|
39
|
+
* This is the "login success" event
|
|
40
|
+
*/
|
|
41
|
+
client.on(Events.SESSION, (payload) => {
|
|
42
|
+
if (payload.token) {
|
|
43
|
+
sessionToken = payload.token;
|
|
44
|
+
console.log(`[Session] Token received: ${payload.token.substring(0, 10)}...`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// join the home channel once we have a session
|
|
48
|
+
console.log(`[System] Joining ${CONFIG.homeChannel}...`);
|
|
49
|
+
client.join(CONFIG.botName, CONFIG.password, CONFIG.homeChannel);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Fired when the client is fully ready
|
|
54
|
+
*/
|
|
55
|
+
client.on(Events.READY, () => {
|
|
56
|
+
console.log('[System] Client is Ready');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fired when the socket disconnects
|
|
61
|
+
*/
|
|
62
|
+
client.on(Events.DISCONNECT, (event) => {
|
|
63
|
+
console.log(`[Connection] Disconnected. Code: ${event.code}`);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Fired when the client attempts to auto-reconnect
|
|
68
|
+
*/
|
|
69
|
+
client.on(Events.RECONNECTING, () => {
|
|
70
|
+
console.log('[Connection] Connection lost. Attempting to reconnect...');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 2. Channel & user state events
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fired when the client successfully joins a channel
|
|
79
|
+
* Contains the channel name and the initial list of users
|
|
80
|
+
*/
|
|
81
|
+
client.on(Events.ONLINE_SET, (payload) => {
|
|
82
|
+
console.log(`[Channel] Joined '${payload.channel}'. Users: ${payload.users.length}`);
|
|
83
|
+
|
|
84
|
+
// optional: announce arrival
|
|
85
|
+
client.say(payload.channel, `Hello! I am ${CONFIG.botName}.`);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Fired when a user joins a channel
|
|
90
|
+
*/
|
|
91
|
+
client.on(Events.USER_JOIN, (user) => {
|
|
92
|
+
console.log(`[Presence] ${user.username} joined ${user.channel}.`);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Fired when a user leaves a channel
|
|
97
|
+
*/
|
|
98
|
+
client.on(Events.USER_LEAVE, (user) => {
|
|
99
|
+
console.log(`[Presence] ${user.username} left ${user.channel}.`);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Fired when a user updates their details (change nick, color, trip, etc)
|
|
104
|
+
*/
|
|
105
|
+
client.on(Events.USER_UPDATE, (user) => {
|
|
106
|
+
console.log(`[Presence] User updated: ${user.username} (Trip: ${user.trip || 'None'})`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Fired when the server sends the list of public channels
|
|
111
|
+
*/
|
|
112
|
+
client.on(Events.PUB_CHANS, (payload) => {
|
|
113
|
+
console.log(`[Info] Received public channel list: ${payload.list.length} channels.`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Fired when the server sends an informational message
|
|
118
|
+
*/
|
|
119
|
+
client.on(Events.CHANNEL_INFO, (info) => {
|
|
120
|
+
console.log(`[Info] Server sez: "${info.text}" in ${info.channel}`);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 3. Chat & interaction events
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Fired on standard chat messages
|
|
129
|
+
*/
|
|
130
|
+
client.on(Events.NEW_MESSAGE, (msg) => {
|
|
131
|
+
// ignore our own messages
|
|
132
|
+
if (msg.user.username === CONFIG.botName) return;
|
|
133
|
+
|
|
134
|
+
console.log(`[Chat][${msg.channel}] ${msg.user.username}: ${msg.content}`);
|
|
135
|
+
|
|
136
|
+
// example command handling
|
|
137
|
+
if (msg.content === '!ping') {
|
|
138
|
+
client.say(msg.channel, `@${msg.user.username} Pong!`);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Fired when a user performs an emote
|
|
144
|
+
*/
|
|
145
|
+
client.on(Events.CHANNEL_EMOTE, (emote) => {
|
|
146
|
+
console.log(`[Emote][${emote.channel}] * ${emote.user.username} ${emote.content}`);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Fired when the bot receives a private whisper
|
|
151
|
+
*/
|
|
152
|
+
client.on(Events.CHANNEL_WHISPER, (msg) => {
|
|
153
|
+
console.log(`[Whisper] ${msg.from.username} -> Me: ${msg.content}`);
|
|
154
|
+
|
|
155
|
+
// auto-reply example
|
|
156
|
+
msg.reply(`I received your whisper: "${msg.content}"`);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Fired when the bot is invited to another channel
|
|
161
|
+
*/
|
|
162
|
+
client.on(Events.CHANNEL_INVITE, (invite) => {
|
|
163
|
+
console.log(`[Invite] ${invite.from.username} invited us to '${invite.targetChannel}'`);
|
|
164
|
+
// client.join(CONFIG.botName, CONFIG.password, invite.targetChannel);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Fired when a message is edited/updated (e.g. overwriting the last line)
|
|
169
|
+
*/
|
|
170
|
+
client.on(Events.UPDATE_MESSAGE, (update) => {
|
|
171
|
+
console.log(`[Edit] ${update.user.username} updated a message in ${update.channel}. Mode: ${update.mode}`);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 4. Security & system events
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Fired when the server issues a warning (e.g., spamming too fast)
|
|
180
|
+
*/
|
|
181
|
+
client.on(Events.CHANNEL_WARN, (warning) => {
|
|
182
|
+
console.warn(`[Warning] ID: ${warning.id} | Text: ${warning.text}`);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Fired when the server requires a CAPTCHA to join/chat
|
|
187
|
+
*/
|
|
188
|
+
client.on(Events.CHANNEL_CAPTCHA, (captcha) => {
|
|
189
|
+
console.log(`[Captcha] Captcha required in ${captcha.channel}`);
|
|
190
|
+
console.log(captcha.text); // prints the ascii art
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Fired when a 3rd party code suggestion arrives
|
|
195
|
+
*/
|
|
196
|
+
client.on(Events.HACK_ATTEMPT, (suggestion) => {
|
|
197
|
+
console.warn(`[Extension] 3rd party code suggested from ${suggestion.fromNick}, library: ${suggestion.lib}`);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Fired on internal errors
|
|
202
|
+
*/
|
|
203
|
+
client.on(Events.ERROR, (err) => {
|
|
204
|
+
console.error('[Error]', err);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Fired on non-critical internal warnings
|
|
209
|
+
*/
|
|
210
|
+
client.on(Events.WARN, (msg) => {
|
|
211
|
+
console.warn('[System Warn]', msg);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Fired for debug logs (if debug: true is set in Client options)
|
|
216
|
+
* Uncomment to see verbose logs
|
|
217
|
+
*/
|
|
218
|
+
/*
|
|
219
|
+
client.on(Events.DEBUG, (msg) => {
|
|
220
|
+
console.log('[Debug]', msg);
|
|
221
|
+
});
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 5. Web3 / wallet events
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Fired when a wallet address lookup (getWallet) returns data
|
|
230
|
+
*/
|
|
231
|
+
client.on(Events.WALLET_INFO, (info) => {
|
|
232
|
+
console.log(`[Wallet] User: ${info.nick}, Address: ${info.address}`);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Fired when the server requests the client to Sign-In With Solana (SIWS)
|
|
237
|
+
*/
|
|
238
|
+
client.on(Events.SIGN_MESSAGE, (payload) => {
|
|
239
|
+
console.log(`[Web3] Sign Message Request. Wallet: ${payload.wallet}`);
|
|
240
|
+
console.log(`[Web3] Message to sign: "${payload.message}"`);
|
|
241
|
+
// logic to sign message with private key would go here
|
|
242
|
+
// @todo show reply flow
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Fired when the server requests the client to sign a transaction
|
|
247
|
+
*/
|
|
248
|
+
client.on(Events.SIGN_TRANSACTION, (payload) => {
|
|
249
|
+
console.log(`[Web3] Sign Transaction Request. Type: ${payload.type}`);
|
|
250
|
+
console.log(`[Web3] TX Payload: ${payload.tx.substring(0, 20)}...`);
|
|
251
|
+
// @todo show reply flow
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Process cleanup
|
|
256
|
+
*/
|
|
257
|
+
process.on('SIGINT', () => {
|
|
258
|
+
console.log('\n[System] Disconnecting...');
|
|
259
|
+
client.destroy();
|
|
260
|
+
process.exit(0);
|
|
261
|
+
});
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_from": "hackchat-engine@^1.0.9",
|
|
3
|
-
"_inBundle": false,
|
|
4
|
-
"_integrity": "sha512-uxyU4HBAs8L4hQktdtvTP/3drbJHQvjkeQDdonglAffHIPtZ1pgU9W/ScNXNCFEyqDAo/QSVikfXp0wMmLtzeQ==",
|
|
5
|
-
"_location": "/hackchat-engine",
|
|
6
|
-
"_phantomChildren": {},
|
|
7
|
-
"_requested": {
|
|
8
|
-
"type": "range",
|
|
9
|
-
"registry": true,
|
|
10
|
-
"raw": "hackchat-engine@^1.0.9",
|
|
11
|
-
"name": "hackchat-engine",
|
|
12
|
-
"escapedName": "hackchat-engine",
|
|
13
|
-
"rawSpec": "^1.0.9",
|
|
14
|
-
"saveSpec": null,
|
|
15
|
-
"fetchSpec": "^1.0.9"
|
|
16
|
-
},
|
|
17
|
-
"_requiredBy": [
|
|
18
|
-
"#USER",
|
|
19
|
-
"/"
|
|
20
|
-
],
|
|
21
|
-
"_resolved": "https://registry.npmjs.org/hackchat-engine/-/hackchat-engine-1.0.9.tgz",
|
|
22
|
-
"_shasum": "536ea142dbfca44d3853c5767b7797c303642cdb",
|
|
23
|
-
"_spec": "hackchat-engine@^1.0.9",
|
|
24
|
-
"_where": "C:\\Users\\Owner\\Documents\\GitHub\\hcClientBeta",
|
|
25
|
-
"author": {
|
|
26
|
-
"name": "Marzavec"
|
|
27
|
-
},
|
|
28
|
-
"bugs": {
|
|
29
|
-
"url": "https://github.com/hack-chat/hackchat-engine/issues"
|
|
30
|
-
},
|
|
31
|
-
"bundleDependencies": [],
|
|
32
|
-
"dependencies": {
|
|
33
|
-
"node-fetch": "^2.6.0",
|
|
34
|
-
"ws": "^7.2.0"
|
|
35
|
-
},
|
|
36
|
-
"deprecated": false,
|
|
37
|
-
"description": "hack.chat chat engine",
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"eslint": "^7.12.1",
|
|
40
|
-
"eslint-config-airbnb-base": "^14.2.0",
|
|
41
|
-
"eslint-plugin-import": "^2.22.1"
|
|
42
|
-
},
|
|
43
|
-
"homepage": "https://github.com/hack-chat/hackchat-engine#readme",
|
|
44
|
-
"keywords": [
|
|
45
|
-
"hack.chat",
|
|
46
|
-
"chat",
|
|
47
|
-
"client"
|
|
48
|
-
],
|
|
49
|
-
"type": "module",
|
|
50
|
-
"license": "WTFPL",
|
|
51
|
-
"main": "index.js",
|
|
52
|
-
"name": "hackchat-engine",
|
|
53
|
-
"repository": {
|
|
54
|
-
"type": "git",
|
|
55
|
-
"url": "git+https://github.com/hack-chat/hackchat-engine.git"
|
|
56
|
-
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"lint": "eslint --ignore-path .gitignore .",
|
|
59
|
-
"lintfix": "eslint --fix --ignore-path .gitignore .",
|
|
60
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
61
|
-
},
|
|
62
|
-
"version": "1.1.
|
|
63
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"_from": "hackchat-engine@^1.0.9",
|
|
3
|
+
"_inBundle": false,
|
|
4
|
+
"_integrity": "sha512-uxyU4HBAs8L4hQktdtvTP/3drbJHQvjkeQDdonglAffHIPtZ1pgU9W/ScNXNCFEyqDAo/QSVikfXp0wMmLtzeQ==",
|
|
5
|
+
"_location": "/hackchat-engine",
|
|
6
|
+
"_phantomChildren": {},
|
|
7
|
+
"_requested": {
|
|
8
|
+
"type": "range",
|
|
9
|
+
"registry": true,
|
|
10
|
+
"raw": "hackchat-engine@^1.0.9",
|
|
11
|
+
"name": "hackchat-engine",
|
|
12
|
+
"escapedName": "hackchat-engine",
|
|
13
|
+
"rawSpec": "^1.0.9",
|
|
14
|
+
"saveSpec": null,
|
|
15
|
+
"fetchSpec": "^1.0.9"
|
|
16
|
+
},
|
|
17
|
+
"_requiredBy": [
|
|
18
|
+
"#USER",
|
|
19
|
+
"/"
|
|
20
|
+
],
|
|
21
|
+
"_resolved": "https://registry.npmjs.org/hackchat-engine/-/hackchat-engine-1.0.9.tgz",
|
|
22
|
+
"_shasum": "536ea142dbfca44d3853c5767b7797c303642cdb",
|
|
23
|
+
"_spec": "hackchat-engine@^1.0.9",
|
|
24
|
+
"_where": "C:\\Users\\Owner\\Documents\\GitHub\\hcClientBeta",
|
|
25
|
+
"author": {
|
|
26
|
+
"name": "Marzavec"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/hack-chat/hackchat-engine/issues"
|
|
30
|
+
},
|
|
31
|
+
"bundleDependencies": [],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"node-fetch": "^2.6.0",
|
|
34
|
+
"ws": "^7.2.0"
|
|
35
|
+
},
|
|
36
|
+
"deprecated": false,
|
|
37
|
+
"description": "hack.chat chat engine",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"eslint": "^7.12.1",
|
|
40
|
+
"eslint-config-airbnb-base": "^14.2.0",
|
|
41
|
+
"eslint-plugin-import": "^2.22.1"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/hack-chat/hackchat-engine#readme",
|
|
44
|
+
"keywords": [
|
|
45
|
+
"hack.chat",
|
|
46
|
+
"chat",
|
|
47
|
+
"client"
|
|
48
|
+
],
|
|
49
|
+
"type": "module",
|
|
50
|
+
"license": "WTFPL",
|
|
51
|
+
"main": "index.js",
|
|
52
|
+
"name": "hackchat-engine",
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "git+https://github.com/hack-chat/hackchat-engine.git"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"lint": "eslint --ignore-path .gitignore .",
|
|
59
|
+
"lintfix": "eslint --fix --ignore-path .gitignore .",
|
|
60
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
61
|
+
},
|
|
62
|
+
"version": "1.1.16"
|
|
63
|
+
}
|
package/structures/UserStruct.js
CHANGED
|
@@ -37,7 +37,16 @@ class User {
|
|
|
37
37
|
* @type {string}
|
|
38
38
|
* @legacy Will be array or set with multichannel patch
|
|
39
39
|
*/
|
|
40
|
-
this.
|
|
40
|
+
this.channel = data.channel || 'unknown';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The channels this user is in
|
|
44
|
+
* @type {string}
|
|
45
|
+
*/
|
|
46
|
+
this.channels = new Set();
|
|
47
|
+
if (data.channel) {
|
|
48
|
+
this.channels.add(data.channel);
|
|
49
|
+
}
|
|
41
50
|
|
|
42
51
|
/**
|
|
43
52
|
* This users name
|
|
@@ -71,10 +80,9 @@ class User {
|
|
|
71
80
|
|
|
72
81
|
/**
|
|
73
82
|
* Whether or not the user is a bot
|
|
74
|
-
* @todo
|
|
75
83
|
* @type {boolean}
|
|
76
84
|
*/
|
|
77
|
-
this.
|
|
85
|
+
this.botting = data.isBot || false;
|
|
78
86
|
|
|
79
87
|
/**
|
|
80
88
|
* The Message object of the last message sent by the user, if one was sent
|
|
@@ -128,15 +136,6 @@ class User {
|
|
|
128
136
|
return this.userid;
|
|
129
137
|
}
|
|
130
138
|
|
|
131
|
-
/**
|
|
132
|
-
* User name
|
|
133
|
-
* @type {string}
|
|
134
|
-
* @readonly
|
|
135
|
-
*/
|
|
136
|
-
get channel() {
|
|
137
|
-
return this.userchannel;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
139
|
/**
|
|
141
140
|
* User name
|
|
142
141
|
* @type {string}
|
|
@@ -167,7 +166,6 @@ class User {
|
|
|
167
166
|
/**
|
|
168
167
|
* User level , returns 'user', 'mod', 'admin'
|
|
169
168
|
* @type {number}
|
|
170
|
-
* @todo Change from string to numeric levels
|
|
171
169
|
* @readonly
|
|
172
170
|
*/
|
|
173
171
|
get level() {
|
|
@@ -186,11 +184,10 @@ class User {
|
|
|
186
184
|
/**
|
|
187
185
|
* Bot status
|
|
188
186
|
* @type {boolean}
|
|
189
|
-
* @todo
|
|
190
187
|
* @readonly
|
|
191
188
|
*/
|
|
192
189
|
get isBot() {
|
|
193
|
-
return this.
|
|
190
|
+
return this.botting;
|
|
194
191
|
}
|
|
195
192
|
|
|
196
193
|
/**
|
|
@@ -262,25 +259,21 @@ class User {
|
|
|
262
259
|
* @type {string}
|
|
263
260
|
*/
|
|
264
261
|
updateUser(data) {
|
|
262
|
+
if (data.channel) {
|
|
263
|
+
this.channels.add(data.channel);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (data.trip) this.usertrip = data.trip;
|
|
267
|
+
if (data.hash) this.userhash = data.hash;
|
|
268
|
+
|
|
265
269
|
this.username = data.nick;
|
|
266
270
|
this.userlevel = data.uType;
|
|
267
|
-
this.
|
|
271
|
+
this.botting = data.isBot;
|
|
268
272
|
this.nickColor = data.color;
|
|
269
273
|
this.flair = data.flair;
|
|
270
274
|
this.permissionLevel = data.level;
|
|
271
275
|
}
|
|
272
276
|
|
|
273
|
-
/**
|
|
274
|
-
* Sets this user either online or offline
|
|
275
|
-
* @param {string} channel Channel that the user joined or left
|
|
276
|
-
* @returns {boolean}
|
|
277
|
-
*/
|
|
278
|
-
// @todo Multichannel
|
|
279
|
-
toggleOnline(channel) { // eslint-disable-line no-unused-vars
|
|
280
|
-
this.online = !this.online;
|
|
281
|
-
return this.online;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
277
|
/**
|
|
285
278
|
* Sets this user either online or offline
|
|
286
279
|
* @param {Message} message This user's latest message
|
|
@@ -302,15 +295,16 @@ class User {
|
|
|
302
295
|
|
|
303
296
|
/**
|
|
304
297
|
* Send chat text using this user's channel
|
|
298
|
+
* @param {string} channel The specific channel to send to
|
|
305
299
|
* @param {string} text Text to send
|
|
306
300
|
* @returns {boolean}
|
|
307
301
|
*/
|
|
308
|
-
sendMessage(text) {
|
|
302
|
+
sendMessage(channel, text) {
|
|
309
303
|
try {
|
|
310
304
|
return new Promise((resolve) => {
|
|
311
305
|
this.client.ws.send({
|
|
312
306
|
cmd: OPCodes.CHAT,
|
|
313
|
-
channel
|
|
307
|
+
channel,
|
|
314
308
|
text,
|
|
315
309
|
});
|
|
316
310
|
resolve(this);
|
|
@@ -322,17 +316,17 @@ class User {
|
|
|
322
316
|
|
|
323
317
|
/**
|
|
324
318
|
* Send a whisper through this users channel to the user
|
|
319
|
+
* @param {string} channel The specific channel to send to
|
|
325
320
|
* @param {string} text Text to send
|
|
326
|
-
* @todo Finish whisper functions on server
|
|
327
321
|
* @returns {Promise}
|
|
328
322
|
*/
|
|
329
|
-
sendWhisper(text) {
|
|
323
|
+
sendWhisper(channel, text) {
|
|
330
324
|
try {
|
|
331
325
|
return new Promise((resolve) => {
|
|
332
326
|
this.client.ws.send({
|
|
333
327
|
cmd: OPCodes.WHISPER,
|
|
334
|
-
channel
|
|
335
|
-
|
|
328
|
+
channel,
|
|
329
|
+
nick: this.username, /* @todo legacy should be this.userid */
|
|
336
330
|
text,
|
|
337
331
|
});
|
|
338
332
|
resolve(this);
|
|
@@ -344,6 +338,8 @@ class User {
|
|
|
344
338
|
|
|
345
339
|
/**
|
|
346
340
|
* Send `invite` event to this user
|
|
341
|
+
* @param {string} channelName Channel name to use
|
|
342
|
+
* @param {string} to Username as string
|
|
347
343
|
* @returns {void}
|
|
348
344
|
*/
|
|
349
345
|
sendInvite(channel, to = '') {
|
|
@@ -362,6 +358,8 @@ class User {
|
|
|
362
358
|
|
|
363
359
|
/**
|
|
364
360
|
* Send `kick` operation to the server
|
|
361
|
+
* @param {string} channelName Channel name to use
|
|
362
|
+
* @param {string} to Username as string
|
|
365
363
|
* @returns {void}
|
|
366
364
|
*/
|
|
367
365
|
kick(channel, to = '') {
|
|
@@ -380,6 +378,7 @@ class User {
|
|
|
380
378
|
|
|
381
379
|
/**
|
|
382
380
|
* Send `ban` operation to the server
|
|
381
|
+
* @param {string} channelName Channel name to use
|
|
383
382
|
* @returns {void}
|
|
384
383
|
*/
|
|
385
384
|
ban(channel) {
|
|
@@ -392,6 +391,7 @@ class User {
|
|
|
392
391
|
|
|
393
392
|
/**
|
|
394
393
|
* Send `mute` operation to the server
|
|
394
|
+
* @param {string} channelName Channel name to use
|
|
395
395
|
* @returns {void}
|
|
396
396
|
*/
|
|
397
397
|
mute(channel) {
|
|
@@ -404,6 +404,7 @@ class User {
|
|
|
404
404
|
|
|
405
405
|
/**
|
|
406
406
|
* Send `unmute` operation to the server
|
|
407
|
+
* @param {string} channelName Channel name to use
|
|
407
408
|
* @returns {void}
|
|
408
409
|
*/
|
|
409
410
|
unmute(channel) {
|
|
@@ -414,6 +415,15 @@ class User {
|
|
|
414
415
|
});
|
|
415
416
|
}
|
|
416
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Is user in channel
|
|
420
|
+
* @param {string} channelName Channel name to use
|
|
421
|
+
* @returns {boolean}
|
|
422
|
+
*/
|
|
423
|
+
inChannel(channelName) {
|
|
424
|
+
return this.channels.has(channelName);
|
|
425
|
+
}
|
|
426
|
+
|
|
417
427
|
/**
|
|
418
428
|
* When referenced as a string, output this users name instead of an object type
|
|
419
429
|
* @returns {string}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This class handles parsing of the data of a `warning` event
|
|
3
|
-
* @todo Warnings will be numeric events in the future
|
|
4
3
|
*/
|
|
5
4
|
class WarningStruct {
|
|
6
5
|
/**
|
|
@@ -32,8 +31,6 @@ class WarningStruct {
|
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
33
|
* Text included with warning
|
|
35
|
-
* @todo Common warnings will be made integer based to allow i18n
|
|
36
|
-
* This will be removed
|
|
37
34
|
* @legacy
|
|
38
35
|
* @type {string}
|
|
39
36
|
*/
|
|
@@ -41,7 +38,6 @@ class WarningStruct {
|
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
40
|
* Channel the warning was issued from
|
|
44
|
-
* @todo Touches multi-channel patch
|
|
45
41
|
* @type {string}
|
|
46
42
|
*/
|
|
47
43
|
this.channel = data.channel;
|
|
@@ -26,6 +26,7 @@ import WalletInfoHandler from './handlers/WalletInfoHandler.js';
|
|
|
26
26
|
|
|
27
27
|
const BeforeReadyWhitelist = [
|
|
28
28
|
WSEvents.SESSION,
|
|
29
|
+
WSEvents.ONLINE_SET,
|
|
29
30
|
WSEvents.PUB_CHANS,
|
|
30
31
|
];
|
|
31
32
|
|
|
@@ -116,10 +117,12 @@ class PacketRouter {
|
|
|
116
117
|
* @returns {void}
|
|
117
118
|
*/
|
|
118
119
|
processQueue() {
|
|
119
|
-
this.queue.
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
while (this.queue.length > 0) {
|
|
121
|
+
const packet = this.queue.shift();
|
|
122
|
+
if (packet) {
|
|
123
|
+
this.route(packet, true);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
/**
|
package/test.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/* eslint no-console: 0 */
|
|
2
|
-
import Client from './Client.js';
|
|
3
|
-
|
|
4
|
-
const testName = 'testBot';
|
|
5
|
-
const testPass = 'testBot';
|
|
6
|
-
const testChannel = 'programming';
|
|
7
|
-
|
|
8
|
-
const hcClient = new Client({
|
|
9
|
-
ws: {
|
|
10
|
-
gateway: 'ws://127.0.0.1:6060/',
|
|
11
|
-
},
|
|
12
|
-
debug: true,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
hcClient.on('connected', () => console.log('Connected!'));
|
|
16
|
-
|
|
17
|
-
hcClient.on('session', (payload) => {
|
|
18
|
-
console.log(payload);
|
|
19
|
-
hcClient.join(testName, testPass, testChannel);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
hcClient.on('channelJoined', (payload) => {
|
|
23
|
-
console.log(payload);
|
|
24
|
-
hcClient.say(testChannel, 'Bep boop i r bot');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
hcClient.on('debug', (payload) => console.log(payload));
|
|
28
|
-
|
|
29
|
-
hcClient.on('userJoined', (payload) => console.log(payload));
|
|
30
|
-
|
|
31
|
-
hcClient.on('userLeft', (payload) => console.log(payload));
|
|
32
|
-
|
|
33
|
-
hcClient.on('warning', (payload) => console.log(payload));
|
|
34
|
-
|
|
35
|
-
hcClient.on('gotCaptcha', (payload) => console.log(payload));
|
|
36
|
-
|
|
37
|
-
hcClient.on('information', (payload) => console.log(payload));
|
|
38
|
-
|
|
39
|
-
hcClient.on('emote', (payload) => console.log(payload));
|
|
40
|
-
|
|
41
|
-
hcClient.on('invite', (payload) => console.log(payload));
|
|
42
|
-
|
|
43
|
-
hcClient.on('whisper', (payload) => console.log(payload));
|
|
44
|
-
|
|
45
|
-
hcClient.on('message', (payload) => console.log(payload));
|