@lxdhub/dbsync
Version:
Display, search and copy LXD-images using a web interface.
118 lines (104 loc) • 4.85 kB
text/typescript
import { Image, ImageAvailability, Remote } from '@lxdhub/db';
import { Injectable, Inject, Logger } from '@nestjs/common';
import Aigle from 'aigle';
import { LXDHubDbSyncSettings } from '../dbsync-settings.interface';
import { ImageService } from '../image';
import { LXDService } from '../lxd';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
export class ImageAvailabilityService {
private logger: Logger;
constructor(
private repository: Repository<ImageAvailability>,
private remoteRepository: Repository<Remote>,
private imageRepository: Repository<Image>,
private imageService: ImageService,
private dbSyncSettings: LXDHubDbSyncSettings,
private lxdService: LXDService
) {
this.logger = new Logger('ImageAvailabilityService');
}
async fillUpImageAvailablities() {
const remotes = await this.remoteRepository.find();
const images = await this.imageRepository.find();
for (const remote of remotes) {
for (const image of images) {
await this.getOrCreate(image, remote, false);
}
}
}
async markAsUnavailable(fingerprints: string[], remote: Remote) {
const imageAvailabilities: ImageAvailability[] = await this.repository
.find({
relations: ['image', 'remote'],
where: {
remote: { id: remote.id },
available: true,
}
});
const notAvailableImages = imageAvailabilities.filter(ai => fingerprints.indexOf(ai.image.fingerprint) === -1);
if (notAvailableImages.length === 0) {
return;
}
this.logger.log(`${notAvailableImages.length} images have been removed on the remote "${remote.name}"`);
await Promise.all(notAvailableImages.map(async imageAvailability => {
imageAvailability.available = false;
this.logger.log(`Updating Image Availability to false #${imageAvailability.id} on remote #${remote.id}`);
return await this.repository.save(imageAvailability);
}));
}
public async updateOrCreate(image: Image, remote: Remote, available: boolean = true): Promise<ImageAvailability> {
const imageAvailability = await this.get(image, remote);
if (imageAvailability) {
imageAvailability.available = available;
return await this.repository.save(imageAvailability);
} else {
return await this.create(image, remote, available);
}
}
private async getOrCreate(image: Image, remote: Remote, available: boolean = true) {
const iA = await this.get(image, remote);
if (!iA) {
return await this.create(image, remote, available);
}
return iA;
}
private async create(image: Image, remote: Remote, available: boolean = true) {
this.logger.log(`Creating Image Availability image#${image.id} remote#${remote.id} -> ${available}`);
const newImageAvailability = new ImageAvailability();
newImageAvailability.available = available;
newImageAvailability.image = image;
newImageAvailability.remote = remote;
return await this.repository.save(newImageAvailability);
}
private async get(image: Image, remote: Remote) {
return await this.repository.createQueryBuilder('iA')
.leftJoin('iA.image', 'image')
.leftJoin('iA.remote', 'remote')
.where('image.id = :imageId AND remote.id = :remoteId', { imageId: image.id, remoteId: remote.id })
.getOne();
}
async synchronize() {
this.logger.log('-> Starting image-availability synchronization');
await Aigle
.resolve(this.dbSyncSettings.lxdhubConfig.remotes)
.forEachSeries(async remote => {
const images = await this.lxdService.getRemoteImages(remote);
const localRemote = await this.remoteRepository.findOne({ name: remote.name, serverUrl: remote.url });
await Aigle
.resolve(images)
.forEachSeries(async remoteImage => {
const image = await this.imageService.getImage(remoteImage);
return await this.updateOrCreate(image, localRemote);
});
await this.markAsUnavailable(images.map(image => image.fingerprint), localRemote);
});
await this.fillUpImageAvailablities();
this.logger.log('-> Finished image-availability synchronization');
}
}