adding suport for CRC32 SFV

This commit is contained in:
Metazla
2024-04-06 11:48:18 +02:00
parent dcc51bf41d
commit e28f924837
28 changed files with 353 additions and 172 deletions
+74
View File
@@ -1 +1,75 @@
# Meta-Hash
Meta-Hash is a TypeScript library designed to monitor a specified folder and compute hashes for any new files detected within it. This library leverages an index system to avoid recomputing hashes if the program is restarted, ensuring efficiency and continuity in hash computation. The hashes are computed in the Content Identifier (CID) format, making them compatible with systems like IPFS (InterPlanetary File System).
## Features
- **Efficient Hash Computation**: Automatically computes hashes for new files using multiple algorithms, including SHA2-256, SHA1, MD5, SHA3-256 and more.
- **Persistent Indexing**: Utilizes an index system to record file hashes, sizes, and modification times, preventing the need for rehashing on program restarts.
- **CID Format**: Hashes are stored in the CID format, facilitating integration with IPFS and similar distributed file systems.
## CID Format and Inspection
The Content Identifier (CID) is a label used to point to material in IPFS. It doesn't indicate where the content is stored, but it forms a kind of address based on the content itself. CIDs are used as a standard way of pointing to pieces of information. A single CID can represent a piece of content that is distributed across multiple systems.
The list of CID formats used in this project can be found at the following link:
[Multicodecs Table](https://ipfs.io/ipfs/QmXec1jjwzxWJoNbxQF5KffL8q6hFXm9QwUGaa3wKGk6dT/#title=Multicodecs&src=https://raw.githubusercontent.com/multiformats/multicodec/master/table.csv)
To inspect the details of a CID, including its version, codec, multihash and more, you can use the CID Inspector tool. This tool allows you to enter a CID and it will break it down into its component parts and provide a detailed explanation of each part.
[CID Inspector Tool](https://cid.ipfs.tech/)
## Installation
To use Meta-Hash in your project, clone this repository and install the required dependencies.
```bash
#to install
yarn add metazla@[email protected]:Metazla/meta-hash.git
#to update
yarn up -i @metazla/meta-hash
```
## Usage of ComputeHashIndexCache
To integrate Meta-Hash into your application, follow these steps:
1. **Import the Library**: Import the necessary components from the library.
```typescript
import { ComputeHashIndexCache, CID_ALGORITHM_NAMES } from "./folder-watch-hasher";
```
2. **Initialize the Watcher**: Create an instance of `ComputeHashIndexCache`, specifying the path to the folder you want to monitor and the hash algorithms you wish to use.
```typescript
//note that the csv file will be derived from the path provided into multiple files (one for each algorithm)
const computer = new ComputeHashIndexCache("path/to/your/indexfile/index.csv", [CID_ALGORITHM_NAMES.sha256, CID_ALGORITHM_NAMES.sha1]);
```
3. **Compute Hashes**: Invoke the `computeMissingHash` method for each file you wish to hash. This method will automatically check the index for existing hashes and compute missing ones.
```typescript
let hash:MultiHashData = {};
await computer.computeMissingHash("path/to/your/file.txt", hash);
console.log(hash[CID_ALGORITHM_NAMES.sha256]);
```
## Example of Index File
An example index file (`index-cid_sha2-256.csv`) is shown below, demonstrating how file paths, sizes, modification times, and computed hashes are stored:
```
path,size,mtime,cid_sha2-256
file.mkv,230265591,2023-01-17T18:53:37.692Z,baejbeif45glg263244x7cbjzyd3ssp5edzae7bxurzxjhnogazcwmj32wa
...
```
## Contributing
Contributions to Meta-Hash are welcome! Please read our contributing guidelines for more information on how to participate.
## License
Meta-Hash is released under the [MIT License](LICENSE.md).
@@ -1,35 +1,44 @@
import { BinaryLike } from 'crypto';
interface MultiHashData { interface MultiHashData {
"cid_sha2-256"?: string; "cid_sha2-256"?: string;
cid_sha1?: string; cid_sha1?: string;
cid_md5?: string; cid_md5?: string;
"cid_sha3-256"?: string; "cid_sha3-256"?: string;
cid_crc32?: string;
} }
interface ComputeInterface { interface ComputeInterface {
computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>; computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>;
} }
/**
* according to
* https://ipfs.io/ipfs/QmXec1jjwzxWJoNbxQF5KffL8q6hFXm9QwUGaa3wKGk6dT/#title=Multicodecs&src=https://raw.githubusercontent.com/multiformats/multicodec/master/table.csv
*/
declare enum CID_ALGORITHM_CODES { declare enum CID_ALGORITHM_CODES {
sha256 = 18, crc32 = 306,
sha1 = 17,
md5 = 213, md5 = 213,
sha3_256 = 22 sha1 = 17,
sha256 = 18,
sha3_256 = 22,
sha3_384 = 21
} }
declare enum CID_ALGORITHM_NAMES { declare enum CID_ALGORITHM_NAMES {
sha256 = "cid_sha2-256", crc32 = "cid_crc32",
sha1 = "cid_sha1",
md5 = "cid_md5", md5 = "cid_md5",
sha3_256 = "cid_sha3-256" sha1 = "cid_sha1",
sha256 = "cid_sha2-256",
sha3_256 = "cid_sha3-256",
sha3_384 = "cid_sha3-384"
} }
declare enum CID_ALGORITHM { declare enum CID_ALGORITHM {
sha256 = "sha2-256", crc32 = "crc32",
sha1 = "sha1",
md5 = "md5", md5 = "md5",
sha3_256 = "sha3-256" sha1 = "sha1",
sha256 = "sha2-256",
sha3_256 = "sha3-256",
sha3_384 = "sha3-384"
} }
interface SimpleHash { interface SimpleHash {
update(data: BinaryLike): any; update(data: Buffer): any;
digest(): Buffer; digest(): Buffer;
} }
/** /**
@@ -1,35 +1,44 @@
import { BinaryLike } from 'crypto';
interface MultiHashData { interface MultiHashData {
"cid_sha2-256"?: string; "cid_sha2-256"?: string;
cid_sha1?: string; cid_sha1?: string;
cid_md5?: string; cid_md5?: string;
"cid_sha3-256"?: string; "cid_sha3-256"?: string;
cid_crc32?: string;
} }
interface ComputeInterface { interface ComputeInterface {
computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>; computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>;
} }
/**
* according to
* https://ipfs.io/ipfs/QmXec1jjwzxWJoNbxQF5KffL8q6hFXm9QwUGaa3wKGk6dT/#title=Multicodecs&src=https://raw.githubusercontent.com/multiformats/multicodec/master/table.csv
*/
declare enum CID_ALGORITHM_CODES { declare enum CID_ALGORITHM_CODES {
sha256 = 18, crc32 = 306,
sha1 = 17,
md5 = 213, md5 = 213,
sha3_256 = 22 sha1 = 17,
sha256 = 18,
sha3_256 = 22,
sha3_384 = 21
} }
declare enum CID_ALGORITHM_NAMES { declare enum CID_ALGORITHM_NAMES {
sha256 = "cid_sha2-256", crc32 = "cid_crc32",
sha1 = "cid_sha1",
md5 = "cid_md5", md5 = "cid_md5",
sha3_256 = "cid_sha3-256" sha1 = "cid_sha1",
sha256 = "cid_sha2-256",
sha3_256 = "cid_sha3-256",
sha3_384 = "cid_sha3-384"
} }
declare enum CID_ALGORITHM { declare enum CID_ALGORITHM {
sha256 = "sha2-256", crc32 = "crc32",
sha1 = "sha1",
md5 = "md5", md5 = "md5",
sha3_256 = "sha3-256" sha1 = "sha1",
sha256 = "sha2-256",
sha3_256 = "sha3-256",
sha3_384 = "sha3-384"
} }
interface SimpleHash { interface SimpleHash {
update(data: BinaryLike): any; update(data: Buffer): any;
digest(): Buffer; digest(): Buffer;
} }
/** /**
+20
View File
@@ -0,0 +1,20 @@
'use strict';
var fs = require('fs');
var crypto = require('crypto');
var cid = require('multiformats/cid');
var digest = require('multiformats/hashes/digest');
var x = require('crc-32');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var x__default = /*#__PURE__*/_interopDefault(x);
var o=(s=>(s[s.crc32=306]="crc32",s[s.md5=213]="md5",s[s.sha1=17]="sha1",s[s.sha256=18]="sha256",s[s.sha3_256=22]="sha3_256",s[s.sha3_384=21]="sha3_384",s))(o||{}),n=(s=>(s.crc32="cid_crc32",s.md5="cid_md5",s.sha1="cid_sha1",s.sha256="cid_sha2-256",s.sha3_256="cid_sha3-256",s.sha3_384="cid_sha3-384",s))(n||{}),u=(s=>(s.crc32="crc32",s.md5="md5",s.sha1="sha1",s.sha256="sha2-256",s.sha3_256="sha3-256",s.sha3_384="sha3-384",s))(u||{});var t=class{_crc=void 0;update(a){return this._crc=x__default.default.buf(a,this._crc),this}digest(){console.log((this._crc>>>0).toString(16));let a=Buffer.alloc(4);return a.writeInt32BE(this._crc,0),a}};async function B({filePath:c,algorithms:a}){let h={"cid_sha2-256":{code:18,hasher:crypto.createHash("sha256")},cid_sha1:{code:17,hasher:crypto.createHash("sha1")},cid_md5:{code:213,hasher:crypto.createHash("md5")},"cid_sha3-256":{code:22,hasher:crypto.createHash("sha3-256")},"cid_sha3-384":{code:21,hasher:crypto.createHash("sha3-384")},cid_crc32:{code:306,hasher:new t}},i=a.map(s=>({hasher:h[s].hasher,code:h[s].code})),d=fs.createReadStream(c);for await(let s of d)for(let r of i)r.hasher.update(s);return await Promise.all(i.map(async({code:s,hasher:r})=>{let m=r.digest(),f=digest.create(s,m);return cid.CID.createV1(s,f).toString()}))}
exports.a = o;
exports.b = n;
exports.c = u;
exports.d = B;
//# sourceMappingURL=out.js.map
//# sourceMappingURL=chunk-A5PD5ID4.cjs.map
+1
View File
File diff suppressed because one or more lines are too long
-15
View File
@@ -1,15 +0,0 @@
'use strict';
var fs = require('fs');
var crypto = require('crypto');
var cid = require('multiformats/cid');
var digest = require('multiformats/hashes/digest');
var i=(a=>(a[a.sha256=18]="sha256",a[a.sha1=17]="sha1",a[a.md5=213]="md5",a[a.sha3_256=22]="sha3_256",a))(i||{}),o=(a=>(a.sha256="cid_sha2-256",a.sha1="cid_sha1",a.md5="cid_md5",a.sha3_256="cid_sha3-256",a))(o||{}),f=(a=>(a.sha256="sha2-256",a.sha1="sha1",a.md5="md5",a.sha3_256="sha3-256",a))(f||{});async function x({filePath:c,algorithms:m}){let r={"cid_sha2-256":{code:18,hasher:crypto.createHash("sha256")},cid_sha1:{code:17,hasher:crypto.createHash("sha1")},cid_md5:{code:213,hasher:crypto.createHash("md5")},"cid_sha3-256":{code:22,hasher:crypto.createHash("sha3-256")}},h=m.map(s=>({hasher:r[s].hasher,code:r[s].code})),a=fs.createReadStream(c);for await(let s of a)for(let t of h)t.hasher.update(s);return await Promise.all(h.map(async({code:s,hasher:t})=>{let d=t.digest(),n=digest.create(s,d);return cid.CID.createV1(s,n).toString()}))}
exports.a = i;
exports.b = o;
exports.c = f;
exports.d = x;
//# sourceMappingURL=out.js.map
//# sourceMappingURL=chunk-DL4KI2PZ.cjs.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["../src/lib/fileID/ShaComputeWorker.ts","../src/lib/MultiHashData.ts"],"names":["createReadStream","createHash","CID","create","CID_ALGORITHM_CODES","CID_ALGORITHM_NAMES","CID_ALGORITHM","computeCIDs","filePath","algorithms","hashFunctions","hashers","algo","stream","chunk","item","code","hasher","hashBuffer","digest"],"mappings":"AAAA,OAAS,oBAAAA,MAAwB,KACjC,OAAoB,cAAAC,MAAiB,SACrC,OAAS,OAAAC,MAAW,mBACpB,OAAS,UAAAC,MAAc,6BCShB,IAAKC,OACRA,IAAA,OAAS,IAAT,SACAA,IAAA,KAAO,IAAP,OACAA,IAAA,IAAM,KAAN,MACAA,IAAA,SAAW,IAAX,WAJQA,OAAA,IAQAC,OACRA,EAAA,OAAS,eACTA,EAAA,KAAO,WACPA,EAAA,IAAM,UACNA,EAAA,SAAW,eAJHA,OAAA,IAQAC,OACRA,EAAA,OAAS,WACTA,EAAA,KAAO,OACPA,EAAA,IAAM,MACNA,EAAA,SAAW,WAJHA,OAAA,IDVZ,eAAOC,EAAmC,CAAE,SAAAC,EAAU,WAAAC,CAAW,EAA+E,CAC5I,IAAMC,EACA,CACD,eAA6B,CAAE,QAAkC,OAAQT,EAAW,QAAQ,CAAE,EAC9F,SAA2B,CAAE,QAAgC,OAAQA,EAAW,MAAM,CAAE,EACxF,QAA0B,CAAE,SAA+B,OAAQA,EAAW,KAAK,CAAE,EACrF,eAA+B,CAAE,QAAoC,OAAOA,EAAW,UAAU,CAAE,CACxG,EAEMU,EAAUF,EAAW,IAAIG,IAAS,CACpC,OAAQF,EAAcE,CAAI,EAAE,OAC5B,KAAMF,EAAcE,CAAI,EAAE,IAC9B,EAAE,EAEIC,EAASb,EAAiBQ,CAAQ,EACxC,cAAiBM,KAASD,EACtB,QAAWE,KAAQJ,EACfI,EAAK,OAAO,OAAOD,CAAK,EAUhC,OANa,MAAM,QAAQ,IAAIH,EAAQ,IAAI,MAAO,CAAE,KAAAK,EAAM,OAAAC,CAAO,IAAM,CACnE,IAAMC,EAAaD,EAAO,OAAO,EAC3BE,EAAShB,EAAOa,EAAME,CAAU,EACtC,OAAOhB,EAAI,SAASc,EAAMG,CAAM,EAAE,SAAS,CAC/C,CAAC,CAAC,CAGN","sourcesContent":["import { createReadStream } from \"fs\";\nimport {BinaryLike, createHash} from 'crypto';\nimport { CID } from 'multiformats/cid';\nimport { create } from \"multiformats/hashes/digest\";\nimport {CID_ALGORITHM, CID_ALGORITHM_CODES, CID_ALGORITHM_NAMES} from \"../MultiHashData\";\n\nexport interface SimpleHash {\n update(data: BinaryLike),\n digest(): Buffer;\n}\n\n\n/**\n * Compute the CIDs of a file using specific algorithms\n * @param filePath The path to the file\n * @param algorithms Array of algorithms ('sha256', 'sha1')\n * @returns Array of CIDs (in the order of the algorithms)\n */\nexport default async function computeCIDs({ filePath, algorithms }: { filePath: string; algorithms: CID_ALGORITHM_NAMES[] }): Promise<string[]> {\n const hashFunctions: Record<string, { code: number, hasher: SimpleHash }>\n = {\n [CID_ALGORITHM_NAMES.sha256]: { code: CID_ALGORITHM_CODES.sha256, hasher: createHash('sha256') },\n [CID_ALGORITHM_NAMES.sha1]: { code: CID_ALGORITHM_CODES.sha1, hasher: createHash('sha1') },\n [CID_ALGORITHM_NAMES.md5]: { code: CID_ALGORITHM_CODES.md5, hasher: createHash('md5') },\n [CID_ALGORITHM_NAMES.sha3_256]: { code: CID_ALGORITHM_CODES.sha3_256, hasher:createHash('sha3-256') }\n };\n\n const hashers = algorithms.map(algo => ({\n hasher: hashFunctions[algo].hasher,\n code: hashFunctions[algo].code\n }));\n\n const stream = createReadStream(filePath);\n for await (const chunk of stream) {\n for (const item of hashers) {\n item.hasher.update(chunk);\n }\n }\n\n const cids = await Promise.all(hashers.map(async ({ code, hasher }) => {\n const hashBuffer = hasher.digest();\n const digest = create(code, hashBuffer);\n return CID.createV1(code, digest).toString();\n }));\n\n return cids;\n}\n","export interface MultiHashData {\n \"cid_sha2-256\"?: string;//0x12 sha2-256\n cid_sha1?: string; // 0x11 sha1\n cid_md5?: string; // 0xd5 md5\n \"cid_sha3-256\"?: string; // 0x16 sha3-256\n //cid_crc32?: string; //0x0132 CRC32 (SFV) TODO\n}\n\nexport interface ComputeInterface {\n computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>;\n}\n\nexport enum CID_ALGORITHM_CODES {\n sha256 = 0x12,\n sha1 = 0x11,\n md5 = 0xd5,\n sha3_256 = 0x16,\n //crc32 = 0x0132\n}\n\nexport enum CID_ALGORITHM_NAMES {\n sha256 = 'cid_sha2-256',\n sha1 = 'cid_sha1',\n md5 = 'cid_md5',\n sha3_256 = 'cid_sha3-256',\n //crc32 = 'cid_crc32'\n}\n\nexport enum CID_ALGORITHM {\n sha256 = 'sha2-256',\n sha1 = 'sha1',\n md5 = 'md5',\n sha3_256 = 'sha3-256',\n //crc32 = 'crc32'\n}"]}
+11
View File
@@ -0,0 +1,11 @@
import { createReadStream } from 'fs';
import { createHash } from 'crypto';
import { CID } from 'multiformats/cid';
import { create } from 'multiformats/hashes/digest';
import x from 'crc-32';
var o=(s=>(s[s.crc32=306]="crc32",s[s.md5=213]="md5",s[s.sha1=17]="sha1",s[s.sha256=18]="sha256",s[s.sha3_256=22]="sha3_256",s[s.sha3_384=21]="sha3_384",s))(o||{}),n=(s=>(s.crc32="cid_crc32",s.md5="cid_md5",s.sha1="cid_sha1",s.sha256="cid_sha2-256",s.sha3_256="cid_sha3-256",s.sha3_384="cid_sha3-384",s))(n||{}),u=(s=>(s.crc32="crc32",s.md5="md5",s.sha1="sha1",s.sha256="sha2-256",s.sha3_256="sha3-256",s.sha3_384="sha3-384",s))(u||{});var t=class{_crc=void 0;update(a){return this._crc=x.buf(a,this._crc),this}digest(){console.log((this._crc>>>0).toString(16));let a=Buffer.alloc(4);return a.writeInt32BE(this._crc,0),a}};async function B({filePath:c,algorithms:a}){let h={"cid_sha2-256":{code:18,hasher:createHash("sha256")},cid_sha1:{code:17,hasher:createHash("sha1")},cid_md5:{code:213,hasher:createHash("md5")},"cid_sha3-256":{code:22,hasher:createHash("sha3-256")},"cid_sha3-384":{code:21,hasher:createHash("sha3-384")},cid_crc32:{code:306,hasher:new t}},i=a.map(s=>({hasher:h[s].hasher,code:h[s].code})),d=createReadStream(c);for await(let s of d)for(let r of i)r.hasher.update(s);return await Promise.all(i.map(async({code:s,hasher:r})=>{let m=r.digest(),f=create(s,m);return CID.createV1(s,f).toString()}))}
export { o as a, n as b, u as c, B as d };
//# sourceMappingURL=out.js.map
//# sourceMappingURL=chunk-FGATABDV.js.map
+1
View File
File diff suppressed because one or more lines are too long
-10
View File
@@ -1,10 +0,0 @@
import { createReadStream } from 'fs';
import { createHash } from 'crypto';
import { CID } from 'multiformats/cid';
import { create } from 'multiformats/hashes/digest';
var i=(a=>(a[a.sha256=18]="sha256",a[a.sha1=17]="sha1",a[a.md5=213]="md5",a[a.sha3_256=22]="sha3_256",a))(i||{}),o=(a=>(a.sha256="cid_sha2-256",a.sha1="cid_sha1",a.md5="cid_md5",a.sha3_256="cid_sha3-256",a))(o||{}),f=(a=>(a.sha256="sha2-256",a.sha1="sha1",a.md5="md5",a.sha3_256="sha3-256",a))(f||{});async function x({filePath:c,algorithms:m}){let r={"cid_sha2-256":{code:18,hasher:createHash("sha256")},cid_sha1:{code:17,hasher:createHash("sha1")},cid_md5:{code:213,hasher:createHash("md5")},"cid_sha3-256":{code:22,hasher:createHash("sha3-256")}},h=m.map(s=>({hasher:r[s].hasher,code:r[s].code})),a=createReadStream(c);for await(let s of a)for(let t of h)t.hasher.update(s);return await Promise.all(h.map(async({code:s,hasher:t})=>{let d=t.digest(),n=create(s,d);return CID.createV1(s,n).toString()}))}
export { i as a, o as b, f as c, x as d };
//# sourceMappingURL=out.js.map
//# sourceMappingURL=chunk-VGBIRFOR.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["../src/lib/fileID/ShaComputeWorker.ts","../src/lib/MultiHashData.ts"],"names":["createReadStream","createHash","CID","create","CID_ALGORITHM_CODES","CID_ALGORITHM_NAMES","CID_ALGORITHM","computeCIDs","filePath","algorithms","hashFunctions","hashers","algo","stream","chunk","item","code","hasher","hashBuffer","digest"],"mappings":"AAAA,OAAS,oBAAAA,MAAwB,KACjC,OAAoB,cAAAC,MAAiB,SACrC,OAAS,OAAAC,MAAW,mBACpB,OAAS,UAAAC,MAAc,6BCShB,IAAKC,OACRA,IAAA,OAAS,IAAT,SACAA,IAAA,KAAO,IAAP,OACAA,IAAA,IAAM,KAAN,MACAA,IAAA,SAAW,IAAX,WAJQA,OAAA,IAQAC,OACRA,EAAA,OAAS,eACTA,EAAA,KAAO,WACPA,EAAA,IAAM,UACNA,EAAA,SAAW,eAJHA,OAAA,IAQAC,OACRA,EAAA,OAAS,WACTA,EAAA,KAAO,OACPA,EAAA,IAAM,MACNA,EAAA,SAAW,WAJHA,OAAA,IDVZ,eAAOC,EAAmC,CAAE,SAAAC,EAAU,WAAAC,CAAW,EAA+E,CAC5I,IAAMC,EACA,CACD,eAA6B,CAAE,QAAkC,OAAQT,EAAW,QAAQ,CAAE,EAC9F,SAA2B,CAAE,QAAgC,OAAQA,EAAW,MAAM,CAAE,EACxF,QAA0B,CAAE,SAA+B,OAAQA,EAAW,KAAK,CAAE,EACrF,eAA+B,CAAE,QAAoC,OAAOA,EAAW,UAAU,CAAE,CACxG,EAEMU,EAAUF,EAAW,IAAIG,IAAS,CACpC,OAAQF,EAAcE,CAAI,EAAE,OAC5B,KAAMF,EAAcE,CAAI,EAAE,IAC9B,EAAE,EAEIC,EAASb,EAAiBQ,CAAQ,EACxC,cAAiBM,KAASD,EACtB,QAAWE,KAAQJ,EACfI,EAAK,OAAO,OAAOD,CAAK,EAUhC,OANa,MAAM,QAAQ,IAAIH,EAAQ,IAAI,MAAO,CAAE,KAAAK,EAAM,OAAAC,CAAO,IAAM,CACnE,IAAMC,EAAaD,EAAO,OAAO,EAC3BE,EAAShB,EAAOa,EAAME,CAAU,EACtC,OAAOhB,EAAI,SAASc,EAAMG,CAAM,EAAE,SAAS,CAC/C,CAAC,CAAC,CAGN","sourcesContent":["import { createReadStream } from \"fs\";\nimport {BinaryLike, createHash} from 'crypto';\nimport { CID } from 'multiformats/cid';\nimport { create } from \"multiformats/hashes/digest\";\nimport {CID_ALGORITHM, CID_ALGORITHM_CODES, CID_ALGORITHM_NAMES} from \"../MultiHashData\";\n\nexport interface SimpleHash {\n update(data: BinaryLike),\n digest(): Buffer;\n}\n\n\n/**\n * Compute the CIDs of a file using specific algorithms\n * @param filePath The path to the file\n * @param algorithms Array of algorithms ('sha256', 'sha1')\n * @returns Array of CIDs (in the order of the algorithms)\n */\nexport default async function computeCIDs({ filePath, algorithms }: { filePath: string; algorithms: CID_ALGORITHM_NAMES[] }): Promise<string[]> {\n const hashFunctions: Record<string, { code: number, hasher: SimpleHash }>\n = {\n [CID_ALGORITHM_NAMES.sha256]: { code: CID_ALGORITHM_CODES.sha256, hasher: createHash('sha256') },\n [CID_ALGORITHM_NAMES.sha1]: { code: CID_ALGORITHM_CODES.sha1, hasher: createHash('sha1') },\n [CID_ALGORITHM_NAMES.md5]: { code: CID_ALGORITHM_CODES.md5, hasher: createHash('md5') },\n [CID_ALGORITHM_NAMES.sha3_256]: { code: CID_ALGORITHM_CODES.sha3_256, hasher:createHash('sha3-256') }\n };\n\n const hashers = algorithms.map(algo => ({\n hasher: hashFunctions[algo].hasher,\n code: hashFunctions[algo].code\n }));\n\n const stream = createReadStream(filePath);\n for await (const chunk of stream) {\n for (const item of hashers) {\n item.hasher.update(chunk);\n }\n }\n\n const cids = await Promise.all(hashers.map(async ({ code, hasher }) => {\n const hashBuffer = hasher.digest();\n const digest = create(code, hashBuffer);\n return CID.createV1(code, digest).toString();\n }));\n\n return cids;\n}\n","export interface MultiHashData {\n \"cid_sha2-256\"?: string;//0x12 sha2-256\n cid_sha1?: string; // 0x11 sha1\n cid_md5?: string; // 0xd5 md5\n \"cid_sha3-256\"?: string; // 0x16 sha3-256\n //cid_crc32?: string; //0x0132 CRC32 (SFV) TODO\n}\n\nexport interface ComputeInterface {\n computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>;\n}\n\nexport enum CID_ALGORITHM_CODES {\n sha256 = 0x12,\n sha1 = 0x11,\n md5 = 0xd5,\n sha3_256 = 0x16,\n //crc32 = 0x0132\n}\n\nexport enum CID_ALGORITHM_NAMES {\n sha256 = 'cid_sha2-256',\n sha1 = 'cid_sha1',\n md5 = 'cid_md5',\n sha3_256 = 'cid_sha3-256',\n //crc32 = 'cid_crc32'\n}\n\nexport enum CID_ALGORITHM {\n sha256 = 'sha2-256',\n sha1 = 'sha1',\n md5 = 'md5',\n sha3_256 = 'sha3-256',\n //crc32 = 'crc32'\n}"]}
+16 -16
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+6 -7
View File
@@ -1,9 +1,8 @@
import { C as ComputeInterface, a as CID_ALGORITHM_NAMES, M as MultiHashData } from './ShaComputeWorker-DWOF-qaH.cjs'; import { C as ComputeInterface, a as CID_ALGORITHM_NAMES, M as MultiHashData } from './ShaComputeWorker-DxWHpwX4.cjs';
export { c as CID_ALGORITHM, b as CID_ALGORITHM_CODES, S as SimpleHash } from './ShaComputeWorker-DWOF-qaH.cjs'; export { c as CID_ALGORITHM, b as CID_ALGORITHM_CODES, S as SimpleHash } from './ShaComputeWorker-DxWHpwX4.cjs';
import * as PQueue from 'p-queue'; import * as PQueue from 'p-queue';
import PQueue__default from 'p-queue'; import PQueue__default from 'p-queue';
import * as p_queue_dist_priority_queue_js from 'p-queue/dist/priority-queue.js'; import * as p_queue_dist_priority_queue_js from 'p-queue/dist/priority-queue.js';
import 'crypto';
declare class HashComputer implements ComputeInterface { declare class HashComputer implements ComputeInterface {
private targetHash; private targetHash;
@@ -19,7 +18,6 @@ interface IndexLine extends Partial<Record<CID_ALGORITHM_NAMES, string>> {
} }
declare const INDEX_HEADERS: string[]; declare const INDEX_HEADERS: string[];
declare class HashIndexManager { declare class HashIndexManager {
private filePath;
private targetHash; private targetHash;
private cache; private cache;
private intervalId; private intervalId;
@@ -29,18 +27,19 @@ declare class HashIndexManager {
private indexOpsInProgress; private indexOpsInProgress;
private hasChanged; private hasChanged;
private initialLoad; private initialLoad;
private filePaths;
constructor(filePath: string, targetHash?: CID_ALGORITHM_NAMES[]); constructor(filePath: string, targetHash?: CID_ALGORITHM_NAMES[]);
getCache(): Map<string, IndexLine>; getCache(): Map<string, IndexLine>;
/** /**
* After init consseutively calls to this method will not reload the index * After init consseutively calls to this method will not reload the index
* @param autosave * @param autosave
*/ */
init(autosave?: boolean): Promise<any>; init(autosave?: boolean): Promise<void>;
checkCSVHeaders(csvContent: string): boolean; private checkCSVHeaders;
start(): void; start(): void;
stopAutoSave(): void; stopAutoSave(): void;
private startAutoSave; private startAutoSave;
loadIndex(): Promise<IndexLine[]>; loadIndex(hash: CID_ALGORITHM_NAMES): Promise<IndexLine[]>;
private loadIndexFromCache; private loadIndexFromCache;
private readCsv; private readCsv;
private saveCacheToFile; private saveCacheToFile;
+6 -7
View File
@@ -1,9 +1,8 @@
import { C as ComputeInterface, a as CID_ALGORITHM_NAMES, M as MultiHashData } from './ShaComputeWorker-DWOF-qaH.js'; import { C as ComputeInterface, a as CID_ALGORITHM_NAMES, M as MultiHashData } from './ShaComputeWorker-DxWHpwX4.js';
export { c as CID_ALGORITHM, b as CID_ALGORITHM_CODES, S as SimpleHash } from './ShaComputeWorker-DWOF-qaH.js'; export { c as CID_ALGORITHM, b as CID_ALGORITHM_CODES, S as SimpleHash } from './ShaComputeWorker-DxWHpwX4.js';
import * as PQueue from 'p-queue'; import * as PQueue from 'p-queue';
import PQueue__default from 'p-queue'; import PQueue__default from 'p-queue';
import * as p_queue_dist_priority_queue_js from 'p-queue/dist/priority-queue.js'; import * as p_queue_dist_priority_queue_js from 'p-queue/dist/priority-queue.js';
import 'crypto';
declare class HashComputer implements ComputeInterface { declare class HashComputer implements ComputeInterface {
private targetHash; private targetHash;
@@ -19,7 +18,6 @@ interface IndexLine extends Partial<Record<CID_ALGORITHM_NAMES, string>> {
} }
declare const INDEX_HEADERS: string[]; declare const INDEX_HEADERS: string[];
declare class HashIndexManager { declare class HashIndexManager {
private filePath;
private targetHash; private targetHash;
private cache; private cache;
private intervalId; private intervalId;
@@ -29,18 +27,19 @@ declare class HashIndexManager {
private indexOpsInProgress; private indexOpsInProgress;
private hasChanged; private hasChanged;
private initialLoad; private initialLoad;
private filePaths;
constructor(filePath: string, targetHash?: CID_ALGORITHM_NAMES[]); constructor(filePath: string, targetHash?: CID_ALGORITHM_NAMES[]);
getCache(): Map<string, IndexLine>; getCache(): Map<string, IndexLine>;
/** /**
* After init consseutively calls to this method will not reload the index * After init consseutively calls to this method will not reload the index
* @param autosave * @param autosave
*/ */
init(autosave?: boolean): Promise<any>; init(autosave?: boolean): Promise<void>;
checkCSVHeaders(csvContent: string): boolean; private checkCSVHeaders;
start(): void; start(): void;
stopAutoSave(): void; stopAutoSave(): void;
private startAutoSave; private startAutoSave;
loadIndex(): Promise<IndexLine[]>; loadIndex(hash: CID_ALGORITHM_NAMES): Promise<IndexLine[]>;
private loadIndexFromCache; private loadIndexFromCache;
private readCsv; private readCsv;
private saveCacheToFile; private saveCacheToFile;
+6 -6
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,9 +1,9 @@
'use strict'; 'use strict';
var chunkDL4KI2PZ_cjs = require('./chunk-DL4KI2PZ.cjs'); var chunkA5PD5ID4_cjs = require('./chunk-A5PD5ID4.cjs');
module.exports = chunkDL4KI2PZ_cjs.d; module.exports = chunkA5PD5ID4_cjs.d;
//# sourceMappingURL=out.js.map //# sourceMappingURL=out.js.map
//# sourceMappingURL=worker.cjs.map //# sourceMappingURL=worker.cjs.map
+1 -2
View File
@@ -1,2 +1 @@
import 'crypto'; export { S as SimpleHash, d as default } from './ShaComputeWorker-DxWHpwX4.cjs';
export { S as SimpleHash, d as default } from './ShaComputeWorker-DWOF-qaH.cjs';
+1 -2
View File
@@ -1,2 +1 @@
import 'crypto'; export { S as SimpleHash, d as default } from './ShaComputeWorker-DxWHpwX4.js';
export { S as SimpleHash, d as default } from './ShaComputeWorker-DWOF-qaH.js';
+1 -1
View File
@@ -1,3 +1,3 @@
export { d as default } from './chunk-VGBIRFOR.js'; export { d as default } from './chunk-FGATABDV.js';
//# sourceMappingURL=out.js.map //# sourceMappingURL=out.js.map
//# sourceMappingURL=worker.js.map //# sourceMappingURL=worker.js.map
+1
View File
@@ -41,6 +41,7 @@
"packageManager": "[email protected]", "packageManager": "[email protected]",
"dependencies": { "dependencies": {
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"crc-32": "^1.2.2",
"csv-parse": "^5.5.5", "csv-parse": "^5.5.5",
"csv-stringify": "^6.4.6", "csv-stringify": "^6.4.6",
"multiformats": "^13.1.0", "multiformats": "^13.1.0",
+2 -2
View File
@@ -9,8 +9,8 @@ export class ComputeHashIndexCache implements ComputeInterface {
hashComputer: HashComputer; hashComputer: HashComputer;
constructor(indexFilePath: string,private targetHash: CID_ALGORITHM_NAMES[] = [CID_ALGORITHM_NAMES.sha1, CID_ALGORITHM_NAMES.sha256],workerPath?:string) { constructor(indexFilePath: string,private targetHash: CID_ALGORITHM_NAMES[] = [CID_ALGORITHM_NAMES.sha1, CID_ALGORITHM_NAMES.sha256],workerPath?:string) {
this.hashComputer = new HashComputer(this.targetHash,workerPath); this.hashComputer = new HashComputer(targetHash,workerPath);
this.hashIndexManager = new HashIndexManager(indexFilePath); this.hashIndexManager = new HashIndexManager(indexFilePath,targetHash);
} }
async computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void> { async computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void> {
+50 -21
View File
@@ -12,6 +12,7 @@ interface IndexLine extends Partial<Record<CID_ALGORITHM_NAMES, string>> {
size: string; size: string;
mtime: string; mtime: string;
} }
export const INDEX_HEADERS = ['path', 'size', 'mtime']; export const INDEX_HEADERS = ['path', 'size', 'mtime'];
export class HashIndexManager { export class HashIndexManager {
@@ -22,11 +23,16 @@ export class HashIndexManager {
private lastCacheFile: IndexLine[]; //state of the file last time it was read private lastCacheFile: IndexLine[]; //state of the file last time it was read
private indexOpsInProgress: boolean = false; private indexOpsInProgress: boolean = false;
private hasChanged: boolean = false; private hasChanged: boolean = false;
private initialLoad; private initialLoad: Promise<void>;
private filePaths: { [key in CID_ALGORITHM_NAMES]?: string } = {};
constructor(private filePath: string,private targetHash:CID_ALGORITHM_NAMES[]= [CID_ALGORITHM_NAMES.sha1,CID_ALGORITHM_NAMES.sha256]) { constructor(filePath: string, private targetHash: CID_ALGORITHM_NAMES[] = [CID_ALGORITHM_NAMES.sha1, CID_ALGORITHM_NAMES.sha256]) {
if (!filePath) { filePath = filePath.replace(".csv", "");
throw new Error('Invalid index file path'); for (const hash of this.targetHash) {
this.filePaths[hash] = `${filePath}-${hash}.csv`;
if (!this.filePaths[hash]) {
throw new Error(`Invalid index file path for ${hash}`);
}
} }
} }
@@ -38,14 +44,16 @@ export class HashIndexManager {
* After init consseutively calls to this method will not reload the index * After init consseutively calls to this method will not reload the index
* @param autosave * @param autosave
*/ */
async init(autosave = true) { public async init(autosave = true) {
if (!this.initialLoad) { if (!this.initialLoad) {
this.initialLoad = new Promise<void>(async (resolve, reject) => { this.initialLoad = new Promise<void>(async (resolve, reject) => {
try { try {
if (!this.checkCSVHeaders(this.filePath)) { for (const hash of this.targetHash) {
throw new Error('Invalid index file headers'); if (!this.checkCSVHeaders(this.filePaths[hash], hash)) {
throw new Error(`Invalid index file headers for ${hash}`);
}
await this.loadIndex(hash);
} }
await this.loadIndex();
if (autosave) { if (autosave) {
this.start(); this.start();
} }
@@ -59,7 +67,7 @@ export class HashIndexManager {
} }
// Function to check CSV headers // Function to check CSV headers
checkCSVHeaders (csvContent: string): boolean { private checkCSVHeaders(csvContent: string, hash: CID_ALGORITHM_NAMES): boolean {
const records = parseSync(csvContent, { const records = parseSync(csvContent, {
bom: true, bom: true,
columns: true, columns: true,
@@ -76,7 +84,7 @@ export class HashIndexManager {
// Define required headers // Define required headers
//from the IndexLine interface //from the IndexLine interface
const requiredHeaders = ['path', 'size', 'mtime', ...this.targetHash]; const requiredHeaders = [...INDEX_HEADERS, hash];
// Check if all required headers are present // Check if all required headers are present
return requiredHeaders.every(header => headers.includes(header)); return requiredHeaders.every(header => headers.includes(header));
@@ -98,15 +106,21 @@ export class HashIndexManager {
this.intervalId = setInterval(() => this.saveCacheToFile(), time); this.intervalId = setInterval(() => this.saveCacheToFile(), time);
} }
public async loadIndex(): Promise<IndexLine[]> { public async loadIndex(hash: CID_ALGORITHM_NAMES): Promise<IndexLine[]> {
if (await existsAsync(this.filePath)) { if (await existsAsync(this.filePaths[hash])) {
// check the file size and if it did not change, do not read the file // check the file size and if it did not change, do not read the file
const stats = await fs.stat(this.filePath); const stats = await fs.stat(this.filePaths[hash]);
if (this.lastIndexFileSize !== stats.size) { if (this.lastIndexFileSize !== stats.size) {
// Read existing file content and parse it // Read existing file content and parse it
const records: IndexLine[] = await this.readCsv(); const records: IndexLine[] = await this.readCsv(hash);
for (const record of records) { for (const record of records) {
let indexLine = this.cache.get(record.path);
if (!indexLine) {
this.cache.set(record.path, record); this.cache.set(record.path, record);
} else {
//update the cache with the latest data
indexLine[hash] = record[hash];
}
} }
this.lastIndexFileSize = stats.size; this.lastIndexFileSize = stats.size;
this.lastCacheFile = records; this.lastCacheFile = records;
@@ -122,8 +136,8 @@ export class HashIndexManager {
return Array.from(this.cache.values()); return Array.from(this.cache.values());
} }
private async readCsv(): Promise<IndexLine[]> { private async readCsv(hash: CID_ALGORITHM_NAMES): Promise<IndexLine[]> {
if (!(await existsAsync(this.filePath))) { if (!(await existsAsync(this.filePaths[hash]))) {
return []; return [];
} }
const start = performance.now(); const start = performance.now();
@@ -136,13 +150,13 @@ export class HashIndexManager {
const records: IndexLine[] = []; const records: IndexLine[] = [];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
createReadStream(this.filePath) createReadStream(this.filePaths[hash])
.pipe(parser) .pipe(parser)
.on('data', (record) => { .on('data', (record) => {
records.push(record); records.push(record);
}).on('end', () => { }).on('end', () => {
resolve(records); resolve(records);
console.log(`Index read time ${performance.now() - start}ms`); console.log(`Index read ${hash} time ${performance.now() - start}ms`);
}).on('error', (err) => { }).on('error', (err) => {
reject(err); reject(err);
}); });
@@ -156,8 +170,9 @@ export class HashIndexManager {
this.hasChanged = false; this.hasChanged = false;
this.indexOpsInProgress = true; this.indexOpsInProgress = true;
const start = performance.now(); const start = performance.now();
let existingRows: IndexLine[] = await this.loadIndex();
for (const hash of this.targetHash) {
let existingRows: IndexLine[] = await this.loadIndex(hash);
if (this.cache.size !== 0) { if (this.cache.size !== 0) {
const cacheRows: IndexLine[] = this.loadIndexFromCache(); const cacheRows: IndexLine[] = this.loadIndexFromCache();
// Filter out cacheRows that are already in the file // Filter out cacheRows that are already in the file
@@ -171,12 +186,13 @@ export class HashIndexManager {
{key: 'path', header: 'path'}, {key: 'path', header: 'path'},
{key: 'size', header: 'size'}, {key: 'size', header: 'size'},
{key: 'mtime', header: 'mtime'}, {key: 'mtime', header: 'mtime'},
...this.targetHash.map(hash => ({key: hash, header: hash})), {key: hash, header: hash},
], ],
}); });
// Append new cacheRows to the file // Append new cacheRows to the file
await fs.appendFile(this.filePath, csvString); await fs.appendFile(this.filePaths[hash], csvString);
}
} }
} }
const totalTime = performance.now() - start; const totalTime = performance.now() - start;
@@ -219,10 +235,23 @@ export class HashIndexManager {
if (!filePath || !fileSize || !mtime || !hashs) { if (!filePath || !fileSize || !mtime || !hashs) {
throw new Error('Invalid parameters'); throw new Error('Invalid parameters');
} }
for (const hash of this.targetHash) {
if (!hashs[hash]) {
throw new Error(`Missing hash ${hash}`);
}
}
const size = fileSize + ""; const size = fileSize + "";
const baseName = path.basename(filePath); const baseName = path.basename(filePath);
let indexLine = this.cache.get(baseName);
if (!indexLine) {
const data = {path: baseName, size: size, mtime: mtime, ...hashs}; const data = {path: baseName, size: size, mtime: mtime, ...hashs};
this.cache.set(baseName, data); this.cache.set(baseName, data);
} else {
//update the cache with the latest data
for (const hash of this.targetHash) {
indexLine[hash] = hashs[hash];
}
}
this.hasChanged = true; this.hasChanged = true;
} }
+17 -10
View File
@@ -3,33 +3,40 @@ export interface MultiHashData {
cid_sha1?: string; // 0x11 sha1 cid_sha1?: string; // 0x11 sha1
cid_md5?: string; // 0xd5 md5 cid_md5?: string; // 0xd5 md5
"cid_sha3-256"?: string; // 0x16 sha3-256 "cid_sha3-256"?: string; // 0x16 sha3-256
//cid_crc32?: string; //0x0132 CRC32 (SFV) TODO cid_crc32?: string; //0x0132 CRC32 (SFV)
} }
export interface ComputeInterface { export interface ComputeInterface {
computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>; computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void>;
} }
/**
* according to
* https://ipfs.io/ipfs/QmXec1jjwzxWJoNbxQF5KffL8q6hFXm9QwUGaa3wKGk6dT/#title=Multicodecs&src=https://raw.githubusercontent.com/multiformats/multicodec/master/table.csv
*/
export enum CID_ALGORITHM_CODES { export enum CID_ALGORITHM_CODES {
sha256 = 0x12, crc32 = 0x0132,
sha1 = 0x11,
md5 = 0xd5, md5 = 0xd5,
sha1 = 0x11,
sha256 = 0x12,
sha3_256 = 0x16, sha3_256 = 0x16,
//crc32 = 0x0132 sha3_384 = 0x15,
} }
export enum CID_ALGORITHM_NAMES { export enum CID_ALGORITHM_NAMES {
sha256 = 'cid_sha2-256', crc32 = 'cid_crc32',
sha1 = 'cid_sha1',
md5 = 'cid_md5', md5 = 'cid_md5',
sha1 = 'cid_sha1',
sha256 = 'cid_sha2-256',
sha3_256 = 'cid_sha3-256', sha3_256 = 'cid_sha3-256',
//crc32 = 'cid_crc32' sha3_384 = 'cid_sha3-384',
} }
export enum CID_ALGORITHM { export enum CID_ALGORITHM {
sha256 = 'sha2-256', crc32 = 'crc32',
sha1 = 'sha1',
md5 = 'md5', md5 = 'md5',
sha1 = 'sha1',
sha256 = 'sha2-256',
sha3_256 = 'sha3-256', sha3_256 = 'sha3-256',
//crc32 = 'crc32' sha3_384 = 'sha3-384',
} }
+31 -6
View File
@@ -1,14 +1,33 @@
import {createReadStream} from "fs"; import {createReadStream} from "fs";
import {BinaryLike, createHash} from 'crypto'; import {createHash} from 'crypto';
import {CID} from 'multiformats/cid'; import {CID} from 'multiformats/cid';
import {create} from "multiformats/hashes/digest"; import {create} from "multiformats/hashes/digest";
import {CID_ALGORITHM, CID_ALGORITHM_CODES, CID_ALGORITHM_NAMES} from "../MultiHashData"; import crc32 from 'crc-32';
import {CID_ALGORITHM_CODES, CID_ALGORITHM_NAMES} from "../MultiHashData";
export interface SimpleHash { export interface SimpleHash {
update(data: BinaryLike), update(data: Buffer),
digest(): Buffer; digest(): Buffer;
} }
class Crc32Hash implements SimpleHash {
private _crc: number = undefined;
update(data: Buffer): Crc32Hash {
// Update the CRC-32 checksum with the new chunk of data
this._crc = crc32.buf(data, this._crc);
return this;
}
digest(): Buffer {
console.log((this._crc>>>0).toString(16)) ;
const buffer = Buffer.alloc(4); // Create a buffer of 4 bytes (32 bits)
buffer.writeInt32BE(this._crc, 0); // Write the unsigned integer to the buffer in big-endian format
return buffer;
}
}
/** /**
* Compute the CIDs of a file using specific algorithms * Compute the CIDs of a file using specific algorithms
@@ -16,13 +35,19 @@ export interface SimpleHash {
* @param algorithms Array of algorithms ('sha256', 'sha1') * @param algorithms Array of algorithms ('sha256', 'sha1')
* @returns Array of CIDs (in the order of the algorithms) * @returns Array of CIDs (in the order of the algorithms)
*/ */
export default async function computeCIDs({ filePath, algorithms }: { filePath: string; algorithms: CID_ALGORITHM_NAMES[] }): Promise<string[]> { export default async function computeCIDs({filePath, algorithms}: {
filePath: string;
algorithms: CID_ALGORITHM_NAMES[]
}): Promise<string[]> {
const hashFunctions: Record<string, { code: number, hasher: SimpleHash }> const hashFunctions: Record<string, { code: number, hasher: SimpleHash }>
= { = {
[CID_ALGORITHM_NAMES.sha256]: {code: CID_ALGORITHM_CODES.sha256, hasher: createHash('sha256')}, [CID_ALGORITHM_NAMES.sha256]: {code: CID_ALGORITHM_CODES.sha256, hasher: createHash('sha256')},
[CID_ALGORITHM_NAMES.sha1]: {code: CID_ALGORITHM_CODES.sha1, hasher: createHash('sha1')}, [CID_ALGORITHM_NAMES.sha1]: {code: CID_ALGORITHM_CODES.sha1, hasher: createHash('sha1')},
[CID_ALGORITHM_NAMES.md5]: {code: CID_ALGORITHM_CODES.md5, hasher: createHash('md5')}, [CID_ALGORITHM_NAMES.md5]: {code: CID_ALGORITHM_CODES.md5, hasher: createHash('md5')},
[CID_ALGORITHM_NAMES.sha3_256]: { code: CID_ALGORITHM_CODES.sha3_256, hasher:createHash('sha3-256') } [CID_ALGORITHM_NAMES.sha3_256]: {code: CID_ALGORITHM_CODES.sha3_256, hasher: createHash('sha3-256')},
[CID_ALGORITHM_NAMES.sha3_384]: {code: CID_ALGORITHM_CODES.sha3_384, hasher: createHash('sha3-384')},
[CID_ALGORITHM_NAMES.crc32]: {code: CID_ALGORITHM_CODES.crc32, hasher: new Crc32Hash()}
}; };
const hashers = algorithms.map(algo => ({ const hashers = algorithms.map(algo => ({
@@ -33,7 +58,7 @@ export default async function computeCIDs({ filePath, algorithms }: { filePath:
const stream = createReadStream(filePath); const stream = createReadStream(filePath);
for await (const chunk of stream) { for await (const chunk of stream) {
for (const item of hashers) { for (const item of hashers) {
item.hasher.update(chunk); item.hasher.update(chunk as Buffer);
} }
} }
+23 -8
View File
@@ -1,27 +1,42 @@
import {HashComputer} from "../lib"; import {CID_ALGORITHM_NAMES, HashComputer} from "../lib";
import {CID_ALGORITHM_NAMES} from "../lib";
import {describe, it, expect} from 'vitest'; import {describe, expect, it} from 'vitest';
import * as process from "process"; import * as process from "process";
process.env.WORKER_URL = "./dist/worker.js"; process.env.WORKER_URL = "./dist/worker.js";
/**
* /!\ WARNING /!\
* Remember to build the worker each time you change the worker code.
*/
describe('add', () => { describe('add', () => {
it('meta data compute', async () => { it('meta data compute', async () => {
let hashComputer = new HashComputer([ let hashComputer = new HashComputer([
CID_ALGORITHM_NAMES.sha1, CID_ALGORITHM_NAMES.sha1,
CID_ALGORITHM_NAMES.sha256, CID_ALGORITHM_NAMES.sha256,
CID_ALGORITHM_NAMES.md5, CID_ALGORITHM_NAMES.md5,
CID_ALGORITHM_NAMES.sha3_256 CID_ALGORITHM_NAMES.sha3_256,
CID_ALGORITHM_NAMES.crc32,
CID_ALGORITHM_NAMES.sha3_384
]); ]);
let metadata = {}; let metadata = {};
await hashComputer.computeMissingHash('./src/tests/test.txt', metadata); await hashComputer.computeMissingHash('./src/tests/test.txt', metadata);
console.log(metadata); console.log(metadata);
/**
* test.txt CF20B62A (CRC32)
* 26f1157f4349a6fb5d207ac5f5995140 *test.txt (MD5)
* bb242b7b821074f4b9eb9a94d439ab668705aac4 ?SHA1*test.txt
* 2aa7a80d2fd1eb96d31afc7cdda9211a97524202c63f04151d6163fba35061a0 ?SHA256*test.txt
* 865a1ea4977b25e04b8ea84af93b21f1a031cb48359f3805089cdae1d89842b9a3faf87654989dcae418144a8bbb378c ?SHA3-384*test.txt
*/
expect(metadata).toEqual({ expect(metadata).toEqual({
cid_sha1: 'baeircff3eqvxxaqqot2lt242stkdtk3gq4c2vra', "cid_crc32": "bagzafmqcathsbnrk",
'cid_sha2-256': 'baejbeibku6ua2l6r5olnggx4pto2sii2s5jeeawgh4cbkhlbmp52gudbua', "cid_sha1": 'baeircff3eqvxxaqqot2lt242stkdtk3gq4c2vra',
cid_md5: 'bahkqdvibcatpcfl7ine2n625eb5ml5mzkfaa', "cid_sha2-256": 'baejbeibku6ua2l6r5olnggx4pto2sii2s5jeeawgh4cbkhlbmp52gudbua',
'cid_sha3-256': 'baelbmidner7x3dd7t2kldh6wiq4w6lsye7qrwo6uoqot2t52zkhqk56fnq' "cid_md5": 'bahkqdvibcatpcfl7ine2n625eb5ml5mzkfaa',
"cid_sha3-256": 'baelbmidner7x3dd7t2kldh6wiq4w6lsye7qrwo6uoqot2t52zkhqk56fnq',
"cid_sha3-384": 'baekrkmeglipkjf33exqexdvijl4twipruay4wsbvt44akce43lq5rgccxgr7v6dwksmj3sxedakevc53g6ga'
}); });
}); });
}); });
+10
View File
@@ -417,6 +417,7 @@ __metadata:
dependencies: dependencies:
"@types/node": "npm:^20.12.2" "@types/node": "npm:^20.12.2"
chokidar: "npm:^3.6.0" chokidar: "npm:^3.6.0"
crc-32: "npm:^1.2.2"
csv-parse: "npm:^5.5.5" csv-parse: "npm:^5.5.5"
csv-stringify: "npm:^6.4.6" csv-stringify: "npm:^6.4.6"
multiformats: "npm:^13.1.0" multiformats: "npm:^13.1.0"
@@ -962,6 +963,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"crc-32@npm:^1.2.2":
version: 1.2.2
resolution: "crc-32@npm:1.2.2"
bin:
crc32: bin/crc32.njs
checksum: 10c0/11dcf4a2e77ee793835d49f2c028838eae58b44f50d1ff08394a610bfd817523f105d6ae4d9b5bef0aad45510f633eb23c903e9902e4409bed1ce70cb82b9bf0
languageName: node
linkType: hard
"create-require@npm:^1.1.0": "create-require@npm:^1.1.0":
version: 1.1.1 version: 1.1.1
resolution: "create-require@npm:1.1.1" resolution: "create-require@npm:1.1.1"