diff --git a/extension.js b/extension.js index 4018a21..dd609a4 100644 --- a/extension.js +++ b/extension.js @@ -3,8 +3,13 @@ */ const vscode = require("vscode"); const fs = require("fs"); -const path = require("path"); + const { TreeViewProvider } = require("./src/admin/treeview"); +const { createConnectionProfileWebview } = require("./src/admin/webview"); +const simpleGit = require('simple-git'); +const { exec } = require('child_process'); +const path = require('path'); +const os = require('os'); const { saveConnectionProfileToStorage, loadConnectionProfilesFromStorage, @@ -19,6 +24,57 @@ let loadedConnectionProfile = null; const fabricsamples = require("./src/fabricsamples"); function activate(context) { + const fabricDebuggerPath = 'C:\\Users\\Public\\fabric-debugger'; + function runupBashScript() { + const platform = process.platform; + const changeDirCommand = `cd "${fabricDebuggerPath}"`; + let runScriptCommand; + if (platform === 'win32') { + runScriptCommand = `wsl bash local-networkup.sh`; + } else { + runScriptCommand = `bash local-networkup.sh`; + } + const fullCommand = `${changeDirCommand} && ${runScriptCommand}`; + exec(fullCommand, (err, stdout, stderr) => { + if (err) { + vscode.window.showErrorMessage(`Error: ${stderr}`); + console.error(`Error: ${stderr}`); + return; + } + vscode.window.showInformationMessage(`Output: ${stdout}`); + console.log(`Output: ${stdout}`); + }); + } + let greenButton = vscode.commands.registerCommand('myview.button1', () => { + runupBashScript(); + }); + context.subscriptions.push(greenButton); + function rundownBashScript() { + const platform = process.platform; + const changeDirCommand = `cd "${fabricDebuggerPath}"`; + let runScriptCommand; + if (platform === 'win32') { + runScriptCommand = `wsl bash local-networkdown.sh`; + } else { + runScriptCommand = `bash local-networkdown.sh`; + } + const fullCommand = `${changeDirCommand} && ${runScriptCommand}`; + exec(fullCommand, (err, stdout, stderr) => { + if (err) { + vscode.window.showErrorMessage(`Error: ${stderr}`); + console.error(`Error: ${stderr}`); + return; + } + vscode.window.showInformationMessage(`Output: ${stdout}`); + console.log(`Output: ${stdout}`); + }); + } + let redButton = vscode.commands.registerCommand('myview.button2', () => { + rundownBashScript(); + }); + context.subscriptions.push(redButton); + + const hyperledgerProvider = new fabricsamples(); vscode.window.registerTreeDataProvider( "start-local-network", @@ -102,7 +158,6 @@ function activate(context) { "All files": ["*"], }, }); - if (fileUri && fileUri[0]) { const filePath = fileUri[0].fsPath; fs.readFile(filePath, "utf8", async (err, fileContents) => { @@ -335,6 +390,7 @@ function activate(context) { } ) ); + context.subscriptions.push( vscode.commands.registerCommand("wallets.uploadWallet", async () => { @@ -736,38 +792,10 @@ function extractWalletDetails(walletData) { credentials = {}, } = walletData; - const certificate = - credentials.certificate || - walletData.signedCert || - walletData.certificate || - "No Certificate Found"; - - const privateKey = - credentials.privateKey || - walletData.privateKey || - walletData.adminPrivateKey || - "No Private Key Found"; - - if ( - name && - mspId && - type && - certificate !== "No Certificate Found" && - privateKey !== "No Private Key Found" - ) { - return { - name, - mspId, - certificate, - privateKey, - type, - }; - } else { - console.warn("Missing required wallet data fields:"); - } } - return null; } + + function deactivate() {} diff --git a/package-lock.json b/package-lock.json index b30d2c2..f489813 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,9 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@hyperledger/fabric-gateway": "^1.7.0", "fabric-network": "^2.2.20", + "js-yaml": "^4.1.0", "simple-git": "^3.27.0" }, "engines": { @@ -45,6 +47,82 @@ "node": ">=6" } }, + "node_modules/@hyperledger/fabric-gateway": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@hyperledger/fabric-gateway/-/fabric-gateway-1.7.0.tgz", + "integrity": "sha512-P3xQBHuyAy7VsHMWFNGOndlpEgcbKzgXwWACNzDClgMBae+9pHuuLsCyIsuHBtMZP6yg83RCYonTaYD6KpX1HQ==", + "dependencies": { + "@grpc/grpc-js": "^1.11.0", + "@hyperledger/fabric-protos": "^0.3.0", + "@noble/curves": "^1.6.0", + "google-protobuf": "^3.21.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "optionalDependencies": { + "pkcs11js": "^2.1.0" + } + }, + "node_modules/@hyperledger/fabric-gateway/node_modules/@grpc/grpc-js": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.2.tgz", + "integrity": "sha512-bgxdZmgTrJZX50OjyVwz3+mNEnCTNkh3cIqGPWVNeW9jX6bn1ZkU80uPd+67/ZpIJIjRQ9qaHCjhavyoWYxumg==", + "dependencies": { + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@hyperledger/fabric-gateway/node_modules/pkcs11js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-2.1.6.tgz", + "integrity": "sha512-+t5jxzB749q8GaEd1yNx3l98xYuaVK6WW/Vjg1Mk1Iy5bMu/A5W4O/9wZGrpOknWF6lFQSb12FXX+eSNxdriwA==", + "hasInstallScript": true, + "optional": true, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/PeculiarVentures" + } + }, + "node_modules/@hyperledger/fabric-protos": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.3.4.tgz", + "integrity": "sha512-su9E0vtnPS+pWXiK2qJfLGHHO//ZWYEnzwumdT5PQQeLFiZkPhziImgz5AjnKFOcOVrsGGIxcVSAaLFgG1vK8Q==", + "dependencies": { + "@grpc/grpc-js": "^1.11.0", + "google-protobuf": "^3.21.0" + }, + "engines": { + "node": ">=16.13.0" + } + }, + "node_modules/@hyperledger/fabric-protos/node_modules/@grpc/grpc-js": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.2.tgz", + "integrity": "sha512-bgxdZmgTrJZX50OjyVwz3+mNEnCTNkh3cIqGPWVNeW9jX6bn1ZkU80uPd+67/ZpIJIjRQ9qaHCjhavyoWYxumg==", + "dependencies": { + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -58,6 +136,31 @@ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, + "node_modules/@noble/curves": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "dependencies": { + "@noble/hashes": "1.5.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -142,6 +245,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", @@ -466,6 +574,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/google-protobuf": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz", + "integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==" + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -571,6 +684,17 @@ "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz", "integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==" }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsrsasign": { "version": "10.9.0", "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.9.0.tgz", diff --git a/package.json b/package.json index 8f63b3a..65b1f70 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,17 @@ }, "commands": [ { - "command": "fabric-network.uploadNetwork", + "command": "extension.extractFunctions", + "title": "Debug-Chaincode ▶" + }, + { + "command": "fabric-network.start", + "title": "Connection profile form", + "category": "Connection Profile", + "icon": "$(folder)" + }, + { + "command": "fabric-network.openFilePicker", "title": "Upload File", "category": "Connection Profile", "icon": "$(new-file)" @@ -172,7 +182,9 @@ ] }, "dependencies": { + "@hyperledger/fabric-gateway": "^1.7.0", "fabric-network": "^2.2.20", + "js-yaml": "^4.1.0", "simple-git": "^3.27.0" }, "publish": { diff --git a/src/Chaincode/invokechaincode.js b/src/Chaincode/invokechaincode.js new file mode 100644 index 0000000..6165b9d --- /dev/null +++ b/src/Chaincode/invokechaincode.js @@ -0,0 +1,128 @@ +const vscode = require("vscode"); +const fs = require("fs"); +const { exec } = require('child_process'); +const fabricsamples = require('./src/fabricsamples'); +const { Console, log } = require("console"); +const outputChannel = vscode.window.createOutputChannel("Function Arguments Logger"); +const { Gateway, Wallets } = require('fabric-network'); +const yaml = require('js-yaml'); + +async function invokeCommand(functionName, argumentValues) { + const outputChannel = vscode.window.createOutputChannel("Chaincode Invocation"); + outputChannel.appendLine(`Invoking function ${functionName} with arguments: ${argumentValues.join(', ')}`); + + let disposable = vscode.commands.registerCommand('extension.extractFunctions', function () { + const editor = vscode.window.activeTextEditor; + if (!editor) { + vscode.window.showInformationMessage('No active editor. Open a chaincode file.'); + return; + } + const filePath = editor.document.fileName; + const text = editor.document.getText(); + let functions = []; + + if (isGoChaincodeFile(filePath)) { + functions = extractGoFunctions(text); + } + + const filteredFunctions = filterIntAndStringFunctions(functions); + const uniqueFunctions = [...new Set(filteredFunctions)]; + storeFunctions(uniqueFunctions, context); + + vscode.window.showInformationMessage(`Extracted and stored ${uniqueFunctions.length} unique functions with int or string parameters.`); + + showStoredFunctions(context, outputChannel); + }); + + context.subscriptions.push(disposable); + function isGoChaincodeFile(filePath) { + const fileName = filePath.toLowerCase(); + return fileName.endsWith('.go'); + } + + function extractGoFunctions(code) { + const functionDetails = []; + const regex = /func\s*\((\w+)\s+\*SmartContract\)\s*(\w+)\s*\((.*?)\)\s*(\w*)/g; + let match; + + while ((match = regex.exec(code)) !== null) { + const functionName = match[2]; + const params = match[3]; + functionDetails.push({ name: functionName, params }); + } + + return functionDetails; + } + + function filterIntAndStringFunctions(functions) { + return functions.filter(func => /int|string/.test(func.params)).map(func => `${func.name}(${func.params})`); + } + + function storeFunctions(functions, context) { + let storedFunctions = context.workspaceState.get('storedFunctions', []); + storedFunctions = [...new Set([...storedFunctions, ...functions])]; + context.workspaceState.update('storedFunctions', storedFunctions); + } + + function showStoredFunctions(context, outputChannel) { + const storedFunctions = context.workspaceState.get('storedFunctions', []); + + vscode.window.showQuickPick(storedFunctions, { + placeHolder: 'Select a function to invoke', + canPickMany: false + }).then(selectedFunction => { + if (selectedFunction) { + vscode.window.showInformationMessage(`Selected: ${selectedFunction}`); + promptForArgumentsSequentially(selectedFunction, outputChannel); + } + }); + } + + async function promptForArgumentsSequentially(selectedFunction, outputChannel) { + const functionPattern = /(\w+)\((.*)\)/; + const match = functionPattern.exec(selectedFunction); + + if (!match) { + vscode.window.showErrorMessage("Invalid function format."); + return; + } + + const functionName = match[1]; + const paramList = match[2].split(',').map(param => param.trim()); + + let argumentValues = []; + + for (let param of paramList) { + if (/int/.test(param)) { + const input = await vscode.window.showInputBox({ prompt: `Enter an integer value for ${param}` }); + const intValue = parseInt(input, 10); + if (isNaN(intValue)) { + vscode.window.showErrorMessage(`Invalid integer value for ${param}.`); + return; + } + argumentValues.push(intValue); + } else if (/string/.test(param)) { + const input = await vscode.window.showInputBox({ prompt: `Enter a string value for ${param}` }); + if (!input) { + vscode.window.showErrorMessage(`Invalid string value for ${param}.`); + return; + } + argumentValues.push(`"${input}"`); + } + } + + const finalArgs = argumentValues.join(', '); + outputChannel.show(); + outputChannel.appendLine(`Function: ${functionName}`); + outputChannel.appendLine(`Arguments: ${finalArgs}`); + + + vscode.window.showInformationMessage(`Arguments captured. Press "Invoke" to execute the command.`, "Invoke").then(selection => { + if (selection === "Invoke") { + invokeCommand(functionName, argumentValues); + } + }); + } + + outputChannel.show(); +}