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.

288 lines
7.8 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
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. const express = require("express");
  2. const Workout = require("../systems/workout");
  3. /**
  4. * @param {import("../repositories/sqlite3")} repo
  5. */
  6. module.exports = function workoutRouter(repo) {
  7. const router = express.Router({caseSensitive: false});
  8. /** @type {Workout[]} */
  9. let workouts = [];
  10. function activeData(id) {
  11. const workout = workouts.find(w2 => w2.id === id);
  12. if (workout == null) {
  13. return {
  14. active: false,
  15. };
  16. }
  17. return {
  18. active: true,
  19. state: workout.state,
  20. }
  21. }
  22. router.get("/", async(req, res) => {
  23. if (req.query.active === "true") {
  24. return res.status(200).json(workouts.map(w => ({
  25. id: w.id,
  26. bike: w.bike,
  27. program: w.program,
  28. date: w.date,
  29. ...activeData(w.id),
  30. })));
  31. }
  32. try {
  33. const dbWorkouts = await repo.listWorkouts();
  34. return res.status(200).json(dbWorkouts.map(w => ({
  35. ...w,
  36. ...activeData(w.id),
  37. })));
  38. } catch (err) {
  39. return res.status(400).json({code: 400, message: err.message || err})
  40. }
  41. });
  42. router.get("/:id", async(req, res) => {
  43. let workout = workouts.find(w => w.id == req.params.id);
  44. if (workout != null) {
  45. return res.status(200).json({
  46. id: workout.id,
  47. bike: workout.bike,
  48. program: workout.program,
  49. date: workout.date,
  50. ...activeData(w.id),
  51. });
  52. }
  53. try {
  54. workout = await repo.findWorkout(req.params.id);
  55. if (workout == null) {
  56. return res.status(404).json({code: 404, message: "workout not found"})
  57. }
  58. return res.status(200).json({active: false, ...workout});
  59. } catch (err) {
  60. return res.status(500).json({code: 500, message: err.message || err})
  61. }
  62. });
  63. router.get("/:id/measurements/", async(req, res) => {
  64. try {
  65. const measurements = await repo.listMeasurements(req.params.id);
  66. if (measurements == null) {
  67. return res.status(404).json({code: 404, message: "measurements not found"})
  68. }
  69. return res.status(200).json(measurements);
  70. } catch (err) {
  71. return res.status(500).json({code: 500, message: err.message || err})
  72. }
  73. });
  74. router.post("/", async(req, res) => {
  75. try {
  76. const {bikeId, programId} = req.body;
  77. const workout = await Workout.create(repo, bikeId, programId);
  78. workouts.push(workout);
  79. return res.status(200).json({
  80. id: workout.id,
  81. bike: workout.bike,
  82. program: workout.program,
  83. date: workout.date,
  84. ...activeData(workout.id),
  85. });
  86. } catch (err) {
  87. return res.status(400).json({code: 400, message: err.message || err});
  88. }
  89. });
  90. router.post("/:id/continue", async(req, res) => {
  91. let workout = workouts.find(w => w.id == req.params.id);
  92. if (workout != null) {
  93. return res.status(400).json({code: 400, message: "Workout already active."})
  94. }
  95. try {
  96. workout = await Workout.continue(repo, req.params.id);
  97. workouts.push(workout);
  98. return res.status(200).json({
  99. id: workout.id,
  100. bike: workout.bike,
  101. program: workout.program,
  102. date: workout.date,
  103. ...activeData(w.id),
  104. });
  105. } catch (err) {
  106. return res.status(400).json({code: 400, message: err.message || err})
  107. }
  108. });
  109. router.post("/:id/connect", async(req, res) => {
  110. const workout = workouts.find(w => w.id == req.params.id);
  111. if (workout == null) {
  112. return res.status(404).json({code: 404, message: "Workout not found or inactive."})
  113. }
  114. try {
  115. await workout.connect();
  116. return res.status(200).json({
  117. id: workout.id,
  118. bike: workout.bike,
  119. program: workout.program,
  120. date: workout.date,
  121. ...activeData(workout.id),
  122. });
  123. } catch(err) {
  124. return res.status(500).json({code: 500, message: err.message || err});
  125. }
  126. });
  127. router.post("/:id/start", async(req, res) => {
  128. const workout = workouts.find(w => w.id == req.params.id);
  129. if (workout == null) {
  130. return res.status(404).json({code: 404, message: "Workout not found or inactive."})
  131. }
  132. try {
  133. await workout.start();
  134. return res.status(200).json({
  135. id: workout.id,
  136. bike: workout.bike,
  137. program: workout.program,
  138. date: workout.date,
  139. ...activeData(workout.id),
  140. });
  141. } catch(err) {
  142. return res.status(500).json({code: 500, message: err.message || err});
  143. }
  144. });
  145. router.post("/:id/pause", async(req, res) => {
  146. const workout = workouts.find(w => w.id == req.params.id);
  147. if (workout == null) {
  148. return res.status(404).json({code: 404, message: "Workout not found or inactive."})
  149. }
  150. try {
  151. await workout.pause();
  152. return res.status(200).json({
  153. id: workout.id,
  154. bike: workout.bike,
  155. program: workout.program,
  156. date: workout.date,
  157. ...activeData(workout.id),
  158. });
  159. } catch(err) {
  160. return res.status(500).json({code: 500, message: err.message || err});
  161. }
  162. });
  163. router.post("/:id/stop", async(req, res) => {
  164. const workout = workouts.find(w => w.id == req.params.id);
  165. if (workout == null) {
  166. return res.status(404).json({code: 404, message: "Workout not found or inactive."})
  167. }
  168. try {
  169. if (workout.driver != null) {
  170. await workout.stop();
  171. }
  172. workouts = workouts.filter(w => w !== workout);
  173. await workout.destroy();
  174. return res.status(200).json({
  175. id: workout.id,
  176. bike: workout.bike,
  177. program: workout.program,
  178. date: workout.date,
  179. ...activeData(workout.id),
  180. });
  181. } catch(err) {
  182. return res.status(500).json({code: 500, message: err.message || err});
  183. }
  184. });
  185. router.delete("/:id", async(req, res) => {
  186. let workout = workouts.find(w => w.id == req.params.id);
  187. if (workout != null) {
  188. return res.status(400).json({code: 400, message: "Workout already active."})
  189. }
  190. try {
  191. workout = await repo.findWorkout(req.params.id);
  192. if (workout == null) {
  193. return res.status(404).json({code: 404, message: "workout not found"})
  194. }
  195. await repo.deleteWorkout(workout);
  196. return res.status(200).json({
  197. id: workout.id,
  198. bike: workout.bike,
  199. program: workout.program,
  200. date: workout.date,
  201. ...activeData(workout.id),
  202. });
  203. } catch (err) {
  204. return res.status(500).json({code: 500, message: err.message || err})
  205. }
  206. });
  207. router.ws("/:id/subscribe", (ws, req) => {
  208. const workout = workouts.find(w => w.id === req.params.id);
  209. if (workout == null) {
  210. ws.send(JSON.stringify({error: "workout not found"}));
  211. ws.close();
  212. }
  213. workout.listMeasurements().then((list) => {
  214. list = list.map(v => {delete v.id; delete v.workoutId; return v});
  215. for (let i = 0; i < list.length; i += 240) {
  216. ws.send(JSON.stringify({workoutStatusBackfill: list.slice(i, i+240)}));
  217. }
  218. }).catch(err => {
  219. ws.send(JSON.stringify({error: `could not list measurements: ${err.message || err}`}));
  220. ws.close();
  221. });
  222. const onWorkoutStatus = (workoutStatus) => {
  223. workoutStatus = {...workoutStatus};
  224. delete workoutStatus.id;
  225. ws.send(JSON.stringify({workoutStatus}))
  226. }
  227. workout.events.on("workoutStatus", onWorkoutStatus);
  228. const onState = (state) => {
  229. ws.send(JSON.stringify({state}))
  230. }
  231. workout.events.on("state", onState);
  232. ws.onclose = () => {
  233. workout.events.removeListener("workoutStatus", onWorkoutStatus);
  234. workout.events.removeListener("state", onState);
  235. ws.removeAllListeners();
  236. };
  237. ws.send(JSON.stringify({
  238. state: workout.state,
  239. workout: {
  240. id: workout.id,
  241. bike: workout.bike,
  242. program: workout.program,
  243. date: workout.date,
  244. },
  245. }));
  246. })
  247. return router;
  248. }