@learnpack/learnpack 5.0.32 → 5.0.33

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.
@@ -58,7 +58,7 @@ export default async function (
58
58
 
59
59
  // Added this line to parse the json body
60
60
 
61
- const jsonBodyParser = bodyParser.json()
61
+ const jsonBodyParser = bodyParser.json({ limit: "10mb" })
62
62
  // Trying to log in from frontend
63
63
  app.post(
64
64
  "/login",
@@ -172,10 +172,15 @@ export default async function (
172
172
  })
173
173
  )
174
174
 
175
- app.get("/telemetry/step/:stepPosition", (req, res) => {
176
- const stepPosition = parseInt(req.params.stepPosition)
177
- const step = TelemetryManager.getStep(stepPosition)
178
- res.json(step)
175
+ app.get("/telemetry", async (req, res) => {
176
+ const telemetry = await TelemetryManager.retrieve()
177
+ res.json(telemetry)
178
+ })
179
+
180
+ app.post("/telemetry", jsonBodyParser, async (req, res) => {
181
+ const telemetry = req.body
182
+ await TelemetryManager.save(telemetry)
183
+ res.json({ message: "Telemetry saved successfully" })
179
184
  })
180
185
 
181
186
  app.get(
@@ -185,12 +190,6 @@ export default async function (
185
190
 
186
191
  if (payload && payload.rigobot && payload.rigobot.key) {
187
192
  res.json({ rigoToken: payload.rigobot.key, payload: payload })
188
-
189
- TelemetryManager.setStudent({
190
- user_id: payload.user_id,
191
- email: payload.email,
192
- token: payload.token,
193
- })
194
193
  } else {
195
194
  res
196
195
  .status(400)
@@ -137,11 +137,6 @@ const Session: ISession = {
137
137
  if (data) {
138
138
  this.start({ token: data.token, payload: data })
139
139
 
140
- TelemetryManager.setStudent({
141
- user_id: data.user_id,
142
- email: data.email,
143
- token: data.token,
144
- })
145
140
  return data
146
141
  }
147
142
  },
@@ -1,5 +1,5 @@
1
1
  import { IFile } from "../models/file"
2
- import API from "../utils/api"
2
+ import { ISocket } from "../models/socket"
3
3
  const packageInfo = require("../../package.json")
4
4
  import Console from "../utils/console"
5
5
 
@@ -107,242 +107,46 @@ type TUser = {
107
107
  email: string
108
108
  }
109
109
 
110
- interface ITelemetryManager {
111
- current: ITelemetryJSONSchema | null
110
+ interface ITelemetryManagerCLI {
112
111
  configPath: string | null
113
- user: TUser
114
- urls: TTelemetryUrls
115
- started: boolean
112
+ socket: ISocket | null
116
113
  version: string
117
- salute: (message: string) => void
118
- start: (
119
- agent: string,
120
- steps: TStep[],
121
- path: string,
122
- tutorialSlug: string
123
- ) => void
124
- prevStep?: number
114
+ start: (path: string, socket: ISocket) => void
125
115
  registerStepEvent: (
126
116
  stepPosition: number,
127
117
  event: TStepEvent,
128
118
  data: any
129
119
  ) => void
130
- streamEvent: (stepPosition: number, event: string, data: any) => void
131
- submit: () => Promise<void>
132
- finishWorkoutSession: () => void
133
- setStudent: (student: TStudent) => void
134
- save: () => void
120
+ save: (telemetry: ITelemetryJSONSchema) => void
135
121
  retrieve: () => Promise<ITelemetryJSONSchema | null>
136
- getStep: (stepPosition: number) => TStep | null
137
122
  }
138
123
 
139
- const TelemetryManager: ITelemetryManager = {
140
- current: null,
141
- urls: {},
124
+ const TelemetryManager: ITelemetryManagerCLI = {
142
125
  version: packageInfo.version,
143
- user: {
144
- token: "",
145
- id: "",
146
- email: "",
147
- },
126
+ socket: null,
127
+
148
128
  configPath: "",
149
- started: false,
150
- salute: message => {
151
- Console.info(message)
152
- },
153
129
 
154
- start: function (agent, steps, path, tutorialSlug) {
130
+ start: function (path, socket) {
155
131
  this.configPath = path
156
- if (!this.current) {
157
- this.retrieve()
158
- .then(data => {
159
- const prevTelemetry = data
160
- if (prevTelemetry) {
161
- this.current = prevTelemetry
162
- this.finishWorkoutSession()
163
- } else {
164
- this.current = {
165
- telemetry_id: createUUID(),
166
- slug: tutorialSlug,
167
- version: `CLI:${this.version}`,
168
- user_id: 0,
169
- agent,
170
- tutorial_started_at: Date.now(),
171
- last_interaction_at: Date.now(),
172
- steps,
173
- workout_session: [
174
- {
175
- started_at: Date.now(),
176
- },
177
- ],
178
- }
179
- }
180
-
181
- if (this.current.user_id) {
182
- this.user.id = this.current.user_id.toString()
183
- }
184
-
185
- if (!this.current.version) {
186
- this.current.version = `CLI:${this.version}`
187
- }
188
-
189
- this.save()
190
-
191
- this.started = true
192
- Console.debug("Telemetry started successfully!")
193
-
194
- if (!this.user.id) {
195
- Console.debug(
196
- "No user ID found, impossible to submit telemetry at start"
197
- )
198
- return
199
- }
200
-
201
- this.submit()
202
- })
203
- .catch(error => {
204
- Console.debug(error)
205
- // Delete the telemetry.json if it exists
206
- fs.unlinkSync(`${this.configPath}/telemetry.json`)
207
- throw new Error(
208
- "There was a problem starting, reload LearnPack\nRun\n$ learnpack start"
209
- )
210
- })
211
- }
212
- },
213
-
214
- setStudent: function (student) {
215
- if (!this.current) {
216
- Console.debug("Telemetry has not been started")
217
-
218
- return
219
- }
220
-
221
- Console.debug("Setting student", student)
222
-
223
- this.current.user_id = student.user_id
224
- this.user.id = student.user_id
225
- this.user.token = student.token
226
- this.user.email = student.email
227
- this.save()
228
- this.submit()
229
- },
230
- finishWorkoutSession: function () {
231
- if (!this.current) {
232
- return
233
- }
234
-
235
- const lastSession =
236
- this.current?.workout_session[this.current.workout_session.length - 1]
237
- if (
238
- lastSession &&
239
- !lastSession.ended_at &&
240
- this.current?.last_interaction_at
241
- ) {
242
- lastSession.ended_at = this.current.last_interaction_at
243
- this.current.workout_session.push({
244
- started_at: Date.now(),
245
- })
246
- }
132
+ this.socket = socket
247
133
  },
248
134
 
249
135
  registerStepEvent: function (stepPosition, event, data) {
250
- Console.debug(`Registering Event ${event} for user ${this.user.id}`)
251
-
252
- if (!this.current) {
253
- // throw new Error("Telemetry has not been started");
254
- return
255
- }
256
-
257
- const step = this.current.steps[stepPosition]
258
- if (!step) {
259
- return
260
- }
261
-
262
- if (data.source_code) {
263
- data.source_code = stringToBase64(data.source_code)
264
- }
265
-
266
- if (data.stdout) {
267
- data.stdout = stringToBase64(data.stdout)
268
- }
269
-
270
- if (data.stderr) {
271
- data.stderr = stringToBase64(data.stderr)
272
- }
273
-
274
- if (Object.prototype.hasOwnProperty.call(data, "exitCode")) {
275
- data.exit_code = data.exitCode
276
- data.exitCode = undefined
277
- }
278
-
279
- switch (event) {
280
- case "compile":
281
- if (!step.compilations) {
282
- step.compilations = []
283
- }
284
-
285
- step.compilations.push(data)
286
- this.current.steps[stepPosition] = step
287
- break
288
- case "test":
289
- if (!step.tests) {
290
- step.tests = []
291
- }
292
-
293
- // data.stdout =
294
- step.tests.push(data)
295
- if (data.exit_code === 0) {
296
- step.completed_at = Date.now()
297
- }
298
-
299
- this.current.steps[stepPosition] = step
300
- break
301
- case "ai_interaction":
302
- if (!step.ai_interactions) {
303
- step.ai_interactions = []
304
- }
305
-
306
- step.ai_interactions.push(data)
307
- break
308
-
309
- case "quiz_submission": {
310
- if (!step.quiz_submissions) {
311
- step.quiz_submissions = []
312
- }
313
-
314
- step.quiz_submissions.push(data)
315
- break
136
+ Console.debug(`Registering Telemetry Event ${event}`)
137
+
138
+ this.socket?.emit(
139
+ "telemetry_event",
140
+ "ready",
141
+ [`Registering telemetry event ${event}`],
142
+ [],
143
+ [],
144
+ {
145
+ stepPosition,
146
+ event,
147
+ data,
316
148
  }
317
-
318
- case "open_step": {
319
- const now = Date.now()
320
-
321
- if (!step.opened_at) {
322
- step.opened_at = now
323
- this.current.steps[stepPosition] = step
324
- }
325
-
326
- if (this.prevStep || this.prevStep === 0) {
327
- const prevStep = this.current.steps[this.prevStep]
328
- if (!prevStep.is_testeable && !prevStep.completed_at) {
329
- prevStep.completed_at = now
330
- this.current.steps[this.prevStep] = prevStep
331
- }
332
- }
333
-
334
- this.prevStep = stepPosition
335
- this.submit()
336
- break
337
- }
338
-
339
- default:
340
- throw new Error(`Event type ${event} is not supported`)
341
- }
342
-
343
- this.current.last_interaction_at = Date.now()
344
- this.streamEvent(stepPosition, event, data)
345
- this.save()
149
+ )
346
150
  },
347
151
  retrieve: function () {
348
152
  return new Promise((resolve, reject) => {
@@ -360,8 +164,8 @@ const TelemetryManager: ITelemetryManager = {
360
164
  } else {
361
165
  try {
362
166
  resolve(JSON.parse(data))
363
- } catch (error) {
364
- reject(error)
167
+ } catch {
168
+ resolve(null)
365
169
  }
366
170
  }
367
171
  }
@@ -369,70 +173,16 @@ const TelemetryManager: ITelemetryManager = {
369
173
  })
370
174
  },
371
175
 
372
- getStep: function (stepPosition: number) {
373
- return this.current?.steps[stepPosition] || null
374
- },
375
-
376
- submit: async function () {
377
- Console.debug("Submitting telemetry...")
378
-
379
- if (!this.current) {
380
- Console.debug("Telemetry has not been started")
381
- return Promise.resolve()
382
- }
383
-
384
- if (!this.user.id) {
385
- Console.debug("User ID not found, skipping batch telemetry delivery")
386
- return Promise.resolve()
387
- }
388
-
389
- const url = this.urls.batch
390
- if (!url) {
391
- Console.debug("Batch URL not found, skipping batch telemetry delivery")
392
- return Promise.resolve()
393
- }
394
-
395
- const body = this.current
396
-
397
- if (!body.user_id) {
398
- body.user_id = this.user.id
399
- }
400
-
401
- API.sendBatchTelemetry(url, body)
402
- },
403
- save: function () {
176
+ save: function (telemetry: ITelemetryJSONSchema) {
404
177
  fs.writeFile(
405
178
  `${this.configPath}/telemetry.json`,
406
- JSON.stringify(this.current),
179
+ JSON.stringify(telemetry),
407
180
  (err: any) => {
408
181
  if (err)
409
182
  throw err
410
183
  }
411
184
  )
412
185
  },
413
-
414
- streamEvent: async function (stepPosition, event, data) {
415
- if (!this.current)
416
- return
417
-
418
- const url = this.urls.streaming
419
- if (!url) {
420
- return
421
- }
422
-
423
- const stepSlug = this.current.steps[stepPosition].slug
424
-
425
- const body = {
426
- slug: stepSlug,
427
- telemetry_id: this.current.telemetry_id,
428
- user_id: this.current.user_id,
429
- step_position: stepPosition,
430
- event,
431
- data,
432
- }
433
-
434
- API.sendStreamTelemetry(url, body)
435
- },
436
186
  }
437
187
 
438
188
  export default TelemetryManager
@@ -1,12 +1,13 @@
1
- export type TAction =
2
- | "test"
3
- | "log"
4
- | "reload"
5
- | "ready"
6
- | "clean"
7
- | "ask"
8
- | "file_change"
9
- | "dialog"
10
- | "session-refreshed"
11
-
12
- export type ICallback = (...agrs: any[]) => any
1
+ export type TAction =
2
+ | "test"
3
+ | "log"
4
+ | "reload"
5
+ | "ready"
6
+ | "clean"
7
+ | "ask"
8
+ | "file_change"
9
+ | "dialog"
10
+ | "session-refreshed"
11
+ | "telemetry_event"
12
+
13
+ export type ICallback = (...agrs: any[]) => any
@@ -13,4 +13,4 @@ export type TStatus =
13
13
  | "open_files"
14
14
  | "open_window"
15
15
  | "instructions_closed"
16
- | "completed";
16
+ | "completed"