Skip to content

Commit

Permalink
feat(canyon-backend): add protobuf compress
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangtao25 committed Oct 16, 2024
1 parent cb8b0b3 commit 55a06a6
Show file tree
Hide file tree
Showing 5 changed files with 10,411 additions and 6 deletions.
27 changes: 24 additions & 3 deletions packages/canyon-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"start": "nest start",
"dev-backend": "nest start --watch",
"preinstall": "prisma generate && nest build",
"format": "prettier --write ."
"format": "prettier --write .",
"do-test": "jest"
},
"dependencies": {
"@mongodb-js/zstd": "^1.2.2",
Expand All @@ -23,6 +24,7 @@
"@nestjs/schedule": "^4.1.1",
"@nestjs/serve-static": "^4.0.2",
"@nestjs/typeorm": "^10.0.2",
"@prisma/client": "5.16.1",
"axios": "^1.7.7",
"body-parser": "^1.20.3",
"canyon-data": "^0.1.1-alpha.11",
Expand All @@ -41,7 +43,7 @@
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"prisma": "5.16.1",
"@prisma/client": "5.16.1",
"protobufjs": "^7.4.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"sqlite3": "^5.1.7",
Expand All @@ -55,6 +57,7 @@
"@types/express": "^5.0.0",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-lib-source-maps": "^4.0.4",
"@types/jest": "^29.5.13",
"@types/lodash": "^4.17.10",
"@types/node": "^22.7.5",
"@types/test-exclude": "^6.0.2",
Expand All @@ -64,11 +67,29 @@
"eslint": "^9.12.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"jest": "^29.7.0",
"prettier": "^3.3.3",
"source-map-support": "^0.5.21",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.6.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"preset": "ts-jest",
"clearMocks": true,
"collectCoverage": true,
"coverageDirectory": "coverage",
"coverageProvider": "v8",
"rootDir": "test",
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/$1"
}
}
}
}
42 changes: 42 additions & 0 deletions packages/canyon-backend/proto/coverage.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
syntax = "proto3";

message CoverageData {
map<string, FileCoverageData> data = 1;
}

message FileCoverageData {
string path = 1;
map<string, Range> statementMap = 2;
map<string, FunctionMapping> fnMap = 3;
map<string, BranchMapping> branchMap = 4;
map<string, int32> s = 5;
map<string, int32> f = 6;
map<string, RepeatedInt32> b = 7;
}

message RepeatedInt32 {
repeated int32 data = 1;
}

message Range {
Location start = 1;
Location end = 2;
}
message Location {
int32 line = 1;
int32 column = 2;
}

message FunctionMapping {
string name = 1;
Range loc = 2;
Range decl = 3;
int32 line = 4;
}

message BranchMapping {
Range loc = 1;
string type = 2;
int32 line = 3;
repeated Range locations = 4;
}
111 changes: 110 additions & 1 deletion packages/canyon-backend/src/utils/compress.ts
Original file line number Diff line number Diff line change
@@ -1 +1,110 @@
// 学习upload里的步骤
import { compress, decompress } from "@mongodb-js/zstd";
import {CoverageMapData} from "istanbul-lib-coverage";
import * as protobuf from "protobufjs";

function jianchaJiaZhuanhuan(coverageData) {
// @ts-ignore
return Object.fromEntries(Object.entries(coverageData).map(([key, value]) => [
key,
{
// @ts-ignore
...value,
// @ts-ignore
b: Object.fromEntries(Object.entries(value.b).map(([k, v]) => [k, { data: v }]))
}
]));
}

function fan_jianchaJiaZhuanhuan(fan_coverageData) {
// console.log(fan_coverageData,'fan_coverageData')
// @ts-ignore
return Object.fromEntries(Object.entries(fan_coverageData).map(([key, value]) => [
key,
{
// @ts-ignore
...value,
// @ts-ignore
b: Object.fromEntries(Object.entries(value.b).map(([k, v]) => [k, v.data]))
}
]));
}

export async function compressCoverageData(coverageData: CoverageMapData) {
const time = new Date().getTime()
return new Promise((resolve, reject) => {
// 获取根目录下的coverage.proto文件
protobuf.load("proto/coverage.proto", function(err, root) {
if (err)
throw err;

// Obtain a message type
const AwesomeMessage = root.lookupType("CoverageData");

// Exemplary payload
const payload = {
data: jianchaJiaZhuanhuan(coverageData)
}

// Verify the payload if necessary (i.e. when possibly incomplete or invalid)
const errMsg = AwesomeMessage.verify(payload);
if (errMsg)
throw Error(errMsg);

// Create a new message
const message = AwesomeMessage.create(payload); // or use .fromObject if conversion is necessary

// Encode a message to an Uint8Array (browser) or Buffer (node)
const buffer2 = AwesomeMessage.encode(message).finish();
// ... do something with buffer

// resolve(buffer);

// console.log(buffer2)
// @ts-ignore
// const res = compress(buffer2);
compress(buffer2).then((res) => {
// console.log(new Date().getTime() - time, 'compress time')
console.log(`压缩耗时: ${new Date().getTime() - time} ms`)
// 压缩率
console.log(`${JSON.stringify(coverageData).length} b`, `${res.length} b`, (100*res.length / JSON.stringify(coverageData).length).toFixed(2)+'%')
resolve(res);
});


});
});
}

export async function decompressCoverageData(buffer) {
return new Promise((resolve, reject) => {
decompress(buffer).then((res) => {
protobuf.load("proto/coverage.proto", function(err, root) {
if (err)
throw err;

// Obtain a message type
const AwesomeMessage = root.lookupType("CoverageData");



var message = AwesomeMessage.decode(res);
// ... do something with message

// If the application uses length-delimited buffers, there is also encodeDelimited and decodeDelimited.

// Maybe convert the message back to a plain object
var object = AwesomeMessage.toObject(message, {
longs: String,
enums: String,
bytes: String,
// see ConversionOptions
});


resolve(fan_jianchaJiaZhuanhuan(object.data));

}
)
})
});
}
Loading

0 comments on commit 55a06a6

Please sign in to comment.