All files / app/core/services cas.service.ts

97.36% Statements 37/38
100% Branches 2/2
100% Functions 10/10
97.29% Lines 36/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                  1x   18x 18x       10x 10x         10x 10x   10x 9x     10x       4x   4x 4x 2x         2x         1x 1x       1x   1x               2x 2x   2x 6x   5x 5x 4x 4x 4x 4x 4x   4x             1x 1x       2x 5x       15x    
import { Injectable, Inject } from '@angular/core';
import { IContentStorage, IStorageProvider } from '../domain/interfaces/storage.interface';
import { Content, ContentHash, ContentMetadata, ContentWithHash } from '../domain/interfaces/content.interface';
import { HashService } from './hash.service';
import { STORAGE_PROVIDER } from './storage-provider.factory';
 
@Injectable({
  providedIn: 'root'
})
export class CasService implements IContentStorage {
  constructor(
    private hashService: HashService,
    @Inject(STORAGE_PROVIDER) private storageService: IStorageProvider
  ) {}
 
  async store(content: Content): Promise<ContentHash> {
    const hashValue = await this.hashService.hash(content.data);
    const contentHash: ContentHash = {
      algorithm: 'sha256',
      value: hashValue
    };
 
    const path = this.getPath(contentHash);
    const exists = await this.storageService.exists(path);
 
    if (!exists) {
      await this.storageService.write(path, content.data);
    }
 
    return contentHash;
  }
 
  async retrieve(hash: ContentHash): Promise<Content> {
    const path = this.getPath(hash);
    
    try {
      const data = await this.storageService.read(path);
      return {
        data,
        hash
      };
    } catch (error) {
      throw new Error('Content not found');
    }
  }
 
  async exists(hash: ContentHash): Promise<boolean> {
    const path = this.getPath(hash);
    return this.storageService.exists(path);
  }
 
  async getMetadata(hash: ContentHash): Promise<ContentMetadata> {
    const content = await this.retrieve(hash);
    
    return {
      hash,
      size: content.data.length,
      createdAt: new Date()
    };
  }
 
  async getAllContent(): Promise<ContentWithHash[]> {
    const paths = await this.storageService.list();
    const casPrefix = 'cas/';
    
    const contentPromises = paths
      .filter((path: string) => path.startsWith(casPrefix))
      .map(async (path: string) => {
        try {
          const data = await this.storageService.read(path);
          const parts = path.split('/');
          if (parts.length >= 3) {
            const algorithm = parts[1];
            const value = parts[2];
            const hash: ContentHash = { algorithm, value };
            
            return {
              content: { data },
              hash
            };
          }
          return null;
        } catch (error) {
          console.error(`Error reading path ${path}:`, error);
          return null;
        }
      });
    
    const results = await Promise.all(contentPromises);
    return results.filter((item: ContentWithHash | null): item is ContentWithHash => item !== null);
  }
 
  private getPath(hash: ContentHash): string {
    return `cas/${hash.algorithm}/${hash.value}`;
  }
}