You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
4.1 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. const EventEmitter = require("events");
  2. const createDriver = require("../drivers");
  3. class Workout {
  4. /**
  5. * @param {import("../repositories/sqlite3")} repo
  6. * @param {number} id
  7. * @param {{
  8. * id: string,
  9. * name: string,
  10. * driver: string,
  11. * connect: string,
  12. * maxLevel: number,
  13. * }} bike
  14. * @param {{
  15. * id: number,
  16. * name: string,
  17. * cpm: number,
  18. * warmupMin: number,
  19. * warmupCpm: number,
  20. * }} program
  21. * @param {Date} date
  22. */
  23. constructor(repo, id, bike, program, date) {
  24. this.repo = repo;
  25. this.id = id;
  26. this.bike = bike;
  27. this.program = program;
  28. this.date = date;
  29. this.driver = null;
  30. this.state = "disconnected";
  31. this.offsetSeconds = 0;
  32. this.offsets = {};
  33. this.events = new EventEmitter();
  34. this.events.emit("state", this.state);
  35. }
  36. async connect() {
  37. if (this.state !== "disconnected") {
  38. return Promise.resolve();
  39. }
  40. this.driver = createDriver(this.bike.driver, this.bike.connect);
  41. this.driver.events.on("workoutStatus", ws => this.handleworkoutStatus(ws));
  42. return this.driver.connect().then((v) => {
  43. this.state = this.driver.state;
  44. this.events.emit("state", this.state);
  45. return v;
  46. });
  47. }
  48. start() {
  49. if (this.state === "started") {
  50. return Promise.resolve();
  51. }
  52. return this.driver.start().then((v) => {
  53. this.state = this.driver.state;
  54. this.events.emit("state", this.state);
  55. return v;
  56. });
  57. }
  58. pause() {
  59. if (this.state !== "started") {
  60. return Promise.resolve();
  61. }
  62. return this.driver.pause().then((v) => {
  63. this.state = this.driver.state;
  64. this.events.emit("state", this.state);
  65. return v;
  66. });
  67. }
  68. stop() {
  69. if (this.state === "started") {
  70. return Promise.resolve();
  71. }
  72. return this.driver.stop().then((v) => {
  73. this.state = this.driver.state;
  74. this.events.emit("state", this.state);
  75. return v;
  76. });
  77. }
  78. destroy() {
  79. this.events.emit("destroy");
  80. this.events.removeAllListeners();
  81. if (this.driver != null) {
  82. this.driver.destroy();
  83. this.state = this.driver.state;
  84. this.events.emit("state", this.state);
  85. this.driver = null;
  86. }
  87. }
  88. listMeasurements() {
  89. return this.repo.listMeasurements(this.id);
  90. }
  91. handleworkoutStatus(ws) {
  92. if (this.offsetSeconds > 0) {
  93. const seconds = (ws.minutes * 60) + ws.seconds + this.offsetSeconds;
  94. ws.minutes = Math.floor(seconds / 60);
  95. ws.seconds = seconds % 60;
  96. for (const key in this.offsets) {
  97. if (!this.offsets.hasOwnProperty(key)) {
  98. continue;
  99. }
  100. ws[key] += this.offsets[key];
  101. }
  102. }
  103. this.repo.insertMeasurement({...ws, workoutId: this.id});
  104. this.events.emit("workoutStatus", {...ws});
  105. }
  106. /**
  107. * @param {import("../repositories/sqlite3")} repo
  108. * @param {number} bikeId
  109. * @param {number} programId
  110. */
  111. static async create(repo, bikeId, programId) {
  112. const bike = await repo.findBike(bikeId);
  113. if (bike == null) {
  114. throw new Error("bike not found");
  115. }
  116. const program = await repo.findProgram(programId);
  117. if (program == null) {
  118. throw new Error("program not found");
  119. }
  120. const date = new Date();
  121. const id = await repo.insertWorkout({
  122. bikeId: bike.id,
  123. programId: program.id,
  124. date: date,
  125. });
  126. return new Workout(repo, id, bike, program, date);
  127. }
  128. /**
  129. * @param {import("../repositories/sqlite3")} repo
  130. * @param {number} id
  131. */
  132. static async continue(repo, id) {
  133. const data = await repo.findWorkout(id);
  134. const bike = await repo.findBike(data.bikeId);
  135. const program = await repo.findWorkout(data.workoutId);
  136. const workout = new Workout(repo, id, bike, program, new Date(data.date));
  137. const list = await repo.listMeasurements(id);
  138. if (list.length > 0) {
  139. const last = list[list.length - 1];
  140. workout.offsetSeconds = (last.minutes * 60 + last.seconds);
  141. workout.offsets = {
  142. distance: last.distance,
  143. calories: last.calories,
  144. }
  145. }
  146. return workout;
  147. }
  148. }
  149. module.exports = Workout;