@quenty/messagingserviceutils 7.13.0-canary.636.52f1a4b.0 → 7.13.1-canary.640.0d6f2d5.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 +12 -1
- package/package.json +7 -3
- package/src/Server/PlaceMessagingService.lua +252 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
## [7.13.1-canary.640.0d6f2d5.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/messagingserviceutils@7.13.0...@quenty/messagingserviceutils@7.13.1-canary.640.0d6f2d5.0) (2026-01-14)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* DataStores now use one message per a place instead of many, which cuts down on subscription costs ([0d6f2d5](https://github.com/Quenty/NevermoreEngine/commit/0d6f2d55fd55226daa5a6c7047288d48946ef8a8))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [7.13.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/messagingserviceutils@7.12.6...@quenty/messagingserviceutils@7.13.0) (2026-01-13)
|
|
7
18
|
|
|
8
19
|
|
|
9
20
|
### Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/messagingserviceutils",
|
|
3
|
-
"version": "7.13.
|
|
3
|
+
"version": "7.13.1-canary.640.0d6f2d5.0",
|
|
4
4
|
"description": "Utility functions for messaging srevice",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -30,7 +30,11 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@quenty/loader": "10.9.3",
|
|
33
|
-
"@quenty/
|
|
33
|
+
"@quenty/maid": "3.5.3",
|
|
34
|
+
"@quenty/promise": "10.13.0",
|
|
35
|
+
"@quenty/rx": "13.22.0",
|
|
36
|
+
"@quenty/servicebag": "11.13.6",
|
|
37
|
+
"@quenty/statestack": "14.25.0"
|
|
34
38
|
},
|
|
35
39
|
"devDependencies": {
|
|
36
40
|
"@quenty/loader": "workspace:*"
|
|
@@ -38,5 +42,5 @@
|
|
|
38
42
|
"publishConfig": {
|
|
39
43
|
"access": "public"
|
|
40
44
|
},
|
|
41
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "0d6f2d55fd55226daa5a6c7047288d48946ef8a8"
|
|
42
46
|
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
Provides a centralized messaging service for the current place, to other places.
|
|
4
|
+
@class PlaceMessagingService
|
|
5
|
+
]=]
|
|
6
|
+
|
|
7
|
+
local require = require(script.Parent.loader).load(script)
|
|
8
|
+
|
|
9
|
+
local RunService = game:GetService("RunService")
|
|
10
|
+
|
|
11
|
+
local Maid = require("Maid")
|
|
12
|
+
local MessagingServiceUtils = require("MessagingServiceUtils")
|
|
13
|
+
local Observable = require("Observable")
|
|
14
|
+
local ObservableSubscriptionTable = require("ObservableSubscriptionTable")
|
|
15
|
+
local Promise = require("Promise")
|
|
16
|
+
local ServiceBag = require("ServiceBag")
|
|
17
|
+
local StateStack = require("StateStack")
|
|
18
|
+
|
|
19
|
+
local LOG_DEBUG = false
|
|
20
|
+
|
|
21
|
+
local PlaceMessagingService = {}
|
|
22
|
+
PlaceMessagingService.ServiceName = "PlaceMessagingService"
|
|
23
|
+
|
|
24
|
+
export type PlaceMessagingService = typeof(setmetatable(
|
|
25
|
+
{} :: {
|
|
26
|
+
_serviceBag: ServiceBag.ServiceBag,
|
|
27
|
+
_subscriptionTable: ObservableSubscriptionTable.ObservableSubscriptionTable<(any, PlacePacketMetadata)>,
|
|
28
|
+
_connectionRequire: StateStack.StateStack<boolean>,
|
|
29
|
+
_maid: Maid.Maid,
|
|
30
|
+
},
|
|
31
|
+
{} :: typeof({ __index = PlaceMessagingService })
|
|
32
|
+
))
|
|
33
|
+
|
|
34
|
+
export type PlaceAddress = {
|
|
35
|
+
jobId: string,
|
|
36
|
+
placeId: number,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type PlaceMessagingPacket = {
|
|
40
|
+
topic: string,
|
|
41
|
+
from: PlaceAddress,
|
|
42
|
+
message: any,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type PlacePacketMetadata = {
|
|
46
|
+
sent: number, -- Same as the MessagingService timestamp
|
|
47
|
+
topic: string,
|
|
48
|
+
from: PlaceAddress,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function PlaceMessagingService.Init(self: PlaceMessagingService, serviceBag: ServiceBag.ServiceBag): ()
|
|
52
|
+
assert(not (self :: any)._serviceBag, "Already initialized")
|
|
53
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
54
|
+
self._maid = Maid.new()
|
|
55
|
+
|
|
56
|
+
self._connectionRequire = self._maid:Add(StateStack.new(false, "boolean"))
|
|
57
|
+
self._subscriptionTable = self._maid:Add(ObservableSubscriptionTable.new() :: any)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
function PlaceMessagingService.Start(self: PlaceMessagingService): ()
|
|
61
|
+
-- Subscribe as needed
|
|
62
|
+
self._maid:GiveTask(self._connectionRequire
|
|
63
|
+
:ObserveBrio(function(required)
|
|
64
|
+
return required
|
|
65
|
+
end)
|
|
66
|
+
:Subscribe(function(brio)
|
|
67
|
+
if brio:IsDead() then
|
|
68
|
+
return
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
local maid = brio:ToMaid()
|
|
72
|
+
local address = self:GetPlaceAddress()
|
|
73
|
+
local topic = self:PlaceAddressToTopicString(address)
|
|
74
|
+
|
|
75
|
+
if LOG_DEBUG then
|
|
76
|
+
print(`[PlaceMessagingService] - Subscribing to global topic {topic}`)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
maid:GiveTask(
|
|
80
|
+
MessagingServiceUtils.promiseSubscribe(topic, function(data: MessagingServiceUtils.SubscriptionData)
|
|
81
|
+
self:_handleIncomingPacket(data)
|
|
82
|
+
end):Then(function(connection: RBXScriptConnection)
|
|
83
|
+
maid:GiveTask(connection)
|
|
84
|
+
end)
|
|
85
|
+
)
|
|
86
|
+
end))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
function PlaceMessagingService._handleIncomingPacket(
|
|
90
|
+
self: PlaceMessagingService,
|
|
91
|
+
data: MessagingServiceUtils.SubscriptionData
|
|
92
|
+
): ()
|
|
93
|
+
local packet: PlaceMessagingPacket = data.Data :: any
|
|
94
|
+
|
|
95
|
+
if LOG_DEBUG then
|
|
96
|
+
print(`[PlaceMessagingService] - Receipted {MessagingServiceUtils.toHumanReadable(packet)}`)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if type(packet) ~= "table" then
|
|
100
|
+
warn("[PlaceMessagingService] - Received invalid packet on place messaging service")
|
|
101
|
+
return
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
local topic = packet.topic
|
|
105
|
+
if type(topic) ~= "string" then
|
|
106
|
+
warn("[PlaceMessagingService] - Received invalid topic on place messaging service")
|
|
107
|
+
return
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
local message = packet.message
|
|
111
|
+
if message == nil then
|
|
112
|
+
warn("[PlaceMessagingService] - Received nil message on place messaging service")
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
local metadata: PlacePacketMetadata = {
|
|
117
|
+
sent = data.Sent,
|
|
118
|
+
topic = topic,
|
|
119
|
+
from = packet.from,
|
|
120
|
+
}
|
|
121
|
+
self._subscriptionTable:Fire(packet.topic, packet.message, metadata)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
--[=[
|
|
125
|
+
Observes messages for the current place on the given topic
|
|
126
|
+
|
|
127
|
+
The returned value should be the same as the message published.
|
|
128
|
+
|
|
129
|
+
:::tip
|
|
130
|
+
This observable will only be active while there is at least one active
|
|
131
|
+
subscription to it. This is to help limit unnecessary load on MessagingService.
|
|
132
|
+
:::
|
|
133
|
+
|
|
134
|
+
@param topic string
|
|
135
|
+
@return Observable<unknown>
|
|
136
|
+
]=]
|
|
137
|
+
function PlaceMessagingService.ObserveMessages(
|
|
138
|
+
self: PlaceMessagingService,
|
|
139
|
+
topic: string
|
|
140
|
+
): Observable.Observable<any, PlacePacketMetadata>
|
|
141
|
+
local observable = self._subscriptionTable:Observe(topic)
|
|
142
|
+
return Observable.new(function(sub)
|
|
143
|
+
local inner = observable:Subscribe(sub:GetFireFailComplete())
|
|
144
|
+
local removePush = self._connectionRequire:PushState(true)
|
|
145
|
+
|
|
146
|
+
if LOG_DEBUG then
|
|
147
|
+
print(`[PlaceMessagingService] - Subscribing to internal {topic}`)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
return function()
|
|
151
|
+
removePush()
|
|
152
|
+
inner:Destroy()
|
|
153
|
+
end
|
|
154
|
+
end) :: any
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
--[=[
|
|
158
|
+
Sends a message to the given place and job
|
|
159
|
+
|
|
160
|
+
@param placeId number
|
|
161
|
+
@param jobId string
|
|
162
|
+
@param topic string
|
|
163
|
+
@param message any
|
|
164
|
+
@return Promise<()>
|
|
165
|
+
]=]
|
|
166
|
+
function PlaceMessagingService.SendMessage(
|
|
167
|
+
self: PlaceMessagingService,
|
|
168
|
+
placeId: number,
|
|
169
|
+
jobId: string,
|
|
170
|
+
topic: string,
|
|
171
|
+
message: any
|
|
172
|
+
): Promise.Promise<()>
|
|
173
|
+
local address = self:PlaceAndJobToServerAddress(placeId, jobId)
|
|
174
|
+
return self:SendMessageToAddress(address, topic, message)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
--[=[
|
|
178
|
+
Sends a message to the given place address
|
|
179
|
+
|
|
180
|
+
@param address PlaceAddress
|
|
181
|
+
@param topic string
|
|
182
|
+
@param message any
|
|
183
|
+
@return Promise<()>
|
|
184
|
+
]=]
|
|
185
|
+
function PlaceMessagingService.SendMessageToAddress(
|
|
186
|
+
self: PlaceMessagingService,
|
|
187
|
+
address: PlaceAddress,
|
|
188
|
+
topic: string,
|
|
189
|
+
message: any
|
|
190
|
+
): Promise.Promise<()>
|
|
191
|
+
local packet: PlaceMessagingPacket = {
|
|
192
|
+
topic = topic,
|
|
193
|
+
from = self:GetPlaceAddress(),
|
|
194
|
+
message = message,
|
|
195
|
+
}
|
|
196
|
+
local addressString = self:PlaceAddressToTopicString(address)
|
|
197
|
+
|
|
198
|
+
if LOG_DEBUG then
|
|
199
|
+
print(`[PlaceMessagingService] - To {addressString} sending {MessagingServiceUtils.toHumanReadable(packet)}`)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
return self._maid:GivePromise(MessagingServiceUtils.promisePublish(addressString, packet))
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
--[=[
|
|
206
|
+
Gets the current place address
|
|
207
|
+
|
|
208
|
+
@return PlaceAddress
|
|
209
|
+
]=]
|
|
210
|
+
function PlaceMessagingService.GetPlaceAddress(self: PlaceMessagingService): PlaceAddress
|
|
211
|
+
local jobId = game.JobId
|
|
212
|
+
if jobId == "" and RunService:IsStudio() then
|
|
213
|
+
jobId = "studio"
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
return self:PlaceAndJobToServerAddress(game.PlaceId, jobId)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
--[=[
|
|
220
|
+
Converts a place address to a topic string
|
|
221
|
+
|
|
222
|
+
@param address PlaceAddress
|
|
223
|
+
@return string
|
|
224
|
+
]=]
|
|
225
|
+
function PlaceMessagingService.PlaceAddressToTopicString(_self: PlaceMessagingService, address: PlaceAddress): string
|
|
226
|
+
return `PlaceMessagingService_{address.placeId}_{address.jobId}`
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
--[=[
|
|
230
|
+
Converts a placeId and jobId to a place address
|
|
231
|
+
|
|
232
|
+
@param placeId number
|
|
233
|
+
@param jobId string
|
|
234
|
+
@return PlaceAddress
|
|
235
|
+
]=]
|
|
236
|
+
function PlaceMessagingService.PlaceAndJobToServerAddress(
|
|
237
|
+
_self: PlaceMessagingService,
|
|
238
|
+
placeId: number,
|
|
239
|
+
jobId: string
|
|
240
|
+
): PlaceAddress
|
|
241
|
+
return {
|
|
242
|
+
placeId = placeId,
|
|
243
|
+
jobId = jobId,
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
function PlaceMessagingService.Destroy(self: PlaceMessagingService)
|
|
248
|
+
self._maid:DoCleaning()
|
|
249
|
+
self._maid = nil :: any
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
return PlaceMessagingService
|