@quenty/userserviceutils 4.0.0-canary.367.e9fdcbc.0 → 4.0.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 CHANGED
@@ -3,7 +3,64 @@
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
- # [4.0.0-canary.367.e9fdcbc.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.5.0...@quenty/userserviceutils@4.0.0-canary.367.e9fdcbc.0) (2023-06-05)
6
+ # [4.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.11.0...@quenty/userserviceutils@4.0.0) (2023-10-11)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * User information de-duplication occurs ([bcb5c2a](https://github.com/Quenty/NevermoreEngine/commit/bcb5c2a062fa775e6c0949f2f56f7026456f849a))
12
+
13
+
14
+
15
+
16
+
17
+ # [3.11.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.10.0...@quenty/userserviceutils@3.11.0) (2023-09-21)
18
+
19
+ **Note:** Version bump only for package @quenty/userserviceutils
20
+
21
+
22
+
23
+
24
+
25
+ # [3.10.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.9.0...@quenty/userserviceutils@3.10.0) (2023-08-23)
26
+
27
+
28
+ ### Features
29
+
30
+ * Add UserInfoService:ObserveDisplayName(userId) ([950c121](https://github.com/Quenty/NevermoreEngine/commit/950c121c35d734d7a66415ada647b146e06c4bf7))
31
+
32
+
33
+
34
+
35
+
36
+ # [3.9.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.8.0...@quenty/userserviceutils@3.9.0) (2023-07-28)
37
+
38
+ **Note:** Version bump only for package @quenty/userserviceutils
39
+
40
+
41
+
42
+
43
+
44
+ # [3.8.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.7.0...@quenty/userserviceutils@3.8.0) (2023-07-25)
45
+
46
+
47
+ ### Features
48
+
49
+ * Add UserInfoService to aggregate user info in a de-duplicated request format ([deb1a79](https://github.com/Quenty/NevermoreEngine/commit/deb1a7914f753f8835ce407a2f94b3f8eac7d812))
50
+
51
+
52
+
53
+
54
+
55
+ # [3.7.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.6.0...@quenty/userserviceutils@3.7.0) (2023-06-17)
56
+
57
+ **Note:** Version bump only for package @quenty/userserviceutils
58
+
59
+
60
+
61
+
62
+
63
+ # [3.6.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/userserviceutils@3.5.0...@quenty/userserviceutils@3.6.0) (2023-06-05)
7
64
 
8
65
  **Note:** Version bump only for package @quenty/userserviceutils
9
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/userserviceutils",
3
- "version": "4.0.0-canary.367.e9fdcbc.0",
3
+ "version": "4.0.0",
4
4
  "description": "Utilities involving UserService in Roblox",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -25,12 +25,16 @@
25
25
  "Quenty"
26
26
  ],
27
27
  "dependencies": {
28
- "@quenty/loader": "6.2.1",
29
- "@quenty/math": "3.0.0-canary.367.e9fdcbc.0",
30
- "@quenty/promise": "6.5.0"
28
+ "@quenty/baseobject": "^7.0.0",
29
+ "@quenty/loader": "^7.0.0",
30
+ "@quenty/maid": "^2.6.0",
31
+ "@quenty/math": "^2.5.0",
32
+ "@quenty/promise": "^7.0.0",
33
+ "@quenty/rx": "^8.0.0",
34
+ "@quenty/servicebag": "^7.0.0"
31
35
  },
32
36
  "publishConfig": {
33
37
  "access": "public"
34
38
  },
35
- "gitHead": "e9fdcbc6ea1d46e068bf42a08b833099e9005259"
39
+ "gitHead": "fdeae46099587019ec5fc15317dc673aed379400"
36
40
  }
@@ -0,0 +1,77 @@
1
+ --[=[
2
+ Centralized provider for user info so we can coordinate web requests.
3
+
4
+ @class UserInfoServiceClient
5
+ ]=]
6
+
7
+ local require = require(script.Parent.loader).load(script)
8
+
9
+ local UserInfoAggregator = require("UserInfoAggregator")
10
+ local Maid = require("Maid")
11
+
12
+ local UserInfoServiceClient = {}
13
+ UserInfoServiceClient.ServiceName = "UserInfoServiceClient"
14
+
15
+ function UserInfoServiceClient:Init(serviceBag)
16
+ assert(not self._serviceBag, "Already initialized")
17
+ self._serviceBag = assert(serviceBag, "No serviceBag")
18
+ self._maid = Maid.new()
19
+
20
+ self._aggregator = UserInfoAggregator.new()
21
+ self._maid:GiveTask(self._aggregator)
22
+ end
23
+
24
+ --[=[
25
+ Promises the user info for the given user, aggregating all requests to reduce
26
+ calls into Roblox.
27
+
28
+ @param userId number
29
+ @return Promise<UserInfo>
30
+ ]=]
31
+ function UserInfoServiceClient:PromiseUserInfo(userId)
32
+ assert(type(userId) == "number", "Bad userId")
33
+
34
+ return self._aggregator:PromiseUserInfo(userId)
35
+ end
36
+
37
+ --[=[
38
+ Promises the user display name for the userId
39
+
40
+ @param userId number
41
+ @return Promise<string>
42
+ ]=]
43
+ function UserInfoServiceClient:PromiseDisplayName(userId)
44
+ assert(type(userId) == "number", "Bad userId")
45
+
46
+ return self._aggregator:PromiseDisplayName(userId)
47
+ end
48
+
49
+ --[=[
50
+ Observes the user info for the user
51
+
52
+ @param userId number
53
+ @return Observable<UserInfo>
54
+ ]=]
55
+ function UserInfoServiceClient:ObserveUserInfo(userId)
56
+ assert(type(userId) == "number", "Bad userId")
57
+
58
+ return self._aggregator:ObserveDisplayName(userId)
59
+ end
60
+
61
+ --[=[
62
+ Observes the user display name for the userId
63
+
64
+ @param userId number
65
+ @return Observable<string>
66
+ ]=]
67
+ function UserInfoServiceClient:ObserveDisplayName(userId)
68
+ assert(type(userId) == "number", "Bad userId")
69
+
70
+ return self._aggregator:ObserveDisplayName(userId)
71
+ end
72
+
73
+ function UserInfoServiceClient:Destroy()
74
+ self._maid:DoCleaning()
75
+ end
76
+
77
+ return UserInfoServiceClient
@@ -0,0 +1,78 @@
1
+ --[=[
2
+ Centralized provider for user info so we can coordinate web requests.
3
+
4
+ @class UserInfoService
5
+ ]=]
6
+
7
+ local require = require(script.Parent.loader).load(script)
8
+
9
+ local UserInfoAggregator = require("UserInfoAggregator")
10
+ local Maid = require("Maid")
11
+
12
+ local UserInfoService = {}
13
+ UserInfoService.ServiceName = "UserInfoService"
14
+
15
+ function UserInfoService:Init(serviceBag)
16
+ assert(not self._serviceBag, "Already initialized")
17
+ self._serviceBag = assert(serviceBag, "No serviceBag")
18
+ self._maid = Maid.new()
19
+
20
+ self._aggregator = UserInfoAggregator.new()
21
+ self._maid:GiveTask(self._aggregator)
22
+ end
23
+
24
+ --[=[
25
+ Promises the user info for the given user, aggregating all requests to reduce
26
+ calls into Roblox.
27
+
28
+ @param userId number
29
+ @return Promise<UserInfo>
30
+ ]=]
31
+ function UserInfoService:PromiseUserInfo(userId)
32
+ assert(type(userId) == "number", "Bad userId")
33
+
34
+ return self._aggregator:PromiseUserInfo(userId)
35
+ end
36
+
37
+ --[=[
38
+ Observes the user info for the user
39
+
40
+ @param userId number
41
+ @return Observable<UserInfo>
42
+ ]=]
43
+ function UserInfoService:ObserveUserInfo(userId)
44
+ assert(type(userId) == "number", "Bad userId")
45
+
46
+ return self._aggregator:ObserveDisplayName(userId)
47
+ end
48
+
49
+ --[=[
50
+ Promises the user display name for the userId
51
+
52
+ @param userId number
53
+ @return Promise<string>
54
+ ]=]
55
+ function UserInfoService:PromiseDisplayName(userId)
56
+ assert(type(userId) == "number", "Bad userId")
57
+
58
+ return self._aggregator:PromiseDisplayName(userId)
59
+ end
60
+
61
+ --[=[
62
+ Observes the user display name for the userId
63
+
64
+ @param userId number
65
+ @return Observable<string>
66
+ ]=]
67
+ function UserInfoService:ObserveDisplayName(userId)
68
+ assert(type(userId) == "number", "Bad userId")
69
+
70
+ return self._aggregator:ObserveDisplayName(userId)
71
+ end
72
+
73
+
74
+ function UserInfoService:Destroy()
75
+ self._maid:DoCleaning()
76
+ end
77
+
78
+ return UserInfoService
@@ -0,0 +1,197 @@
1
+ --[=[
2
+ Aggregates all requests into one big send request to deduplicate the request
3
+
4
+ @class UserInfoAggregator
5
+ ]=]
6
+
7
+ local require = require(script.Parent.loader).load(script)
8
+
9
+ local BaseObject = require("BaseObject")
10
+ local Promise = require("Promise")
11
+ local UserServiceUtils = require("UserServiceUtils")
12
+ local Rx = require("Rx")
13
+
14
+ local MAX_USER_IDS_PER_REQUEST = 200
15
+
16
+ local UserInfoAggregator = setmetatable({}, BaseObject)
17
+ UserInfoAggregator.ClassName = "UserInfoAggregator"
18
+ UserInfoAggregator.__index = UserInfoAggregator
19
+
20
+ function UserInfoAggregator.new()
21
+ local self = setmetatable(BaseObject.new(), UserInfoAggregator)
22
+
23
+ -- TODO: LRU cache this? Limit to 1k or something?
24
+ self._promises = {}
25
+
26
+ self._unsentCount = 0
27
+ self._unsentPromises = {}
28
+
29
+ return self
30
+ end
31
+
32
+ --[=[
33
+ Promises the user info for the given user, aggregating all requests to reduce
34
+ calls into Roblox.
35
+
36
+ @param userId number
37
+ @return Promise<UserInfo>
38
+ ]=]
39
+ function UserInfoAggregator:PromiseUserInfo(userId)
40
+ assert(type(userId) == "number", "Bad userId")
41
+
42
+ if self._promises[userId] then
43
+ return self._promises[userId]
44
+ end
45
+
46
+ local promise = Promise.new()
47
+
48
+ self._unsentPromises[userId] = promise
49
+ self._unsentCount = self._unsentCount + 1
50
+ self._promises[userId] = promise
51
+
52
+ self:_queueAggregatedPromises()
53
+
54
+ return promise
55
+ end
56
+
57
+ --[=[
58
+ Promises the user display name for the userId
59
+
60
+ @param userId number
61
+ @return Promise<string>
62
+ ]=]
63
+ function UserInfoAggregator:PromiseDisplayName(userId)
64
+ assert(type(userId) == "number", "Bad userId")
65
+
66
+ return self:PromiseUserInfo(userId)
67
+ :Then(function(userInfo)
68
+ return userInfo.DisplayName
69
+ end)
70
+ end
71
+
72
+ --[=[
73
+ Promises the user display name for the userId
74
+
75
+ @param userId number
76
+ @return Promise<string>
77
+ ]=]
78
+ function UserInfoAggregator:PromiseDisplayName(userId)
79
+ assert(type(userId) == "number", "Bad userId")
80
+
81
+ return self:PromiseUserInfo(userId)
82
+ :Then(function(userInfo)
83
+ return userInfo.DisplayName
84
+ end)
85
+ end
86
+
87
+ --[=[
88
+ Promises the user display name for the userId
89
+
90
+ @param userId number
91
+ @return Promise<boolean>
92
+ ]=]
93
+ function UserInfoAggregator:PromiseHasVerifiedBadge(userId)
94
+ assert(type(userId) == "number", "Bad userId")
95
+
96
+ return self:PromiseUserInfo(userId)
97
+ :Then(function(userInfo)
98
+ return userInfo.HasVerifiedBadge
99
+ end)
100
+ end
101
+
102
+ --[=[
103
+ Observes the user display name for the userId
104
+
105
+ @param userId number
106
+ @return Observable<UserInfo>
107
+ ]=]
108
+ function UserInfoAggregator:ObserveUserInfo(userId)
109
+ assert(type(userId) == "number", "Bad userId")
110
+
111
+ return Rx.fromPromise(self:PromiseUserInfo(userId))
112
+ end
113
+
114
+ --[=[
115
+ Observes the user display name for the userId
116
+
117
+ @param userId number
118
+ @return Observable<string>
119
+ ]=]
120
+ function UserInfoAggregator:ObserveDisplayName(userId)
121
+ assert(type(userId) == "number", "Bad userId")
122
+
123
+ return self:ObserveUserInfo():Pipe({
124
+ Rx.map(function(userInfo)
125
+ return userInfo.DisplayName
126
+ end)
127
+ })
128
+ end
129
+
130
+ function UserInfoAggregator:_sendAggregatedPromises(promiseMap)
131
+ assert(promiseMap, "No promiseMap")
132
+
133
+ local userIds = {}
134
+ local unresolvedMap = {}
135
+ for userId, promise in pairs(promiseMap) do
136
+ table.insert(userIds, userId)
137
+ unresolvedMap[userId] = promise
138
+ end
139
+
140
+ if #userIds == 0 then
141
+ return
142
+ end
143
+
144
+ assert(#userIds <= MAX_USER_IDS_PER_REQUEST, "Too many userIds sent")
145
+
146
+ self._maid:GivePromise(UserServiceUtils.promiseUserInfosByUserIds(userIds))
147
+ :Then(function(result)
148
+ assert(type(result) == "table", "Bad result")
149
+
150
+ for _, data in pairs(result) do
151
+ assert(type(data.Id) == "number", "Bad result[?].Id")
152
+
153
+ if unresolvedMap[data.Id] then
154
+ unresolvedMap[data.Id]:Resolve(data)
155
+ unresolvedMap[data.Id] = nil
156
+ end
157
+ end
158
+
159
+ -- Reject other ones
160
+ for userId, promise in pairs(unresolvedMap) do
161
+ promise:Reject(string.format("Failed to get result for userId %d", userId))
162
+ end
163
+ end, function(...)
164
+ for _, item in pairs(unresolvedMap) do
165
+ item:Reject(...)
166
+ end
167
+ end)
168
+ end
169
+
170
+ function UserInfoAggregator:_resetQueue()
171
+ local promiseMap = self._unsentPromises
172
+
173
+ self._maid._queue = nil
174
+ self._unsentCount = 0
175
+ self._unsentPromises = {}
176
+
177
+ return promiseMap
178
+ end
179
+
180
+ function UserInfoAggregator:_queueAggregatedPromises()
181
+ if self._unsentCount >= MAX_USER_IDS_PER_REQUEST then
182
+ self:_sendAggregatedPromises(self:_resetQueue())
183
+ return
184
+ end
185
+
186
+ if self._maid._queue then
187
+ return
188
+ end
189
+
190
+ self._maid._queue = task.delay(0.1, function()
191
+ task.spawn(function()
192
+ self:_sendAggregatedPromises(self:_resetQueue())
193
+ end)
194
+ end)
195
+ end
196
+
197
+ return UserInfoAggregator
@@ -1,4 +1,6 @@
1
1
  --[=[
2
+ Wraps [UserService] API calls with [Promise].
3
+
2
4
  @class UserServiceUtils
3
5
  ]=]
4
6
 
@@ -15,11 +17,17 @@ local UserServiceUtils = {}
15
17
  .Id number -- The Id associated with the UserInfoResponse object
16
18
  .Username string -- The username associated with the UserInfoResponse object
17
19
  .DisplayName string -- The display name associated with the UserInfoResponse object
20
+ .HasVerifiedBadge boolean -- The HasVerifiedBadge value associated with the user.
18
21
  @within UserServiceUtils
19
22
  ]=]
20
23
 
21
24
  --[=[
22
25
  Wraps UserService:GetUserInfosByUserIdsAsync(userIds)
26
+
27
+ ::: tip
28
+ User [UserInfoAggregator] via [UserInfoService] to get this deduplicated.
29
+ :::
30
+
23
31
  @param userIds { number }
24
32
  @return Promise<{ UserInfo }>
25
33
  ]=]
@@ -46,6 +54,10 @@ end
46
54
  --[=[
47
55
  Wraps UserService:GetUserInfosByUserIdsAsync({ userId })[1]
48
56
 
57
+ ::: tip
58
+ User [UserInfoAggregator] via [UserInfoService] to get this deduplicated.
59
+ :::
60
+
49
61
  @param userId number
50
62
  @return Promise<UserInfo>
51
63
  ]=]
@@ -67,6 +79,10 @@ end
67
79
  --[=[
68
80
  Wraps UserService:GetUserInfosByUserIdsAsync({ userId })[1].DisplayName
69
81
 
82
+ ::: tip
83
+ User [UserInfoAggregator] via [UserInfoService] to get this deduplicated.
84
+ :::
85
+
70
86
  @param userId number
71
87
  @return Promise<string>
72
88
  ]=]
@@ -82,6 +98,10 @@ end
82
98
  --[=[
83
99
  Wraps UserService:GetUserInfosByUserIdsAsync({ userId })[1].Username
84
100
 
101
+ ::: tip
102
+ User [UserInfoAggregator] via [UserInfoService] to get this deduplicated.
103
+ :::
104
+
85
105
  @param userId number
86
106
  @return Promise<string>
87
107
  ]=]