-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdataController.js
188 lines (174 loc) · 6.98 KB
/
dataController.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
123
124
125
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
180
181
182
183
184
185
186
187
188
import consola from 'consola'
import { pack } from 'msgpackr'
import { Op } from 'sequelize'
import { io } from '../listeners/socketServer'
import models from '../models/indexModel'
import { lastSeen, lastSaved } from '../helpers/users'
import { games } from '../../assets/js/games'
import metrics from '../helpers/metrics'
import { users, idFromIp } from './userController.js'
// only data mode implemented for now will be mapping, so only xyz and maybe rumble/surface for each point?
// we check what mode user is in
// set throttle based on mode and only save data we need, maybe send full telemetry to frontend
/**
* TODO: Cache each map and maybe, only sync db and cache to stop async calls in main function
* category=nuxt
*/
export const throttledWrite = async (msg, rinfo, gameId) => {
// Checksconsole.log(1);
const userId = idFromIp(rinfo.address)
if (users[userId] === undefined || users[userId].udp === undefined) { return }
if (users[userId].udp.throttleTime === undefined) {
users[userId].udp.throttleTime = 1000 / 2
}
// throttle
if (Date.now() - users[userId].udp.lastSeen >= users[userId].udp.throttleTime) { // sending 12 cuz stop motion idk native is about 160
lastSeen(users[userId])
// throttle user differently if on frontend or not, actually genius ifelse
if (('socket' in users[userId])) {
users[userId].udp.throttleTime = 1000 / 12.69
} else {
users[userId].udp.throttleTime = 1000 / 2
}
} else {
return
}
// parse
const parsed = games[gameId].parsers.xyz.parse(Buffer.from(msg, 'hex'))
// const parseFull = games[gameId].parsers.full.parse(Buffer.from(msg, 'hex'))
if (parsed.PositionX === 0 || parsed.PositionY === 0 || parsed.PositionZ === 0) { return }
// See if user is known or not if not just send back chord
if (('socket' in users[userId]) && users[userId].udp.known === false) {
// what are we sending back? default xyz data for game?
// parse only xyz and surface here
// io.to('gameName').emit('chord', msg) // maybe dont send raw tel of everyone to global map
io.to(users[userId].socket.id).emit('chord', msg)
metrics.ioOut.mark()
}
// User is known look what we need to save and send
// Throttle this again to not save as much as we send?
if (users[userId].udp.known !== false) {
// look at mode even tho user can only have x atm, tells us what to do with data
if (users[userId].udp.known.mode === 0) {
if (Date.now() - users[userId].lastSaved >= 1000 / 2 || users[userId].lastSaved === undefined) { // sending 12 cuz stop motion idk native is about 160
metrics.data2db.mark()
// parse only xyz and surface here
await models.position.create({
x: parsed.PositionX,
y: parsed.PositionY,
z: parsed.PositionZ,
inPuddleSum: parsed.WheelInPuddle.reduce((partialSum, a) => partialSum + a, 0).toFixed(2),
surfaceRumbleSum: parsed.SurfaceRumble.reduce((partialSum, a) => partialSum + a, 0).toFixed(2),
normSuspensionTravelSum: parsed.NormSuspensionTravel.reduce((partialSum, a) => partialSum + a, 0).toFixed(2),
gameId,
userId: users[userId].udp.known.userId
}).catch(function (err) {
consola.error(err)
})
if (users[userId].udp.known.visibility === 1) { return }
io.to(id2GameSlug(gameId)).emit('globalChord', parsed)
lastSaved(users[userId])
}
if ('socket' in users[userId]) {
io.to(users[userId].socket.id).emit('chord', msg)
}
// Visibility check
// console.log('visibility; ' + users[userId].udp.known.visibility)
}
}
}
export const sendInitData = async (socket, route) => {
// route has route infos
// { 21:08:23
// slug: 'fh5',
// name: 'm-slug'
// }
let gameId
if (route.name === 'index' && socket.decoded.id !== undefined) {
await models.position.findAll({
where: {
userId: socket.decoded.id
},
raw: true,
attributes: ['x', 'y', 'z']
}).then(function (alluserPos) {
const serializedAsBuffer = pack({ alluserPos })
io.to(socket.id).emit('chordPack', serializedAsBuffer)
}).catch(function (err) {
io.to(socket.id).emit('error', { code: 404, msg: 'Page not found' })
consola.error(err)
})
// u-slug
} else if (route.name === 'u-slug') {
const isUUID = await validUUID(route.slug)
if (!isUUID) {
io.to(socket.id).emit('error', { code: 404, msg: 'Page not found' })
return
}
const uid = route.slug
await models.position.findAll({
where: {
userId: uid
},
raw: true,
attributes: ['x', 'y', 'z']
}).then(function (alluserPos) {
const serializedAsBuffer = pack({ alluserPos })
io.to(socket.id).emit('chordPack', serializedAsBuffer)
}).catch(function (err) {
io.to(socket.id).emit('error', { code: 404, msg: 'Page not found' })
consola.error(err)
})
// m-slug
} else if (route.name === 'm-slug') {
gameId = gameSlug2Id(route.slug)
if (gameId === false || gameId === undefined) {
io.to(socket.id).emit('error', { code: 404, msg: 'Page not found' })
return
}
// TODO: Get this data over its client so we can first only take clients with visibility 0 and then we can do checks on all of these
await models.position.findAll({
where: {
gameId,
normSuspensionTravelSum: { // dont display flying data on frontend helps with point from ppl teleporting even tho they shouldn't? can be undone when soft banning is on
[Op.gt]: process.env.MAXSUSPENSION || 0.4 // basically how much we remove points with low suspenstiontravelsum
}
},
raw: true,
attributes: ['x', 'y', 'z']
}).then(function (alluserPos) {
const serializedAsBuffer = pack({ alluserPos })
io.to(socket.id).emit('chordPack', serializedAsBuffer)
}).catch(function (err) {
io.to(socket.id).emit('error', { code: 404, msg: 'Page not found' })
consola.error(err)
})
}
}
function gameSlug2Id (slug) {
for (const [key, value] of Object.entries(games)) {
if (value.slug === slug) {
return key
}
}
}
function id2GameSlug (originalKey) {
for (const [key, value] of Object.entries(games)) {
if (parseInt(key) === parseInt(originalKey)) {
return value.slug
}
}
}
function validUUID (str) {
// Regular expression to check if string is a valid UUID
const regexExp = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi
return regexExp.test(str)
}
// function niceBytes (x) {
// let l = 0; let n = parseInt(x, 10) || 0
// const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
// while (n >= 1024 && ++l) {
// n = n / 1024
// }
// return (n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l])
// }