Skip to content
This repository has been archived by the owner on Jul 19, 2024. It is now read-only.

Rework gRPC proto loading #83

Merged
merged 4 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions packages/insomnia/src/network/__tests__/network.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ describe('sendCurlAndWriteTimeline()', () => {
PROXY: '',
TIMEOUT_MS: 30000,
URL: 'http://localhost/',
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down Expand Up @@ -373,7 +373,7 @@ describe('sendCurlAndWriteTimeline()', () => {
TIMEOUT_MS: 30000,
UPLOAD: 1,
URL: 'http://localhost/',
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down Expand Up @@ -466,7 +466,7 @@ describe('sendCurlAndWriteTimeline()', () => {
TIMEOUT_MS: 30000,
URL: 'http://localhost/',
UPLOAD: 1,
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down Expand Up @@ -507,7 +507,7 @@ describe('sendCurlAndWriteTimeline()', () => {
TIMEOUT_MS: 30000,
URL: 'http://my/path',
UNIX_SOCKET_PATH: '/my/socket',
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down Expand Up @@ -547,7 +547,7 @@ describe('sendCurlAndWriteTimeline()', () => {
PROXY: '',
TIMEOUT_MS: 30000,
URL: 'http://localhost:3000/foo/bar',
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down Expand Up @@ -587,7 +587,7 @@ describe('sendCurlAndWriteTimeline()', () => {
PROXY: '',
TIMEOUT_MS: 30000,
URL: 'http://unix:3000/my/path',
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down Expand Up @@ -629,7 +629,7 @@ describe('sendCurlAndWriteTimeline()', () => {
TIMEOUT_MS: 30000,
NETRC: CurlNetrc.Required,
URL: '',
USERAGENT: `insomnia/${version}`,
USERAGENT: `insomnium/${version}`,
VERBOSE: true,
},
});
Expand Down
99 changes: 0 additions & 99 deletions packages/insomnia/src/network/grpc/proto-directory-loader.tsx

This file was deleted.

179 changes: 179 additions & 0 deletions packages/insomnia/src/network/grpc/proto-loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import fs from "fs";
import path from "path";

import * as protoLoader from "@grpc/proto-loader";

import * as models from "../../models";
import { database as db } from "../../common/database";
import { ProtoDirectory } from "../../models/proto-directory";
import { ProtoFile } from "../../models/proto-file";
import { writeProtoFile } from "./write-proto-file";
import { Workspace } from "../../models/workspace";

export type ProtoLoadResult = { success: true; loaded: ProtoFile[]; errors: string[] } | { success: false; errors: string[] };

export async function addFileFromPath(filePath: string, parent: ProtoDirectory | Workspace): Promise<ProtoLoadResult> {
// First validate the proto file
const validationResult = await validateProtoFile(filePath, parent);

if (validationResult.success) {
// If proto file is valid, add it
const contents = await fs.promises.readFile(filePath, "utf-8");
const newFile = await models.protoFile.create({
name: path.basename(filePath),
parentId: parent._id,
protoText: contents,
});

return { success: true, loaded: [newFile], errors: [] };
} else {
return { success: false, errors: validationResult.errors };
}
}

export async function updateFileFromPath(protoFile: ProtoFile, filePath: string): Promise<ProtoLoadResult> {
// First validate the proto file
const parent = (await models.protoDirectory.getById(protoFile.parentId)) ?? (await models.workspace.getById(protoFile.parentId));
const validationResult = await validateProtoFile(filePath, parent!);

if (validationResult.success) {
// If file is valid, update it
const contents = await fs.promises.readFile(filePath, "utf-8");
const contentsChanged = contents !== protoFile.protoText;
const updatedFile = await models.protoFile.update(protoFile, {
name: path.basename(filePath),
protoText: contents,
});
// force update the proto file if the content changed
writeProtoFile(updatedFile, contentsChanged);

return { success: true, loaded: [updatedFile], errors: [] };
} else {
return { success: false, errors: validationResult.errors };
}
}

export async function addDirectoryFromPath(directoryPath: string, parent: ProtoDirectory | Workspace): Promise<ProtoLoadResult> {
const entries = await fs.promises.readdir(directoryPath, {
withFileTypes: true,
});
if (entries.length === 0) return { success: true, loaded: [], errors: [] };

const loaded: ProtoFile[] = [];
const errors: string[] = [];

// Make temporary parent id without making the model yet
const newDirectory = await models.protoDirectory.create({
name: path.basename(directoryPath),
parentId: parent._id,
});

for (const e of entries) {
const entryPath = path.join(directoryPath, e.name);
if (e.isDirectory()) {
const nestedResult = await addDirectoryFromPath(entryPath, newDirectory);
if (nestedResult.success) loaded.push(...nestedResult.loaded);
errors.push(...nestedResult.errors);
} else {
if (!e.name.endsWith(".proto")) {
continue; // Not a protobuf file, skip
}

const addResult = await addFileFromPath(entryPath, newDirectory);
if (addResult.success) loaded.push(...addResult.loaded);
errors.push(...addResult.errors);
}
}

if (loaded.length === 0) {
// If no files were created, remove the created directory again
models.protoDirectory.remove(newDirectory);
}

return { success: true, loaded, errors };
}

export async function updateDirectoryFromPath(directoryPath: string, protoDir: ProtoDirectory): Promise<ProtoLoadResult> {
const entries = await fs.promises.readdir(directoryPath, {
withFileTypes: true,
});
if (entries.length === 0) return { success: true, loaded: [], errors: [] };

const loaded: ProtoFile[] = [];
const errors: string[] = [];

const existingChildren = await findDirectoryChildren(protoDir);
for (const e of entries) {
const entryPath = path.join(directoryPath, e.name);
if (e.isDirectory()) {
// If the child is a known directory recurse the update into it, otherwise add it to db
const existingDirectory = existingChildren.find(c => models.protoDirectory.isProtoDirectory(c) && c.name === e.name);
if (existingDirectory) {
// Directory already known, udpate it
const updateResult = await updateDirectoryFromPath(entryPath, existingDirectory);
if (updateResult.success) loaded.push(...updateResult.loaded);
errors.push(...updateResult.errors);
} else {
// Directory unknown, add it
const addResult = await addDirectoryFromPath(entryPath, protoDir);
if (addResult.success) loaded.push(...addResult.loaded);
errors.push(...addResult.errors);
}
} else {
// If the child is a file, update if known, otherwise add it
const existingFile = existingChildren.find((c): c is ProtoFile => models.protoFile.isProtoFile(c) && c.name === e.name);
if (existingFile) {
// File already known, update it
const updateResult = await updateFileFromPath(existingFile, entryPath);
if (updateResult.success) loaded.push(...updateResult.loaded);
errors.push(...updateResult.errors);
} else {
// File is new, add it
const addResult = await addFileFromPath(entryPath, protoDir);
if (addResult.success) loaded.push(...addResult.loaded);
errors.push(...addResult.errors);
}
}
}

return { success: true, loaded, errors };
}

async function findDirectoryChildren(protoDir: ProtoDirectory): Promise<(ProtoFile | ProtoDirectory)[]> {
const descendants = await db.withDescendants(protoDir);
return descendants.filter(d => (models.protoFile.isProtoFile(d) || models.protoDirectory.isProtoDirectory(d)) && d._id !== protoDir._id);
}

async function findAncestorDirectories(filePath: string, context: ProtoDirectory | Workspace): Promise<string[]> {
if (models.workspace.isWorkspace(context)) {
return [path.dirname(filePath)];
} else {
/* Traverse up the file tree to gather all _real_ ancestor directories */
let parent = await models.protoDirectory.getById(context._id);
let basePath = filePath;
const result = [];
while (parent !== null) {
basePath = path.dirname(basePath);
result.push(basePath);
parent = await models.protoDirectory.getById(parent.parentId);
}
return result;
}
}

async function validateProtoFile(filePath: string, parent: ProtoDirectory | Workspace): Promise<ProtoLoadResult> {
const includeDirs = await findAncestorDirectories(filePath, parent);
try {
await protoLoader.load(filePath, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: includeDirs,
});
return { success: true, loaded: [], errors: [] };
} catch (e: any) {
return { success: false, errors: [`${filePath}: ${e.message}}`] };
}
}
6 changes: 3 additions & 3 deletions packages/insomnia/src/sync/git/__tests__/git-vcs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ describe('Git-VCS', () => {
},
message: 'First commit!\n',
parent: [],
tree: '14819d8019f05edb70a29850deb09a4314ad0afc',
tree: 'e2f917fbb2b671fd9a408124fde336a156f2b80c',
},
oid: '76f804a23eef9f52017bf93f4bc0bfde45ec8a93',
payload: `tree 14819d8019f05edb70a29850deb09a4314ad0afc
oid: '42c57adff2f3204f5551348414e930a44c47c88b',
payload: `tree e2f917fbb2b671fd9a408124fde336a156f2b80c
author Karen Brown <karen@example.com> 1000000000 +0000
committer Karen Brown <karen@example.com> 1000000000 +0000

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const GrpcMethodDropdown: FunctionComponent<Props> = ({
style={{ maxWidth: '240px', display: 'flex', alignItems: 'center' }}
>
<span style={{ maxWidth: '240px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
{!selectedPath ? 'Select Method' : getShortGrpcPath(selectedPath)}
{selectedPath ? getShortGrpcPath(selectedPath) : methods.length > 0 ? 'Select Method' : 'No methods in proto'}
</span>
<i className="fa fa-caret-down pad-left-sm" />
</Tooltip>
Expand Down
Loading
Loading