@rbxts/tether 1.2.0 → 1.2.1
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/README.md +23 -24
- package/out/builtin-middlewares.d.ts +8 -0
- package/out/builtin-middlewares.luau +27 -1
- package/out/message-emitter.d.ts +1 -1
- package/out/message-emitter.luau +22 -7
- package/out/middleware.d.ts +9 -6
- package/out/middleware.luau +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,28 +24,26 @@ export interface MessageData {
|
|
|
24
24
|
readonly n: DataType.u8;
|
|
25
25
|
};
|
|
26
26
|
[Message.Packed]: DataType.Packed<{
|
|
27
|
-
boolean1: boolean;
|
|
28
|
-
boolean2: boolean;
|
|
29
|
-
boolean3: boolean;
|
|
30
|
-
boolean4: boolean;
|
|
31
|
-
boolean5: boolean;
|
|
32
|
-
boolean6: boolean;
|
|
33
|
-
boolean7: boolean;
|
|
34
|
-
boolean8: boolean;
|
|
27
|
+
readonly boolean1: boolean;
|
|
28
|
+
readonly boolean2: boolean;
|
|
29
|
+
readonly boolean3: boolean;
|
|
30
|
+
readonly boolean4: boolean;
|
|
31
|
+
readonly boolean5: boolean;
|
|
32
|
+
readonly boolean6: boolean;
|
|
33
|
+
readonly boolean7: boolean;
|
|
34
|
+
readonly boolean8: boolean;
|
|
35
35
|
}>;
|
|
36
36
|
}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
> [!CAUTION]
|
|
40
|
-
> Every single message kind must implement an interface for it's data (in the example that would be the object
|
|
40
|
+
> Every single message kind must implement an interface for it's data (in the example that would be the object types in `MessageData`). Message serialization (as well as your message itself) will not work if you don't do this.
|
|
41
41
|
|
|
42
42
|
### Server
|
|
43
43
|
```ts
|
|
44
44
|
import { Message, messaging } from "shared/messaging";
|
|
45
45
|
|
|
46
|
-
messaging.server.on(Message.Test, (player, data) =>
|
|
47
|
-
print(player, "sent data:", data);
|
|
48
|
-
});
|
|
46
|
+
messaging.server.on(Message.Test, (player, data) => print(player, "sent data:", data));
|
|
49
47
|
```
|
|
50
48
|
|
|
51
49
|
### Client
|
|
@@ -116,7 +114,7 @@ Drop, delay, or modify requests
|
|
|
116
114
|
import type { ClientMiddleware } from "@rbxts/tether";
|
|
117
115
|
|
|
118
116
|
export function logClient(): ClientMiddleware {
|
|
119
|
-
return message => (player,
|
|
117
|
+
return message => (player, ctx) => print(`[LOG]: Sent message '${message}' to player ${player} with data:`, ctx.data);
|
|
120
118
|
}
|
|
121
119
|
```
|
|
122
120
|
|
|
@@ -125,7 +123,7 @@ export function logClient(): ClientMiddleware {
|
|
|
125
123
|
import type { ServerMiddleware } from "@rbxts/tether";
|
|
126
124
|
|
|
127
125
|
export function logServer(): ServerMiddleware {
|
|
128
|
-
return message =>
|
|
126
|
+
return message => ctx => print(`[LOG]: Sent message '${message}' to server with data:`, ctx.data);
|
|
129
127
|
}
|
|
130
128
|
```
|
|
131
129
|
|
|
@@ -152,7 +150,7 @@ import type { ServerMiddleware } from "@rbxts/tether";
|
|
|
152
150
|
|
|
153
151
|
export function incrementNumberData(): ServerMiddleware<number> {
|
|
154
152
|
// sets the data to be used by the any subsequent middlewares as well as sent through the remote
|
|
155
|
-
return () => (data, updateData) => updateData(data + 1);
|
|
153
|
+
return () => ({ data, updateData }) => updateData(data + 1);
|
|
156
154
|
}
|
|
157
155
|
```
|
|
158
156
|
|
|
@@ -166,7 +164,8 @@ messaging.middleware
|
|
|
166
164
|
// only allows requests to the server every 5 seconds,
|
|
167
165
|
// drops any requests that occur within 5 seconds of each other
|
|
168
166
|
.useServer(Message.Test, BuiltinMiddlewares.rateLimit(5))
|
|
169
|
-
|
|
167
|
+
// will be just one byte!
|
|
168
|
+
.useShared(Message.Packed, () => ctx => print("Packed object size:", buffer.len(ctx.getRawData().buffer)));
|
|
170
169
|
// logs every message fired
|
|
171
170
|
.useServerGlobal(logServer())
|
|
172
171
|
.useClientGlobal(logClient())
|
|
@@ -185,14 +184,14 @@ export interface MessageData {
|
|
|
185
184
|
readonly n: DataType.u8;
|
|
186
185
|
};
|
|
187
186
|
[Message.Packed]: DataType.Packed<{
|
|
188
|
-
boolean1: boolean;
|
|
189
|
-
boolean2: boolean;
|
|
190
|
-
boolean3: boolean;
|
|
191
|
-
boolean4: boolean;
|
|
192
|
-
boolean5: boolean;
|
|
193
|
-
boolean6: boolean;
|
|
194
|
-
boolean7: boolean;
|
|
195
|
-
boolean8: boolean;
|
|
187
|
+
readonly boolean1: boolean;
|
|
188
|
+
readonly boolean2: boolean;
|
|
189
|
+
readonly boolean3: boolean;
|
|
190
|
+
readonly boolean4: boolean;
|
|
191
|
+
readonly boolean5: boolean;
|
|
192
|
+
readonly boolean6: boolean;
|
|
193
|
+
readonly boolean7: boolean;
|
|
194
|
+
readonly boolean8: boolean;
|
|
196
195
|
}>;
|
|
197
196
|
}
|
|
198
197
|
```
|
|
@@ -11,6 +11,14 @@ export declare namespace BuiltinMiddlewares {
|
|
|
11
11
|
* @returns A shared middleware that will simulate a ping
|
|
12
12
|
*/
|
|
13
13
|
function simulatePing(pingInMs: number): SharedMiddleware;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a shared middleware that will check if a message packet exceeds the given maximum size in bytes
|
|
16
|
+
*
|
|
17
|
+
* @param maxBytes The maximum size of the packet in bytes
|
|
18
|
+
* @param throwError Whether the middleware should throw an error if the packet exceeds the maximum size, or simply drop the request
|
|
19
|
+
* @returns A shared middleware that will check if a message packet exceeds the given maximum size
|
|
20
|
+
*/
|
|
21
|
+
function maxPacketSize(maxBytes: number, throwError?: boolean): SharedMiddleware;
|
|
14
22
|
/**
|
|
15
23
|
* Creates a shared middleware that will drop any message that occurs within the given interval of the previous message
|
|
16
24
|
*
|
|
@@ -24,6 +24,30 @@ do
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
_container.simulatePing = simulatePing
|
|
27
|
+
--[[
|
|
28
|
+
*
|
|
29
|
+
* Creates a shared middleware that will check if a message packet exceeds the given maximum size in bytes
|
|
30
|
+
*
|
|
31
|
+
* @param maxBytes The maximum size of the packet in bytes
|
|
32
|
+
* @param throwError Whether the middleware should throw an error if the packet exceeds the maximum size, or simply drop the request
|
|
33
|
+
* @returns A shared middleware that will check if a message packet exceeds the given maximum size
|
|
34
|
+
|
|
35
|
+
]]
|
|
36
|
+
local function maxPacketSize(maxBytes, throwError)
|
|
37
|
+
if throwError == nil then
|
|
38
|
+
throwError = true
|
|
39
|
+
end
|
|
40
|
+
return function(message)
|
|
41
|
+
return function(ctx)
|
|
42
|
+
local rawData = ctx.getRawData()
|
|
43
|
+
local totalSize = buffer.len(rawData.buffer) + #rawData.blobs * BLOB_SIZE
|
|
44
|
+
if totalSize > maxBytes then
|
|
45
|
+
return if throwError then error(`[@rbxts/tether]: Message '{message}' exceeded maximum packet size of {maxBytes} bytes`) else DropRequest
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
_container.maxPacketSize = maxPacketSize
|
|
27
51
|
--[[
|
|
28
52
|
*
|
|
29
53
|
* Creates a shared middleware that will drop any message that occurs within the given interval of the previous message
|
|
@@ -87,7 +111,9 @@ do
|
|
|
87
111
|
]]
|
|
88
112
|
local function debug(schema)
|
|
89
113
|
return function(message)
|
|
90
|
-
return function(
|
|
114
|
+
return function(_param)
|
|
115
|
+
local data = _param.data
|
|
116
|
+
local getRawData = _param.getRawData
|
|
91
117
|
local rawData = getRawData()
|
|
92
118
|
local bufferSize = buffer.len(rawData.buffer)
|
|
93
119
|
local blobsSize = #rawData.blobs * BLOB_SIZE
|
package/out/message-emitter.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare class MessageEmitter<MessageData> extends Destroyable {
|
|
|
9
9
|
private readonly serverCallbacks;
|
|
10
10
|
private readonly serverFunctions;
|
|
11
11
|
private readonly guards;
|
|
12
|
-
private serializers;
|
|
12
|
+
private readonly serializers;
|
|
13
13
|
private serverEvents;
|
|
14
14
|
private clientEvents;
|
|
15
15
|
/** @metadata macro */
|
package/out/message-emitter.luau
CHANGED
|
@@ -61,11 +61,16 @@ do
|
|
|
61
61
|
return nil
|
|
62
62
|
end
|
|
63
63
|
task.spawn(function()
|
|
64
|
+
local ctx = {
|
|
65
|
+
data = data,
|
|
66
|
+
updateData = updateData,
|
|
67
|
+
getRawData = getPacket,
|
|
68
|
+
}
|
|
64
69
|
for _, globalMiddleware in self.middleware:getServerGlobal() do
|
|
65
70
|
if not self:validateData(message, data) then
|
|
66
71
|
return nil
|
|
67
72
|
end
|
|
68
|
-
local result = globalMiddleware(message)(
|
|
73
|
+
local result = globalMiddleware(message)(ctx)
|
|
69
74
|
if result == DropRequest then
|
|
70
75
|
return nil
|
|
71
76
|
end
|
|
@@ -74,7 +79,7 @@ do
|
|
|
74
79
|
if not self:validateData(message, data) then
|
|
75
80
|
return nil
|
|
76
81
|
end
|
|
77
|
-
local result = middleware(message)(
|
|
82
|
+
local result = middleware(message)(ctx)
|
|
78
83
|
if result == DropRequest then
|
|
79
84
|
return nil
|
|
80
85
|
end
|
|
@@ -140,11 +145,16 @@ do
|
|
|
140
145
|
return nil
|
|
141
146
|
end
|
|
142
147
|
task.spawn(function()
|
|
148
|
+
local ctx = {
|
|
149
|
+
data = data,
|
|
150
|
+
updateData = updateData,
|
|
151
|
+
getRawData = getPacket,
|
|
152
|
+
}
|
|
143
153
|
for _, globalMiddleware in self.middleware:getClientGlobal() do
|
|
144
154
|
if not self:validateData(message, data) then
|
|
145
155
|
return nil
|
|
146
156
|
end
|
|
147
|
-
local result = globalMiddleware(message)(player,
|
|
157
|
+
local result = globalMiddleware(message)(player, ctx)
|
|
148
158
|
if result == DropRequest then
|
|
149
159
|
return nil
|
|
150
160
|
end
|
|
@@ -153,7 +163,7 @@ do
|
|
|
153
163
|
if not self:validateData(message, data) then
|
|
154
164
|
return nil
|
|
155
165
|
end
|
|
156
|
-
local result = middleware(message)(player,
|
|
166
|
+
local result = middleware(message)(player, ctx)
|
|
157
167
|
if result == DropRequest then
|
|
158
168
|
return nil
|
|
159
169
|
end
|
|
@@ -180,12 +190,17 @@ do
|
|
|
180
190
|
return nil
|
|
181
191
|
end
|
|
182
192
|
task.spawn(function()
|
|
193
|
+
local ctx = {
|
|
194
|
+
data = data,
|
|
195
|
+
updateData = updateData,
|
|
196
|
+
getRawData = getPacket,
|
|
197
|
+
}
|
|
183
198
|
for _, globalMiddleware in self.middleware:getClientGlobal() do
|
|
184
199
|
for _1, player in Players:GetPlayers() do
|
|
185
200
|
if not self:validateData(message, data) then
|
|
186
201
|
return nil
|
|
187
202
|
end
|
|
188
|
-
local result = globalMiddleware(message)(player,
|
|
203
|
+
local result = globalMiddleware(message)(player, ctx)
|
|
189
204
|
if result == DropRequest then
|
|
190
205
|
return nil
|
|
191
206
|
end
|
|
@@ -196,7 +211,7 @@ do
|
|
|
196
211
|
if not self:validateData(message, data) then
|
|
197
212
|
return nil
|
|
198
213
|
end
|
|
199
|
-
local result = middleware(message)(player,
|
|
214
|
+
local result = middleware(message)(player, ctx)
|
|
200
215
|
if result == DropRequest then
|
|
201
216
|
return nil
|
|
202
217
|
end
|
|
@@ -244,7 +259,7 @@ do
|
|
|
244
259
|
self.janitor:Add(function()
|
|
245
260
|
table.clear(self.clientCallbacks)
|
|
246
261
|
table.clear(self.serverCallbacks)
|
|
247
|
-
self.serializers
|
|
262
|
+
table.clear(self.serializers)
|
|
248
263
|
self.serverEvents = nil
|
|
249
264
|
self.clientEvents = nil
|
|
250
265
|
end)
|
package/out/middleware.d.ts
CHANGED
|
@@ -3,16 +3,19 @@ type DropRequestSymbol = symbol & {
|
|
|
3
3
|
_drop_req?: undefined;
|
|
4
4
|
};
|
|
5
5
|
export declare const DropRequest: DropRequestSymbol;
|
|
6
|
-
type UpdateDataFn<T> = (newData: T) => void;
|
|
7
|
-
type GetRawDataFn = () => SerializedPacket;
|
|
8
6
|
export type ClientMiddleware<Data = unknown> = {
|
|
9
7
|
_client?: void;
|
|
10
|
-
} & ((message: BaseMessage) => (player: Player | Player[],
|
|
11
|
-
export type ServerMiddleware<Data = unknown> =
|
|
8
|
+
} & ((message: BaseMessage) => (player: Player | Player[], ctx: MiddlewareContext<Data>) => DropRequestSymbol | void);
|
|
9
|
+
export type ServerMiddleware<Data = unknown> = {
|
|
12
10
|
_server?: void;
|
|
13
|
-
}
|
|
14
|
-
export type SharedMiddleware<Data = unknown> = (message: BaseMessage) => (
|
|
11
|
+
} & SharedMiddleware<Data>;
|
|
12
|
+
export type SharedMiddleware<Data = unknown> = (message: BaseMessage) => (ctx: MiddlewareContext<Data>) => DropRequestSymbol | void;
|
|
15
13
|
export type Middleware<Data = unknown> = ServerMiddleware<Data> & ClientMiddleware<Data> & SharedMiddleware<Data>;
|
|
14
|
+
export interface MiddlewareContext<Data = unknown> {
|
|
15
|
+
readonly data: Readonly<Data>;
|
|
16
|
+
updateData: (newData: Data) => void;
|
|
17
|
+
getRawData: () => SerializedPacket;
|
|
18
|
+
}
|
|
16
19
|
export declare class MiddlewareProvider<MessageData> {
|
|
17
20
|
private readonly clientGlobalMiddlewares;
|
|
18
21
|
private readonly serverGlobalMiddlewares;
|
package/out/middleware.luau
CHANGED
|
@@ -78,8 +78,8 @@ do
|
|
|
78
78
|
local _newValue = table.create(#_exp)
|
|
79
79
|
local _callback = function(middleware)
|
|
80
80
|
return function(message)
|
|
81
|
-
return function(_,
|
|
82
|
-
return middleware(message)(
|
|
81
|
+
return function(_, ctx)
|
|
82
|
+
return middleware(message)(ctx)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
end
|
|
@@ -133,8 +133,8 @@ do
|
|
|
133
133
|
local _newValue = table.create(#_exp)
|
|
134
134
|
local _callback = function(middleware)
|
|
135
135
|
return function(message)
|
|
136
|
-
return function(_,
|
|
137
|
-
return middleware(message)(
|
|
136
|
+
return function(_, ctx)
|
|
137
|
+
return middleware(message)(ctx)
|
|
138
138
|
end
|
|
139
139
|
end
|
|
140
140
|
end
|