bancho.js 0.11.6 → 0.12.0
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/CHANGELOG.md +13 -1
- package/README.md +1 -1
- package/index.d.ts +49 -49
- package/lib/BanchoChannel.js +5 -1
- package/lib/BanchoClient.js +74 -47
- package/lib/IrcCommands/JoinCommand.js +11 -10
- package/lib/IrcCommands/PartCommand.js +16 -12
- package/package.json +1 -1
- package/tests/TestGoals.js +3 -1
- package/tests/units/JoinEventChannelUnit.js +5 -9
- package/tests/units/MultiplayerLobbiesUnit.js +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Pre-release
|
|
2
2
|
|
|
3
|
+
## Version 0.12
|
|
4
|
+
|
|
5
|
+
### Version 0.12.0
|
|
6
|
+
|
|
7
|
+
- **Support creating lobbies with filtered names by queuing lobby creation**
|
|
8
|
+
Created lobbies are no longer checked against their names for the `createLobby` call to succeed. This helps in cases where the requested lobby name has filtered words.
|
|
9
|
+
As a consequence, lobby creation can no longer be done in parallel. They are now transparently queued. The promise returned by `createLobby` still resolves when the lobby is created, so this should be fully transparent to the user.
|
|
10
|
+
- **Fix infinite loop when message fails to send**
|
|
11
|
+
- BanchoChannel: Fix join and leave methods hanging forever if channel is already joined/left
|
|
12
|
+
- BanchoChannel: Fix JOIN and PART events being emitted before they're fully processed
|
|
13
|
+
- Fix slots types not being nullable
|
|
14
|
+
|
|
3
15
|
## Version 0.11
|
|
4
16
|
|
|
5
17
|
### Version 0.11.6
|
|
@@ -376,4 +388,4 @@
|
|
|
376
388
|
|
|
377
389
|
## Version 0.1
|
|
378
390
|
|
|
379
|
-
- Initial single-file library with very basic IRC support
|
|
391
|
+
- Initial single-file library with very basic IRC support
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://nodei.co/npm/bancho.js/)
|
|
4
4
|
[](https://git.cartooncraft.fr/ThePooN/bancho.js/commits/master)
|
|
5
5
|
|
|
6
|
-
## Current release: 0.
|
|
6
|
+
## Current release: 0.12.0
|
|
7
7
|
|
|
8
8
|
# Introduction
|
|
9
9
|
|
package/index.d.ts
CHANGED
|
@@ -5,17 +5,17 @@ declare module "bancho.js" {
|
|
|
5
5
|
|
|
6
6
|
export class BanchoClient extends EventEmitter {
|
|
7
7
|
constructor(options: BanchoClientOptions)
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
/**
|
|
10
10
|
* Populated with a Nodesu client, if api key is passed to the constructor
|
|
11
11
|
*/
|
|
12
12
|
osuApi: nodesu.Client
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
/**
|
|
15
15
|
* Get a BanchoUser instance for the specified user
|
|
16
16
|
*/
|
|
17
17
|
getUser(username: string): BanchoUser
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
/**
|
|
20
20
|
* Get a BanchoUser representing ourself
|
|
21
21
|
*/
|
|
@@ -25,7 +25,7 @@ declare module "bancho.js" {
|
|
|
25
25
|
* Get a BanchoUser instance for the specified user id
|
|
26
26
|
*/
|
|
27
27
|
getUserById(userid: number): Promise<BanchoUser>
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
/**
|
|
30
30
|
* Get a BanchoChannel instance for the specified name
|
|
31
31
|
*/
|
|
@@ -37,99 +37,99 @@ declare module "bancho.js" {
|
|
|
37
37
|
* @param privateLobby Mark as private
|
|
38
38
|
*/
|
|
39
39
|
createLobby(name: string, private?: boolean): Promise<BanchoMultiplayerChannel>
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
/**
|
|
42
42
|
* Connects to Bancho, rejects an Error if connection fails
|
|
43
43
|
*/
|
|
44
44
|
connect(): Promise<null>
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
/**
|
|
47
47
|
* Disconnects from Bancho
|
|
48
48
|
*/
|
|
49
49
|
disconnect(): void
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
/**
|
|
52
52
|
* Returns the current connection state.
|
|
53
53
|
*/
|
|
54
54
|
getConnectState(): Symbol
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
/**
|
|
57
57
|
* Returns true if the connectState is Connected, false otherwise.
|
|
58
58
|
*/
|
|
59
59
|
isConnected(): boolean
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
/**
|
|
62
62
|
* Returns true if the connectState is Disconnected, otherwise false.
|
|
63
63
|
*/
|
|
64
64
|
isDisconnected(): boolean
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
/**
|
|
67
67
|
* Registers a listener for channel messages.
|
|
68
68
|
* @param listener the callback
|
|
69
69
|
*/
|
|
70
70
|
on(event: "CM", listener: (message: ChannelMessage) => void): this
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
/**
|
|
73
73
|
* Registers a listener for the successful connection events.
|
|
74
74
|
* @param listener the callback
|
|
75
75
|
*/
|
|
76
76
|
on(event: "connected", listener: () => void): this
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
/**
|
|
79
79
|
* Registers a listener for the disconnection events.
|
|
80
80
|
* @param listener the callback
|
|
81
81
|
*/
|
|
82
82
|
on(event: "disconnected", listener: (error: Error) => void): this
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
/**
|
|
85
85
|
* Registers a listener for errors.
|
|
86
86
|
* @param listener the callback
|
|
87
87
|
*/
|
|
88
88
|
on(event: "error", listener: (error: Error) => void): this
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
/**
|
|
91
91
|
* Registers a listener for when a user joins a channel.
|
|
92
92
|
* @param listener the callback
|
|
93
93
|
*/
|
|
94
94
|
on(event: "JOIN", listener: (member: BanchoChannelMember) => void): this
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
/**
|
|
97
97
|
* Registers a listener for when a user leaves a channel.
|
|
98
98
|
* @param listener the callback
|
|
99
99
|
*/
|
|
100
100
|
on(event: "PART", listener: (member: BanchoChannelMember) => void): this
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
/**
|
|
103
103
|
* Registers a listener for when the client fails to enter a non-existant channel.
|
|
104
104
|
* @param listener the callback with the concerned BanchoChannel
|
|
105
105
|
*/
|
|
106
106
|
on(event: "nochannel", listener: (channel: BanchoChannel) => void): this
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
/**
|
|
109
109
|
* Registers a listener for when the client tries to execute something for an offline user.
|
|
110
110
|
* @param listener the callback with the concerned BanchoUser
|
|
111
111
|
*/
|
|
112
112
|
on(event: "nouser", listener: (user: BanchoUser) => void): this
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
/**
|
|
115
115
|
* Registers a listener for private messages.
|
|
116
116
|
* @param listener the callback
|
|
117
117
|
*/
|
|
118
118
|
on(event: "PM", listener: (message: PrivateMessage) => void): this
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
/**
|
|
121
121
|
* Registers a listener for when Bancho sends us back a PM that couldn't be sent.
|
|
122
122
|
* As far as we know, only happens when a PM is rejected because the recipient blocks messages from non-friends.
|
|
123
123
|
* @param listener the callback with the concerned PrivateMessage
|
|
124
124
|
*/
|
|
125
125
|
on(event: "rejectedMessage", listener: (message: PrivateMessage) => void): this
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
/**
|
|
128
128
|
* Registers a listener for client state changes.
|
|
129
129
|
* @param listener the callback with a Symbol from ConnectStates and a possible error.
|
|
130
130
|
*/
|
|
131
131
|
on(event: "state", listener: (state: Symbol, error?: Error) => void): this
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
export class BanchoUser extends EventEmitter {
|
|
@@ -138,10 +138,10 @@ declare module "bancho.js" {
|
|
|
138
138
|
* @param banchojs Bancho.js client this user was instancied by
|
|
139
139
|
*/
|
|
140
140
|
constructor(banchojs: BanchoClient, ircUsername: string)
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
banchojs: BanchoClient
|
|
143
143
|
ircUsername: string
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
id: number
|
|
146
146
|
username: string
|
|
147
147
|
joinDate: Date
|
|
@@ -162,19 +162,19 @@ declare module "bancho.js" {
|
|
|
162
162
|
totalSecondsPlayed: number
|
|
163
163
|
ppCountryRank: number
|
|
164
164
|
events: Array<nodesu.UserEvent>
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
/**
|
|
167
167
|
* Fetch the user from the osu! API if possible. Populates all the "optional" properties of BanchoUser.
|
|
168
|
-
*
|
|
168
|
+
*
|
|
169
169
|
* @throws {Error} osu! API/no API key error
|
|
170
170
|
*/
|
|
171
171
|
fetchFromAPI(): Promise<nodesu.User>
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
/**
|
|
174
174
|
* Returns true if the user is the client
|
|
175
175
|
*/
|
|
176
176
|
isClient(): boolean
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
/**
|
|
179
179
|
* Sends a PM to this user.
|
|
180
180
|
*/
|
|
@@ -261,7 +261,7 @@ declare module "bancho.js" {
|
|
|
261
261
|
constructor(banchojs: BanchoClient, recipient: BanchoUser|BanchoChannel, message: string)
|
|
262
262
|
/**
|
|
263
263
|
* Sends the prepared message to the recipient
|
|
264
|
-
*
|
|
264
|
+
*
|
|
265
265
|
* @throws {Error} If recipient isn't a valid type
|
|
266
266
|
*/
|
|
267
267
|
send(): Promise<null>
|
|
@@ -288,7 +288,7 @@ declare module "bancho.js" {
|
|
|
288
288
|
channelMembers: Map<string, BanchoChannelMember>
|
|
289
289
|
/**
|
|
290
290
|
* Sends a message to this channel
|
|
291
|
-
*
|
|
291
|
+
*
|
|
292
292
|
* Elevated Bancho users are advised to heavily sanitize their inputs.
|
|
293
293
|
*/
|
|
294
294
|
sendMessage(message: string): Promise<null>
|
|
@@ -304,13 +304,13 @@ declare module "bancho.js" {
|
|
|
304
304
|
* @param listener the callback with the message
|
|
305
305
|
*/
|
|
306
306
|
on(event: "message", listener: (message: BanchoMessage) => void): this
|
|
307
|
-
|
|
307
|
+
|
|
308
308
|
/**
|
|
309
309
|
* Registers a listener for when a user joins this channel.
|
|
310
310
|
* @param listener the callback
|
|
311
311
|
*/
|
|
312
312
|
on(event: "JOIN", listener: (member: BanchoChannelMember) => void): this
|
|
313
|
-
|
|
313
|
+
|
|
314
314
|
/**
|
|
315
315
|
* Registers a listener for when a user leaves this channel.
|
|
316
316
|
* @param listener the callback
|
|
@@ -328,7 +328,7 @@ declare module "bancho.js" {
|
|
|
328
328
|
|
|
329
329
|
/**
|
|
330
330
|
* Represents a Bancho multiplayer lobby.
|
|
331
|
-
*
|
|
331
|
+
*
|
|
332
332
|
* Highly recommended to await updateSettings before manipulating (else some properties will be null).
|
|
333
333
|
*/
|
|
334
334
|
export class BanchoLobby extends EventEmitter {
|
|
@@ -348,7 +348,7 @@ declare module "bancho.js" {
|
|
|
348
348
|
/**
|
|
349
349
|
* Array of BanchoLobbyPlayer determining each users' slot, from 0 to 15
|
|
350
350
|
*/
|
|
351
|
-
slots: Array<BanchoLobbyPlayer>
|
|
351
|
+
slots: Array<BanchoLobbyPlayer | null>
|
|
352
352
|
/**
|
|
353
353
|
* Current size of the lobby
|
|
354
354
|
*/
|
|
@@ -356,7 +356,7 @@ declare module "bancho.js" {
|
|
|
356
356
|
gamemode: nodesu.ModeType
|
|
357
357
|
/**
|
|
358
358
|
* Beatmap fetched from the API (late/not as reliable, use beatmapId when possible)
|
|
359
|
-
*
|
|
359
|
+
*
|
|
360
360
|
*/
|
|
361
361
|
beatmap: nodesu.Beatmap
|
|
362
362
|
beatmapId: number
|
|
@@ -436,7 +436,7 @@ declare module "bancho.js" {
|
|
|
436
436
|
* @param winCondition See BanchoLobbyWinConditions
|
|
437
437
|
*/
|
|
438
438
|
setSettings(teamMode?: number, winCondition?: number, size?: number): Promise<null>
|
|
439
|
-
|
|
439
|
+
|
|
440
440
|
/**
|
|
441
441
|
* Moves a player from one slot to another
|
|
442
442
|
* @param slot starting from 0
|
|
@@ -650,8 +650,8 @@ declare module "bancho.js" {
|
|
|
650
650
|
/** A Bancho channel member */
|
|
651
651
|
export class BanchoChannelMember {
|
|
652
652
|
/**
|
|
653
|
-
* @param client
|
|
654
|
-
* @param channel
|
|
653
|
+
* @param client
|
|
654
|
+
* @param channel
|
|
655
655
|
* @param userString Username with optional @ or + prefix (that will automatically determine the role)
|
|
656
656
|
*/
|
|
657
657
|
constructor(client: BanchoClient, channel: BanchoChannel, userString: string)
|
|
@@ -753,7 +753,7 @@ declare module "bancho.js" {
|
|
|
753
753
|
/**
|
|
754
754
|
* Parse mods in their bit flags form and returns them in an array of BanchoMods.
|
|
755
755
|
* @param bits Mods combination in bit flags form
|
|
756
|
-
* @param returnNone Returns [BanchoMods.None] if bits is equal to 0
|
|
756
|
+
* @param returnNone Returns [BanchoMods.None] if bits is equal to 0
|
|
757
757
|
*/
|
|
758
758
|
parseBitFlags(bits: number, returnNone?: boolean): BanchoMod[]
|
|
759
759
|
/**
|
|
@@ -888,23 +888,23 @@ declare module "bancho.js" {
|
|
|
888
888
|
* Contains the different connect states: Disconnected, Connecting, Reconnecting, Connected.
|
|
889
889
|
*/
|
|
890
890
|
type ConnectStateTypes = {
|
|
891
|
-
/**
|
|
892
|
-
* When we're purposely disconnected from Bancho or after an auth fail
|
|
891
|
+
/**
|
|
892
|
+
* When we're purposely disconnected from Bancho or after an auth fail
|
|
893
893
|
*/
|
|
894
894
|
Disconnected: Symbol,
|
|
895
|
-
|
|
896
|
-
/**
|
|
897
|
-
* When we've opened the socket before any reconnection attempts and waiting for the Welcome packet
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* When we've opened the socket before any reconnection attempts and waiting for the Welcome packet
|
|
898
898
|
*/
|
|
899
899
|
Connecting: Symbol,
|
|
900
|
-
|
|
901
|
-
/**
|
|
902
|
-
* When we've gotten disconnected, and are currently waiting before trying to reconnect
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* When we've gotten disconnected, and are currently waiting before trying to reconnect
|
|
903
903
|
*/
|
|
904
904
|
Reconnecting: Symbol,
|
|
905
|
-
|
|
906
|
-
/**
|
|
907
|
-
* When we're online! \o/
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* When we're online! \o/
|
|
908
908
|
*/
|
|
909
909
|
Connected: Symbol
|
|
910
910
|
}
|
package/lib/BanchoChannel.js
CHANGED
|
@@ -97,6 +97,8 @@ class BanchoChannel extends EventEmitter {
|
|
|
97
97
|
* @returns {Promise<null>}
|
|
98
98
|
*/
|
|
99
99
|
join() {
|
|
100
|
+
if (this.joined)
|
|
101
|
+
return Promise.resolve();
|
|
100
102
|
return this._joinOrPart("JOIN", "joinCallback", "joinPromise");
|
|
101
103
|
}
|
|
102
104
|
|
|
@@ -107,6 +109,8 @@ class BanchoChannel extends EventEmitter {
|
|
|
107
109
|
* @returns {Promise<null>}
|
|
108
110
|
*/
|
|
109
111
|
leave() {
|
|
112
|
+
if (!this.joined)
|
|
113
|
+
return Promise.resolve();
|
|
110
114
|
return this._joinOrPart("PART", "partCallback", "partPromise");
|
|
111
115
|
}
|
|
112
116
|
|
|
@@ -137,4 +141,4 @@ class BanchoChannel extends EventEmitter {
|
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
143
|
|
|
140
|
-
module.exports = BanchoChannel;
|
|
144
|
+
module.exports = BanchoChannel;
|
package/lib/BanchoClient.js
CHANGED
|
@@ -103,7 +103,7 @@ class BanchoClient extends EventEmitter {
|
|
|
103
103
|
this.setMaxListeners(50);
|
|
104
104
|
if(!this.username || !this.password)
|
|
105
105
|
throw new Error("You gotta gimme an username and a password to connect to Bancho dumbass");
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
this.client = null;
|
|
108
108
|
this.connectState = ConnectStates.Disconnected;
|
|
109
109
|
this.reconnect = true;
|
|
@@ -115,6 +115,7 @@ class BanchoClient extends EventEmitter {
|
|
|
115
115
|
this.usersById = new CacheMap();
|
|
116
116
|
this.channels = {};
|
|
117
117
|
this.messagesQueue = [];
|
|
118
|
+
this.lobbyCreationQueue = [];
|
|
118
119
|
|
|
119
120
|
// Register our own error listener so there are no uncaught exceptions
|
|
120
121
|
// for exceptions WE throw for the end-user that don't need to be caught (such as timeouts)
|
|
@@ -151,10 +152,11 @@ class BanchoClient extends EventEmitter {
|
|
|
151
152
|
else if(message.recipient instanceof BanchoChannel)
|
|
152
153
|
this.emit("CM", new ChannelMessage(this.getSelf(), content, true, message.recipient));
|
|
153
154
|
|
|
154
|
-
this.messagesQueue.shift();
|
|
155
155
|
resolve();
|
|
156
156
|
} catch(e) {
|
|
157
157
|
reject(e);
|
|
158
|
+
} finally {
|
|
159
|
+
this.messagesQueue.shift();
|
|
158
160
|
}
|
|
159
161
|
}
|
|
160
162
|
}
|
|
@@ -176,7 +178,7 @@ class BanchoClient extends EventEmitter {
|
|
|
176
178
|
this.emit("error", err);
|
|
177
179
|
this.onClose(err);
|
|
178
180
|
});
|
|
179
|
-
|
|
181
|
+
|
|
180
182
|
this.client.on("close", () => {
|
|
181
183
|
if(!this.ignoreClose)
|
|
182
184
|
this.onClose(new Error("Connection closed"));
|
|
@@ -205,7 +207,7 @@ class BanchoClient extends EventEmitter {
|
|
|
205
207
|
|
|
206
208
|
/**
|
|
207
209
|
* Send raw data over IRC.
|
|
208
|
-
* @param {string} data
|
|
210
|
+
* @param {string} data
|
|
209
211
|
* @param {boolean} throwIfDisconnected Throws an Error if we're disconnected
|
|
210
212
|
* @private
|
|
211
213
|
*/
|
|
@@ -218,7 +220,7 @@ class BanchoClient extends EventEmitter {
|
|
|
218
220
|
|
|
219
221
|
/**
|
|
220
222
|
* Update connection state
|
|
221
|
-
* @param {ConnectState} newConnectState
|
|
223
|
+
* @param {ConnectState} newConnectState
|
|
222
224
|
* @param {Error} err Error to emit with the new state
|
|
223
225
|
* @fires BanchoClient#connected
|
|
224
226
|
* @fires BanchoClient#disconnected
|
|
@@ -257,7 +259,7 @@ class BanchoClient extends EventEmitter {
|
|
|
257
259
|
|
|
258
260
|
/**
|
|
259
261
|
* Executed when connection is expectedly or not closed
|
|
260
|
-
* @param {Error} err
|
|
262
|
+
* @param {Error} err
|
|
261
263
|
* @private
|
|
262
264
|
*/
|
|
263
265
|
onClose(err) {
|
|
@@ -268,14 +270,14 @@ class BanchoClient extends EventEmitter {
|
|
|
268
270
|
|
|
269
271
|
if(this.connectState == ConnectStates.Disconnected)
|
|
270
272
|
return;
|
|
271
|
-
|
|
273
|
+
|
|
272
274
|
if(!this.reconnect)
|
|
273
275
|
return this.updateState(ConnectStates.Disconnected, err);
|
|
274
|
-
|
|
276
|
+
|
|
275
277
|
this.updateState(ConnectStates.Reconnecting, err);
|
|
276
278
|
if(this.reconnectTimeout)
|
|
277
279
|
clearTimeout(this.reconnectTimeout);
|
|
278
|
-
|
|
280
|
+
|
|
279
281
|
this.reconnectTimeout = setTimeout(() => {
|
|
280
282
|
if(this.reconnect) {
|
|
281
283
|
const oldCallback = this.connectCallback;
|
|
@@ -288,7 +290,7 @@ class BanchoClient extends EventEmitter {
|
|
|
288
290
|
|
|
289
291
|
/**
|
|
290
292
|
* Handle incoming IRC commands from Bancho
|
|
291
|
-
* @param {string} command
|
|
293
|
+
* @param {string} command
|
|
292
294
|
* @private
|
|
293
295
|
*/
|
|
294
296
|
handleIrcCommand(command) {
|
|
@@ -309,8 +311,8 @@ class BanchoClient extends EventEmitter {
|
|
|
309
311
|
|
|
310
312
|
/**
|
|
311
313
|
* Get a BanchoUser instance for the specified username
|
|
312
|
-
*
|
|
313
|
-
* @param {string} username
|
|
314
|
+
*
|
|
315
|
+
* @param {string} username
|
|
314
316
|
* @returns {BanchoUser}
|
|
315
317
|
*/
|
|
316
318
|
getUser(username) {
|
|
@@ -332,7 +334,7 @@ class BanchoClient extends EventEmitter {
|
|
|
332
334
|
|
|
333
335
|
/**
|
|
334
336
|
* Get a BanchoUser instance for the specified user id
|
|
335
|
-
*
|
|
337
|
+
*
|
|
336
338
|
* @async
|
|
337
339
|
* @param {number} userid
|
|
338
340
|
* @returns {Promise<BanchoUser>}
|
|
@@ -355,8 +357,8 @@ class BanchoClient extends EventEmitter {
|
|
|
355
357
|
|
|
356
358
|
/**
|
|
357
359
|
* Get a BanchoChannel instance for the specified name
|
|
358
|
-
*
|
|
359
|
-
* @param {string} channelName
|
|
360
|
+
*
|
|
361
|
+
* @param {string} channelName
|
|
360
362
|
* @returns {BanchoChannel|BanchoMultiplayerChannel}
|
|
361
363
|
*/
|
|
362
364
|
getChannel(channelName) {
|
|
@@ -372,7 +374,7 @@ class BanchoClient extends EventEmitter {
|
|
|
372
374
|
|
|
373
375
|
/**
|
|
374
376
|
* Creates a multiplayer lobby and return its channel.
|
|
375
|
-
*
|
|
377
|
+
*
|
|
376
378
|
* @async
|
|
377
379
|
* @param {string} name Lobby name
|
|
378
380
|
* @param {boolean} [privateLobby] Mark as private
|
|
@@ -385,33 +387,58 @@ class BanchoClient extends EventEmitter {
|
|
|
385
387
|
if(!name || !name.trim())
|
|
386
388
|
throw new Error("Empty name!");
|
|
387
389
|
name = name.trim();
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
reject(new Error("Multiplayer lobby creation timeout has been reached!"));
|
|
394
|
-
}, 10000);
|
|
395
|
-
const matchCreatedRegex = /Created the tournament match https:\/\/osu\.ppy\.sh\/mp\/(\d+) (.+)/;
|
|
396
|
-
const listener = (msg) => {
|
|
397
|
-
const m = matchCreatedRegex.exec(msg.message);
|
|
398
|
-
if(!m || m[2] != name)
|
|
399
|
-
return;
|
|
400
|
-
|
|
401
|
-
BanchoBot.removeListener("message", listener);
|
|
402
|
-
const channel = this.getChannel("#mp_"+Number(m[1]));
|
|
403
|
-
if(!channel.lobby)
|
|
404
|
-
return reject(new Error("Not a multiplayer channel?! This shouldn't happen..."));
|
|
405
|
-
resolve(channel);
|
|
406
|
-
};
|
|
407
|
-
BanchoBot.on("message", listener);
|
|
390
|
+
this.lobbyCreationQueue.push({
|
|
391
|
+
name,
|
|
392
|
+
privateLobby,
|
|
393
|
+
resolve,
|
|
394
|
+
reject,
|
|
408
395
|
});
|
|
396
|
+
if(this.lobbyCreationQueue.length === 1)
|
|
397
|
+
this.processLobbyCreationQueue();
|
|
409
398
|
});
|
|
410
399
|
}
|
|
411
400
|
|
|
401
|
+
async processLobbyCreationQueue() {
|
|
402
|
+
while(this.lobbyCreationQueue[0]) {
|
|
403
|
+
const { name, privateLobby, resolve, reject } = this.lobbyCreationQueue[0];
|
|
404
|
+
|
|
405
|
+
try {
|
|
406
|
+
if(!this.isConnected())
|
|
407
|
+
throw new Error("Currently disconnected!");
|
|
408
|
+
|
|
409
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
410
|
+
resolve(await new Promise(async (resolve, reject) => {
|
|
411
|
+
const BanchoBot = this.getUser("BanchoBot");
|
|
412
|
+
const command = !privateLobby ? "make" : "makeprivate";
|
|
413
|
+
await BanchoBot.sendMessage("!mp "+command+" "+name);
|
|
414
|
+
setTimeout(() => {
|
|
415
|
+
reject(new Error("Multiplayer lobby creation timeout has been reached!"));
|
|
416
|
+
}, 10000);
|
|
417
|
+
const matchCreatedRegex = /Created the tournament match https:\/\/osu\.ppy\.sh\/mp\/(\d+) (.+)/;
|
|
418
|
+
const listener = (msg) => {
|
|
419
|
+
const m = matchCreatedRegex.exec(msg.message);
|
|
420
|
+
if(!m)
|
|
421
|
+
return;
|
|
422
|
+
|
|
423
|
+
BanchoBot.removeListener("message", listener);
|
|
424
|
+
const channel = this.getChannel("#mp_"+Number(m[1]));
|
|
425
|
+
if(!channel.lobby)
|
|
426
|
+
return reject(new Error("Not a multiplayer channel?! This shouldn't happen..."));
|
|
427
|
+
resolve(channel);
|
|
428
|
+
};
|
|
429
|
+
BanchoBot.on("message", listener);
|
|
430
|
+
}));
|
|
431
|
+
} catch(e) {
|
|
432
|
+
reject(e);
|
|
433
|
+
} finally {
|
|
434
|
+
this.lobbyCreationQueue.shift();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
412
439
|
/**
|
|
413
440
|
* Connects to Bancho, rejects an Error if connection fails
|
|
414
|
-
*
|
|
441
|
+
*
|
|
415
442
|
* @method
|
|
416
443
|
* @async
|
|
417
444
|
* @return {Promise<null, Error>}
|
|
@@ -421,7 +448,7 @@ class BanchoClient extends EventEmitter {
|
|
|
421
448
|
if(this.connectState == ConnectStates.Connected ||
|
|
422
449
|
this.connectState == ConnectStates.Connecting)
|
|
423
450
|
return reject(new Error("Already connected/connecting"));
|
|
424
|
-
|
|
451
|
+
|
|
425
452
|
this.connectCallback = (err) => {
|
|
426
453
|
if(err)
|
|
427
454
|
return reject(err);
|
|
@@ -441,18 +468,18 @@ class BanchoClient extends EventEmitter {
|
|
|
441
468
|
|
|
442
469
|
/**
|
|
443
470
|
* Disconnects from Bancho
|
|
444
|
-
*
|
|
471
|
+
*
|
|
445
472
|
* @method
|
|
446
473
|
*/
|
|
447
474
|
disconnect() {
|
|
448
475
|
if(this.connectState == ConnectStates.Disconnected)
|
|
449
476
|
return;
|
|
450
|
-
|
|
477
|
+
|
|
451
478
|
if(this.isConnected())
|
|
452
479
|
this.send("QUIT");
|
|
453
480
|
else if(this.connectState == ConnectStates.Connecting)
|
|
454
481
|
this.client.destroy();
|
|
455
|
-
|
|
482
|
+
|
|
456
483
|
if(this.reconnectTimeout) {
|
|
457
484
|
clearTimeout(this.reconnectTimeout);
|
|
458
485
|
this.reconnectTimeout = null;
|
|
@@ -463,7 +490,7 @@ class BanchoClient extends EventEmitter {
|
|
|
463
490
|
|
|
464
491
|
/**
|
|
465
492
|
* When we've just connected, execute the connect callback
|
|
466
|
-
*
|
|
493
|
+
*
|
|
467
494
|
* @param {any} arg Arg to pass to the callback
|
|
468
495
|
* @param {boolean} [erase=true] Erase the existing callback
|
|
469
496
|
* @param {boolean} [throwIfNonexistant=false] Throw an error if the callback doesn't exist
|
|
@@ -481,16 +508,16 @@ class BanchoClient extends EventEmitter {
|
|
|
481
508
|
|
|
482
509
|
/**
|
|
483
510
|
* Returns the current connection state.
|
|
484
|
-
*
|
|
511
|
+
*
|
|
485
512
|
* @returns {Symbol} Current connection state. See ConnectStates
|
|
486
513
|
*/
|
|
487
514
|
getConnectState() {
|
|
488
515
|
return this.connectState;
|
|
489
516
|
}
|
|
490
|
-
|
|
517
|
+
|
|
491
518
|
/**
|
|
492
519
|
* Returns true if the connectState is Connected, otherwise false.
|
|
493
|
-
*
|
|
520
|
+
*
|
|
494
521
|
* @returns {boolean}
|
|
495
522
|
*/
|
|
496
523
|
isConnected() {
|
|
@@ -499,7 +526,7 @@ class BanchoClient extends EventEmitter {
|
|
|
499
526
|
|
|
500
527
|
/**
|
|
501
528
|
* Returns true if the connectState is Disconnected, otherwise false.
|
|
502
|
-
*
|
|
529
|
+
*
|
|
503
530
|
* @returns {boolean}
|
|
504
531
|
*/
|
|
505
532
|
isDisconnected() {
|
|
@@ -507,4 +534,4 @@ class BanchoClient extends EventEmitter {
|
|
|
507
534
|
}
|
|
508
535
|
}
|
|
509
536
|
|
|
510
|
-
module.exports = BanchoClient;
|
|
537
|
+
module.exports = BanchoClient;
|
|
@@ -14,26 +14,27 @@ class JoinCommand extends IrcCommand {
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Emits the JOIN event
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* @fires BanchoClient#JOIN
|
|
19
|
-
* @param {BanchoClient} client
|
|
19
|
+
* @param {BanchoClient} client
|
|
20
20
|
* @param {BanchoUser} user
|
|
21
|
-
* @param {BanchoChannel} channel
|
|
21
|
+
* @param {BanchoChannel} channel
|
|
22
22
|
*/
|
|
23
23
|
emit(client, user, channel) {
|
|
24
|
-
/**
|
|
25
|
-
* Fired when a user has joined a channel
|
|
26
|
-
* @event BanchoClient#JOIN
|
|
27
|
-
* @type {BanchoChannelMember}
|
|
28
|
-
*/
|
|
29
24
|
const member = new BanchoChannelMember(client, channel, user.ircUsername);
|
|
30
25
|
channel.channelMembers.set(user.ircUsername, member);
|
|
31
|
-
client.emit("JOIN", member);
|
|
32
26
|
if(user.isClient()) {
|
|
33
27
|
channel.joined = true;
|
|
34
28
|
if(channel.joinCallback != null)
|
|
35
29
|
channel.joinCallback();
|
|
36
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fired when a user has joined a channel
|
|
34
|
+
* @event BanchoClient#JOIN
|
|
35
|
+
* @type {BanchoChannelMember}
|
|
36
|
+
*/
|
|
37
|
+
client.emit("JOIN", member);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
handleCommand(client, command, splits) {
|
|
@@ -43,4 +44,4 @@ class JoinCommand extends IrcCommand {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
module.exports = JoinCommand;
|
|
47
|
+
module.exports = JoinCommand;
|
|
@@ -13,27 +13,31 @@ class PartCommand extends JoinCommand {
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Emits the PART event
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* @fires BanchoClient#PART
|
|
18
|
-
* @param {BanchoClient} client
|
|
19
|
-
* @param {BanchoUser} user
|
|
20
|
-
* @param {BanchoChannel} channel
|
|
18
|
+
* @param {BanchoClient} client
|
|
19
|
+
* @param {BanchoUser} user
|
|
20
|
+
* @param {BanchoChannel} channel
|
|
21
21
|
*/
|
|
22
22
|
emit(client, user, channel) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* @event BanchoClient#PART
|
|
26
|
-
* @type {BanchoChannelMember}
|
|
27
|
-
*/
|
|
28
|
-
if(channel.channelMembers.has(user.ircUsername))
|
|
29
|
-
client.emit("PART", channel.channelMembers.get(user.ircUsername));
|
|
23
|
+
const member = channel.channelMembers.get(user.ircUsername);
|
|
24
|
+
|
|
30
25
|
if(user.isClient()) {
|
|
31
26
|
channel.joined = false;
|
|
32
27
|
channel.channelMembers.clear();
|
|
33
28
|
if(channel.partCallback != null)
|
|
34
29
|
channel.partCallback();
|
|
30
|
+
} else {
|
|
31
|
+
channel.channelMembers.delete(user.ircUsername);
|
|
35
32
|
}
|
|
36
|
-
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Fired when a user has left a channel
|
|
36
|
+
* @event BanchoClient#PART
|
|
37
|
+
* @type {BanchoChannelMember}
|
|
38
|
+
*/
|
|
39
|
+
if(member)
|
|
40
|
+
client.emit("PART", member);
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
package/package.json
CHANGED
package/tests/TestGoals.js
CHANGED
|
@@ -19,6 +19,8 @@ const TestGoals = {
|
|
|
19
19
|
MultiplayerScoresSorting: Symbol("MultiplayerScoresSorting"),
|
|
20
20
|
|
|
21
21
|
MultiplayerLobbyExists: Symbol("MultiplayerLobbyExists"),
|
|
22
|
+
MultiplayerLobbyUpdateSettings: Symbol("MultiplayerLobbyUpdateSettings"),
|
|
23
|
+
MultiplayerLobbyNamed: Symbol("MultiplayerLobbyNamed"),
|
|
22
24
|
MultiplayerLobbySetMap: Symbol("MultiplayerLobbySetMap"),
|
|
23
25
|
MultiplayerLobbySetModsDTFree: Symbol("MultiplayerLobbySetModsDTFree"),
|
|
24
26
|
MultiplayerLobbySetModsHDHR: Symbol("MultiplayerLobbySetModsHDHR"),
|
|
@@ -35,4 +37,4 @@ const TestGoals = {
|
|
|
35
37
|
MultiplayerLobbyCloseLobby: Symbol("MultiplayerLobbyCloseLobby")
|
|
36
38
|
};
|
|
37
39
|
|
|
38
|
-
module.exports = Object.freeze(TestGoals);
|
|
40
|
+
module.exports = Object.freeze(TestGoals);
|
|
@@ -10,38 +10,34 @@ class JoinEventChannelUnit extends TestUnit {
|
|
|
10
10
|
run() {
|
|
11
11
|
return new Promise((resolve, reject) => {
|
|
12
12
|
const channel = this.client.getChannel("#french");
|
|
13
|
-
let returned = false;
|
|
14
13
|
this.client.on("JOIN", (obj) => {
|
|
15
14
|
if(obj.user.isClient() && obj.channel == channel) {
|
|
16
15
|
this.fulFillGoal(TestGoals.JoinEvent);
|
|
17
|
-
channel.leave(channel);
|
|
18
16
|
|
|
19
17
|
this.client.on("PART", (obj) => {
|
|
20
18
|
if(obj.user.isClient() && obj.channel == channel) {
|
|
21
19
|
this.client.removeAllListeners("JOIN");
|
|
22
20
|
this.client.removeAllListeners("nochannel");
|
|
21
|
+
this.client.removeAllListeners("PART");
|
|
23
22
|
this.fulFillGoal(TestGoals.PartEvent);
|
|
24
|
-
returned = true;
|
|
25
23
|
resolve();
|
|
26
24
|
}
|
|
27
25
|
});
|
|
26
|
+
channel.leave(channel);
|
|
28
27
|
}
|
|
29
28
|
});
|
|
30
29
|
this.client.on("nochannel", (errorChannel) => {
|
|
31
30
|
if(errorChannel == channel) {
|
|
32
31
|
this.client.removeAllListeners("JOIN");
|
|
33
32
|
this.client.removeAllListeners("nochannel");
|
|
34
|
-
|
|
33
|
+
this.client.removeAllListeners("PART");
|
|
35
34
|
reject(new Error("No such channel: "+errorChannel.name));
|
|
36
35
|
}
|
|
37
36
|
});
|
|
38
37
|
channel.join();
|
|
39
|
-
setTimeout(() =>
|
|
40
|
-
if(!returned)
|
|
41
|
-
reject(new Error("Didn't join after timeout!"));
|
|
42
|
-
}, 10000);
|
|
38
|
+
setTimeout(() => reject(new Error("Didn't join and leave after timeout!")), 10000);
|
|
43
39
|
});
|
|
44
40
|
}
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
module.exports = new JoinEventChannelUnit();
|
|
43
|
+
module.exports = new JoinEventChannelUnit();
|
|
@@ -20,6 +20,11 @@ class MultiplayerLobbiesUnit extends TestUnit {
|
|
|
20
20
|
if(!channel.lobby)
|
|
21
21
|
throw new Error("lobby doesn't exist! this is a regular channel, not a multiplayer one!");
|
|
22
22
|
this.fulFillGoal(TestGoals.MultiplayerLobbyExists);
|
|
23
|
+
await channel.lobby.updateSettings();
|
|
24
|
+
this.fulFillGoal(TestGoals.MultiplayerLobbyUpdateSettings);
|
|
25
|
+
if(channel.lobby.name !== roomName)
|
|
26
|
+
throw new Error("lobby name doesn't match!");
|
|
27
|
+
this.fulFillGoal(TestGoals.MultiplayerLobbyNamed);
|
|
23
28
|
await channel.lobby.setMap(75);
|
|
24
29
|
this.fulFillGoal(TestGoals.MultiplayerLobbySetMap);
|
|
25
30
|
await channel.lobby.setMods([BanchoMods.enum.DoubleTime], true);
|
|
@@ -54,4 +59,4 @@ class MultiplayerLobbiesUnit extends TestUnit {
|
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
module.exports = new MultiplayerLobbiesUnit();
|
|
62
|
+
module.exports = new MultiplayerLobbiesUnit();
|