Passed
Push — filestream ( 7bdb53 )
by Jan
05:29
created

src/util-file.ts   A

Complexity

Total Complexity 11
Complexity/F 2.2

Size

Lines of Code 90
Function Count 5

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 11
eloc 74
mnd 6
bc 6
fnc 5
dl 0
loc 90
rs 10
bpm 1.2
cpm 2.2
noi 0
c 0
b 0
f 0

5 Functions

Rating   Name   Duplication   Size   Complexity  
A util-file.ts ➔ getId3TagDataFromFileSync 0 20 3
A util-file.ts ➔ getId3TagDataFromFileAsync 0 21 3
A util-file.ts ➔ completePartialId3TagDataAsync 0 13 2
A util-file.ts ➔ calculateMissingBytes 0 3 1
A util-file.ts ➔ completePartialId3TagData 0 13 2
1
import * as fs from 'fs'
2
import { promisify } from 'util'
3
import { findId3TagPosition, getId3TagSize } from './id3-tag'
4
5
const FileBufferSize = 20 * 1024 * 1024
6
const Id3TagHeaderSize = 10
7
8
const fsOpenPromise = promisify(fs.open)
9
const fsReadPromise = promisify(fs.read)
10
const fsClosePromise = promisify(fs.close)
11
12
type SuccessCallback = (err: null, buffer: Buffer) => void
13
type ErrorCallback = (err: Error, buffer: Buffer) => void
14
type Callback = SuccessCallback & ErrorCallback
15
16
export function getId3TagDataFromFileSync(filepath: string): Buffer {
17
    const fileDescriptor = fs.openSync(filepath, 'r')
18
    const buffer = Buffer.alloc(FileBufferSize)
19
20
    while(fs.readSync(fileDescriptor, buffer, {offset: Id3TagHeaderSize})) {
21
        const id3TagPosition = findId3TagPosition(buffer)
22
        if(id3TagPosition === -1) {
23
            buffer.copyWithin(0, buffer.length - 10)
24
            continue
25
        }
26
        fs.closeSync(fileDescriptor)
27
        return completePartialId3TagData(
28
            fileDescriptor,
29
            buffer.subarray(id3TagPosition)
30
        )
31
    }
32
33
    fs.closeSync(fileDescriptor)
34
    return Buffer.alloc(0)
35
}
36
37
export function getId3TagDataFromFileAsync(filepath: string, callback: Callback) {
38
    fsOpenPromise(filepath, 'r').then(async (fileDescriptor) => {
39
        const buffer = Buffer.alloc(FileBufferSize)
40
        while((await fsReadPromise(fileDescriptor, {buffer, offset: Id3TagHeaderSize})).bytesRead) {
41
            const id3TagPosition = findId3TagPosition(buffer)
42
            if(id3TagPosition === -1) {
43
                buffer.copyWithin(0, buffer.length - 10)
44
                continue
45
            }
46
            await fsClosePromise(fileDescriptor)
47
            callback(null, await completePartialId3TagDataAsync(
48
                fileDescriptor,
49
                buffer.subarray(id3TagPosition)
50
            ))
51
        }
52
53
        await fsClosePromise(fileDescriptor)
54
        callback(null, Buffer.alloc(0))
55
    }).catch((error: Error) => {
56
        callback(error, Buffer.alloc(0))
57
    })
58
}
59
60
function calculateMissingBytes(id3TagSize: number, id3TagBuffer: Buffer) {
61
    return Math.max(0, id3TagSize - id3TagBuffer.length)
62
}
63
64
function completePartialId3TagData(fileDescriptor: number, partialId3TagData: Buffer): Buffer {
65
    const id3TagSize = getId3TagSize(partialId3TagData);
66
    const missingBytesCount = calculateMissingBytes(id3TagSize, partialId3TagData)
67
    if(missingBytesCount) {
68
        const id3TagRemainingBuffer = Buffer.alloc(missingBytesCount, 0x00)
69
        fs.readSync(fileDescriptor, id3TagRemainingBuffer)
70
        return Buffer.concat([
71
            partialId3TagData,
72
            id3TagRemainingBuffer
73
        ])
74
    }
75
    return partialId3TagData.subarray(0, id3TagSize)
76
}
77
78
async function completePartialId3TagDataAsync(fileDescriptor: number, partialId3TagData: Buffer): Promise<Buffer> {
79
    const id3TagSize = getId3TagSize(partialId3TagData);
80
    const missingBytesCount = calculateMissingBytes(id3TagSize, partialId3TagData)
81
    if(missingBytesCount) {
82
        const id3TagRemainingBuffer = Buffer.alloc(missingBytesCount, 0x00)
83
        await fsReadPromise(fileDescriptor, {buffer: id3TagRemainingBuffer})
84
        return Buffer.concat([
85
            partialId3TagData,
86
            id3TagRemainingBuffer
87
        ])
88
    }
89
    return partialId3TagData.subarray(0, id3TagSize)
90
}