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.
180 lines
4.1 KiB
180 lines
4.1 KiB
const EventEmitter = require("events");
|
|
const createDriver = require("../drivers");
|
|
|
|
class Workout {
|
|
/**
|
|
* @param {import("../repositories/sqlite3")} repo
|
|
* @param {number} id
|
|
* @param {{
|
|
* id: string,
|
|
* name: string,
|
|
* driver: string,
|
|
* connect: string,
|
|
* maxLevel: number,
|
|
* }} bike
|
|
* @param {{
|
|
* id: number,
|
|
* name: string,
|
|
* cpm: number,
|
|
* warmupMin: number,
|
|
* warmupCpm: number,
|
|
* }} program
|
|
* @param {Date} date
|
|
*/
|
|
constructor(repo, id, bike, program, date) {
|
|
this.repo = repo;
|
|
this.id = id;
|
|
this.bike = bike;
|
|
this.program = program;
|
|
this.date = date;
|
|
this.driver = null;
|
|
|
|
this.state = "disconnected";
|
|
|
|
this.offsetSeconds = 0;
|
|
this.offsets = {};
|
|
|
|
this.events = new EventEmitter();
|
|
|
|
this.events.emit("state", this.state);
|
|
}
|
|
|
|
async connect() {
|
|
if (this.state !== "disconnected") {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
this.driver = createDriver(this.bike.driver, this.bike.connect);
|
|
this.driver.events.on("workoutStatus", ws => this.handleworkoutStatus(ws));
|
|
|
|
return this.driver.connect().then((v) => {
|
|
this.state = this.driver.state;
|
|
this.events.emit("state", this.state);
|
|
return v;
|
|
});
|
|
}
|
|
|
|
start() {
|
|
if (this.state === "started") {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return this.driver.start().then((v) => {
|
|
this.state = this.driver.state;
|
|
this.events.emit("state", this.state);
|
|
return v;
|
|
});
|
|
}
|
|
|
|
pause() {
|
|
if (this.state !== "started") {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return this.driver.pause().then((v) => {
|
|
this.state = this.driver.state;
|
|
this.events.emit("state", this.state);
|
|
return v;
|
|
});
|
|
}
|
|
|
|
stop() {
|
|
if (this.state === "started") {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return this.driver.stop().then((v) => {
|
|
this.state = this.driver.state;
|
|
this.events.emit("state", this.state);
|
|
return v;
|
|
});
|
|
}
|
|
|
|
destroy() {
|
|
this.events.emit("destroy");
|
|
this.events.removeAllListeners();
|
|
|
|
if (this.driver != null) {
|
|
this.driver.destroy();
|
|
this.state = this.driver.state;
|
|
this.events.emit("state", this.state);
|
|
this.driver = null;
|
|
}
|
|
}
|
|
|
|
listMeasurements() {
|
|
return this.repo.listMeasurements(this.id);
|
|
}
|
|
|
|
handleworkoutStatus(ws) {
|
|
if (this.offsetSeconds > 0) {
|
|
const seconds = (ws.minutes * 60) + ws.seconds + this.offsetSeconds;
|
|
ws.minutes = Math.floor(seconds / 60);
|
|
ws.seconds = seconds % 60;
|
|
|
|
for (const key in this.offsets) {
|
|
if (!this.offsets.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
|
|
ws[key] += this.offsets[key];
|
|
}
|
|
}
|
|
|
|
this.repo.insertMeasurement({...ws, workoutId: this.id});
|
|
|
|
this.events.emit("workoutStatus", {...ws});
|
|
}
|
|
|
|
/**
|
|
* @param {import("../repositories/sqlite3")} repo
|
|
* @param {number} bikeId
|
|
* @param {number} programId
|
|
*/
|
|
static async create(repo, bikeId, programId) {
|
|
const bike = await repo.findBike(bikeId);
|
|
if (bike == null) {
|
|
throw new Error("bike not found");
|
|
}
|
|
const program = await repo.findProgram(programId);
|
|
if (program == null) {
|
|
throw new Error("program not found");
|
|
}
|
|
|
|
const date = new Date();
|
|
const id = await repo.insertWorkout({
|
|
bikeId: bike.id,
|
|
programId: program.id,
|
|
date: date,
|
|
});
|
|
|
|
return new Workout(repo, id, bike, program, date);
|
|
}
|
|
|
|
/**
|
|
* @param {import("../repositories/sqlite3")} repo
|
|
* @param {number} id
|
|
*/
|
|
static async continue(repo, id) {
|
|
const data = await repo.findWorkout(id);
|
|
const bike = await repo.findBike(data.bikeId);
|
|
const program = await repo.findWorkout(data.workoutId);
|
|
|
|
const workout = new Workout(repo, id, bike, program, new Date(data.date));
|
|
|
|
const list = await repo.listMeasurements(id);
|
|
if (list.length > 0) {
|
|
const last = list[list.length - 1];
|
|
|
|
workout.offsetSeconds = (last.minutes * 60 + last.seconds);
|
|
workout.offsets = {
|
|
distance: last.distance,
|
|
calories: last.calories,
|
|
}
|
|
}
|
|
|
|
return workout;
|
|
}
|
|
}
|
|
|
|
module.exports = Workout;
|