Merge remote-tracking branch 'origin/develop' into jon/update-some-nym-prefixes
This commit is contained in:
@@ -14,12 +14,20 @@ inputs:
|
||||
description: 'The tag/release to process. Uses the release id when trigger from a release.'
|
||||
required: false
|
||||
default: ''
|
||||
repo:
|
||||
description: 'The repo to use. Defaults to "nym".'
|
||||
required: false
|
||||
default: 'nym'
|
||||
owner:
|
||||
description: 'The repo owner to use. Defaults to "nymtech".'
|
||||
required: false
|
||||
default: 'nymtech'
|
||||
outputs:
|
||||
hashes:
|
||||
description: 'A string containing JSON with the release asset hashes and signatures'
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'index.js'
|
||||
using: 'node20'
|
||||
main: 'dist/index.js'
|
||||
branding:
|
||||
icon: 'hash'
|
||||
color: 'green'
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
export const id = 37;
|
||||
export const ids = [37];
|
||||
export const modules = {
|
||||
|
||||
/***/ 4037:
|
||||
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "toFormData": () => (/* binding */ toFormData)
|
||||
/* harmony export */ });
|
||||
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2777);
|
||||
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8010);
|
||||
|
||||
|
||||
|
||||
let s = 0;
|
||||
const S = {
|
||||
START_BOUNDARY: s++,
|
||||
HEADER_FIELD_START: s++,
|
||||
HEADER_FIELD: s++,
|
||||
HEADER_VALUE_START: s++,
|
||||
HEADER_VALUE: s++,
|
||||
HEADER_VALUE_ALMOST_DONE: s++,
|
||||
HEADERS_ALMOST_DONE: s++,
|
||||
PART_DATA_START: s++,
|
||||
PART_DATA: s++,
|
||||
END: s++
|
||||
};
|
||||
|
||||
let f = 1;
|
||||
const F = {
|
||||
PART_BOUNDARY: f,
|
||||
LAST_BOUNDARY: f *= 2
|
||||
};
|
||||
|
||||
const LF = 10;
|
||||
const CR = 13;
|
||||
const SPACE = 32;
|
||||
const HYPHEN = 45;
|
||||
const COLON = 58;
|
||||
const A = 97;
|
||||
const Z = 122;
|
||||
|
||||
const lower = c => c | 0x20;
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
class MultipartParser {
|
||||
/**
|
||||
* @param {string} boundary
|
||||
*/
|
||||
constructor(boundary) {
|
||||
this.index = 0;
|
||||
this.flags = 0;
|
||||
|
||||
this.onHeaderEnd = noop;
|
||||
this.onHeaderField = noop;
|
||||
this.onHeadersEnd = noop;
|
||||
this.onHeaderValue = noop;
|
||||
this.onPartBegin = noop;
|
||||
this.onPartData = noop;
|
||||
this.onPartEnd = noop;
|
||||
|
||||
this.boundaryChars = {};
|
||||
|
||||
boundary = '\r\n--' + boundary;
|
||||
const ui8a = new Uint8Array(boundary.length);
|
||||
for (let i = 0; i < boundary.length; i++) {
|
||||
ui8a[i] = boundary.charCodeAt(i);
|
||||
this.boundaryChars[ui8a[i]] = true;
|
||||
}
|
||||
|
||||
this.boundary = ui8a;
|
||||
this.lookbehind = new Uint8Array(this.boundary.length + 8);
|
||||
this.state = S.START_BOUNDARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} data
|
||||
*/
|
||||
write(data) {
|
||||
let i = 0;
|
||||
const length_ = data.length;
|
||||
let previousIndex = this.index;
|
||||
let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
|
||||
const boundaryLength = this.boundary.length;
|
||||
const boundaryEnd = boundaryLength - 1;
|
||||
const bufferLength = data.length;
|
||||
let c;
|
||||
let cl;
|
||||
|
||||
const mark = name => {
|
||||
this[name + 'Mark'] = i;
|
||||
};
|
||||
|
||||
const clear = name => {
|
||||
delete this[name + 'Mark'];
|
||||
};
|
||||
|
||||
const callback = (callbackSymbol, start, end, ui8a) => {
|
||||
if (start === undefined || start !== end) {
|
||||
this[callbackSymbol](ui8a && ui8a.subarray(start, end));
|
||||
}
|
||||
};
|
||||
|
||||
const dataCallback = (name, clear) => {
|
||||
const markSymbol = name + 'Mark';
|
||||
if (!(markSymbol in this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
callback(name, this[markSymbol], i, data);
|
||||
delete this[markSymbol];
|
||||
} else {
|
||||
callback(name, this[markSymbol], data.length, data);
|
||||
this[markSymbol] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
for (i = 0; i < length_; i++) {
|
||||
c = data[i];
|
||||
|
||||
switch (state) {
|
||||
case S.START_BOUNDARY:
|
||||
if (index === boundary.length - 2) {
|
||||
if (c === HYPHEN) {
|
||||
flags |= F.LAST_BOUNDARY;
|
||||
} else if (c !== CR) {
|
||||
return;
|
||||
}
|
||||
|
||||
index++;
|
||||
break;
|
||||
} else if (index - 1 === boundary.length - 2) {
|
||||
if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
|
||||
state = S.END;
|
||||
flags = 0;
|
||||
} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
|
||||
index = 0;
|
||||
callback('onPartBegin');
|
||||
state = S.HEADER_FIELD_START;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (c !== boundary[index + 2]) {
|
||||
index = -2;
|
||||
}
|
||||
|
||||
if (c === boundary[index + 2]) {
|
||||
index++;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.HEADER_FIELD_START:
|
||||
state = S.HEADER_FIELD;
|
||||
mark('onHeaderField');
|
||||
index = 0;
|
||||
// falls through
|
||||
case S.HEADER_FIELD:
|
||||
if (c === CR) {
|
||||
clear('onHeaderField');
|
||||
state = S.HEADERS_ALMOST_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
if (c === HYPHEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c === COLON) {
|
||||
if (index === 1) {
|
||||
// empty header field
|
||||
return;
|
||||
}
|
||||
|
||||
dataCallback('onHeaderField', true);
|
||||
state = S.HEADER_VALUE_START;
|
||||
break;
|
||||
}
|
||||
|
||||
cl = lower(c);
|
||||
if (cl < A || cl > Z) {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.HEADER_VALUE_START:
|
||||
if (c === SPACE) {
|
||||
break;
|
||||
}
|
||||
|
||||
mark('onHeaderValue');
|
||||
state = S.HEADER_VALUE;
|
||||
// falls through
|
||||
case S.HEADER_VALUE:
|
||||
if (c === CR) {
|
||||
dataCallback('onHeaderValue', true);
|
||||
callback('onHeaderEnd');
|
||||
state = S.HEADER_VALUE_ALMOST_DONE;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.HEADER_VALUE_ALMOST_DONE:
|
||||
if (c !== LF) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
case S.HEADERS_ALMOST_DONE:
|
||||
if (c !== LF) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback('onHeadersEnd');
|
||||
state = S.PART_DATA_START;
|
||||
break;
|
||||
case S.PART_DATA_START:
|
||||
state = S.PART_DATA;
|
||||
mark('onPartData');
|
||||
// falls through
|
||||
case S.PART_DATA:
|
||||
previousIndex = index;
|
||||
|
||||
if (index === 0) {
|
||||
// boyer-moore derrived algorithm to safely skip non-boundary data
|
||||
i += boundaryEnd;
|
||||
while (i < bufferLength && !(data[i] in boundaryChars)) {
|
||||
i += boundaryLength;
|
||||
}
|
||||
|
||||
i -= boundaryEnd;
|
||||
c = data[i];
|
||||
}
|
||||
|
||||
if (index < boundary.length) {
|
||||
if (boundary[index] === c) {
|
||||
if (index === 0) {
|
||||
dataCallback('onPartData', true);
|
||||
}
|
||||
|
||||
index++;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else if (index === boundary.length) {
|
||||
index++;
|
||||
if (c === CR) {
|
||||
// CR = part boundary
|
||||
flags |= F.PART_BOUNDARY;
|
||||
} else if (c === HYPHEN) {
|
||||
// HYPHEN = end boundary
|
||||
flags |= F.LAST_BOUNDARY;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else if (index - 1 === boundary.length) {
|
||||
if (flags & F.PART_BOUNDARY) {
|
||||
index = 0;
|
||||
if (c === LF) {
|
||||
// unset the PART_BOUNDARY flag
|
||||
flags &= ~F.PART_BOUNDARY;
|
||||
callback('onPartEnd');
|
||||
callback('onPartBegin');
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
}
|
||||
} else if (flags & F.LAST_BOUNDARY) {
|
||||
if (c === HYPHEN) {
|
||||
callback('onPartEnd');
|
||||
state = S.END;
|
||||
flags = 0;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
// when matching a possible boundary, keep a lookbehind reference
|
||||
// in case it turns out to be a false lead
|
||||
lookbehind[index - 1] = c;
|
||||
} else if (previousIndex > 0) {
|
||||
// if our boundary turned out to be rubbish, the captured lookbehind
|
||||
// belongs to partData
|
||||
const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
|
||||
callback('onPartData', 0, previousIndex, _lookbehind);
|
||||
previousIndex = 0;
|
||||
mark('onPartData');
|
||||
|
||||
// reconsider the current character even so it interrupted the sequence
|
||||
// it could be the beginning of a new sequence
|
||||
i--;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.END:
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected state entered: ${state}`);
|
||||
}
|
||||
}
|
||||
|
||||
dataCallback('onHeaderField');
|
||||
dataCallback('onHeaderValue');
|
||||
dataCallback('onPartData');
|
||||
|
||||
// Update properties for the next call
|
||||
this.index = index;
|
||||
this.state = state;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
end() {
|
||||
if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
|
||||
(this.state === S.PART_DATA && this.index === this.boundary.length)) {
|
||||
this.onPartEnd();
|
||||
} else if (this.state !== S.END) {
|
||||
throw new Error('MultipartParser.end(): stream ended unexpectedly');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _fileName(headerValue) {
|
||||
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||
const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
|
||||
const match = m[2] || m[3] || '';
|
||||
let filename = match.slice(match.lastIndexOf('\\') + 1);
|
||||
filename = filename.replace(/%22/g, '"');
|
||||
filename = filename.replace(/&#(\d{4});/g, (m, code) => {
|
||||
return String.fromCharCode(code);
|
||||
});
|
||||
return filename;
|
||||
}
|
||||
|
||||
async function toFormData(Body, ct) {
|
||||
if (!/multipart/i.test(ct)) {
|
||||
throw new TypeError('Failed to fetch');
|
||||
}
|
||||
|
||||
const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
|
||||
|
||||
if (!m) {
|
||||
throw new TypeError('no or bad content-type header, no multipart boundary');
|
||||
}
|
||||
|
||||
const parser = new MultipartParser(m[1] || m[2]);
|
||||
|
||||
let headerField;
|
||||
let headerValue;
|
||||
let entryValue;
|
||||
let entryName;
|
||||
let contentType;
|
||||
let filename;
|
||||
const entryChunks = [];
|
||||
const formData = new formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__/* .FormData */ .Ct();
|
||||
|
||||
const onPartData = ui8a => {
|
||||
entryValue += decoder.decode(ui8a, {stream: true});
|
||||
};
|
||||
|
||||
const appendToFile = ui8a => {
|
||||
entryChunks.push(ui8a);
|
||||
};
|
||||
|
||||
const appendFileToFormData = () => {
|
||||
const file = new fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__/* .File */ .$B(entryChunks, filename, {type: contentType});
|
||||
formData.append(entryName, file);
|
||||
};
|
||||
|
||||
const appendEntryToFormData = () => {
|
||||
formData.append(entryName, entryValue);
|
||||
};
|
||||
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
decoder.decode();
|
||||
|
||||
parser.onPartBegin = function () {
|
||||
parser.onPartData = onPartData;
|
||||
parser.onPartEnd = appendEntryToFormData;
|
||||
|
||||
headerField = '';
|
||||
headerValue = '';
|
||||
entryValue = '';
|
||||
entryName = '';
|
||||
contentType = '';
|
||||
filename = null;
|
||||
entryChunks.length = 0;
|
||||
};
|
||||
|
||||
parser.onHeaderField = function (ui8a) {
|
||||
headerField += decoder.decode(ui8a, {stream: true});
|
||||
};
|
||||
|
||||
parser.onHeaderValue = function (ui8a) {
|
||||
headerValue += decoder.decode(ui8a, {stream: true});
|
||||
};
|
||||
|
||||
parser.onHeaderEnd = function () {
|
||||
headerValue += decoder.decode();
|
||||
headerField = headerField.toLowerCase();
|
||||
|
||||
if (headerField === 'content-disposition') {
|
||||
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||
const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
|
||||
|
||||
if (m) {
|
||||
entryName = m[2] || m[3] || '';
|
||||
}
|
||||
|
||||
filename = _fileName(headerValue);
|
||||
|
||||
if (filename) {
|
||||
parser.onPartData = appendToFile;
|
||||
parser.onPartEnd = appendFileToFormData;
|
||||
}
|
||||
} else if (headerField === 'content-type') {
|
||||
contentType = headerValue;
|
||||
}
|
||||
|
||||
headerValue = '';
|
||||
headerField = '';
|
||||
};
|
||||
|
||||
for await (const chunk of Body) {
|
||||
parser.write(chunk);
|
||||
}
|
||||
|
||||
parser.end();
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const {parentPort} = require('worker_threads');
|
||||
|
||||
const handlers = {
|
||||
hashFile: (algorithm, filePath) => new Promise((resolve, reject) => {
|
||||
const hasher = crypto.createHash(algorithm);
|
||||
fs.createReadStream(filePath)
|
||||
// TODO: Use `Stream.pipeline` when targeting Node.js 12.
|
||||
.on('error', reject)
|
||||
.pipe(hasher)
|
||||
.on('error', reject)
|
||||
.on('finish', () => {
|
||||
const {buffer} = new Uint8Array(hasher.read());
|
||||
resolve({value: buffer, transferList: [buffer]});
|
||||
});
|
||||
}),
|
||||
hash: async (algorithm, input) => {
|
||||
const hasher = crypto.createHash(algorithm);
|
||||
|
||||
if (Array.isArray(input)) {
|
||||
for (const part of input) {
|
||||
hasher.update(part);
|
||||
}
|
||||
} else {
|
||||
hasher.update(input);
|
||||
}
|
||||
|
||||
const {buffer} = new Uint8Array(hasher.digest());
|
||||
return {value: buffer, transferList: [buffer]};
|
||||
}
|
||||
};
|
||||
|
||||
parentPort.on('message', async message => {
|
||||
try {
|
||||
const {method, args} = message;
|
||||
const handler = handlers[method];
|
||||
|
||||
if (handler === undefined) {
|
||||
throw new Error(`Unknown method '${method}'`);
|
||||
}
|
||||
|
||||
const {value, transferList} = await handler(...args);
|
||||
parentPort.postMessage({id: message.id, value}, transferList);
|
||||
} catch (error) {
|
||||
const newError = {message: error.message, stack: error.stack};
|
||||
|
||||
for (const [key, value] of Object.entries(error)) {
|
||||
if (typeof value !== 'object') {
|
||||
newError[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
parentPort.postMessage({id: message.id, error: newError});
|
||||
}
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import core from "@actions/core";
|
||||
import github from "@actions/github";
|
||||
import { createHashesFromReleaseTagOrNameOrId } from './create-hashes.mjs';
|
||||
|
||||
const algorithm = core.getInput('hash-type');
|
||||
const filename = core.getInput("file-name");
|
||||
|
||||
// use the release id from the payload if it is set
|
||||
const releaseTagOrNameOrId = core.getInput("release-tag-or-name-or-id") || github.context.payload.release?.id;
|
||||
|
||||
try {
|
||||
await createHashesFromReleaseTagOrNameOrId({ releaseTagOrNameOrId, algorithm, filename })
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
@@ -2,17 +2,6 @@
|
||||
"name": "nym-hash-release",
|
||||
"version": "1.0.0",
|
||||
"description": "Generate hashes and signatures for assets in Nym releases",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"local": "node run-local.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/auth-action": "^4.0.0",
|
||||
"@octokit/rest": "^20.0.1",
|
||||
"hasha": "^5.2.0",
|
||||
"node-fetch": "^3.2.10"
|
||||
}
|
||||
"main": "dist/index.js",
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# nym-hash-release
|
||||
|
||||
This is the source code for the custom GitHub Action to calculate hashes.
|
||||
|
||||
It is in a subdirectory to avoid issues with `package.json`.
|
||||
|
||||
## Build
|
||||
|
||||
The following will bundle all code and dependencies into the `dist` folder, and copy it into place for GitHub Actions.
|
||||
|
||||
```
|
||||
npm run build
|
||||
npm run dist:copy
|
||||
```
|
||||
+8
-4
@@ -142,7 +142,7 @@ export async function createHashes({ assets, algorithm, filename, cache }) {
|
||||
return output;
|
||||
}
|
||||
|
||||
export async function createHashesFromReleaseTagOrNameOrId({ releaseTagOrNameOrId, algorithm = 'sha256', filename = 'hashes.json', cache = false, upload = true }) {
|
||||
export async function createHashesFromReleaseTagOrNameOrId({ releaseTagOrNameOrId, algorithm = 'sha256', filename = 'hashes.json', cache = false, upload = true, owner = 'nymtech', repo = 'nym' }) {
|
||||
console.log("🚀🚀🚀 Getting releases");
|
||||
|
||||
let auth;
|
||||
@@ -157,8 +157,6 @@ export async function createHashesFromReleaseTagOrNameOrId({ releaseTagOrNameOrI
|
||||
auth: process.env.GITHUB_TOKEN,
|
||||
request: { fetch }
|
||||
});
|
||||
const owner = "nymtech";
|
||||
const repo = "nym";
|
||||
|
||||
let releases;
|
||||
if(cache) {
|
||||
@@ -212,7 +210,13 @@ export async function createHashesFromReleaseTagOrNameOrId({ releaseTagOrNameOrI
|
||||
|
||||
releasesToProcess.forEach(release => {
|
||||
const {tag_name, name} = release;
|
||||
const tagComponents = tag_name.split('-v');
|
||||
const matches = tag_name.match(/(\S+)-v([0-9]+\.[0-9]+\.\S+)/);
|
||||
|
||||
if(!matches || matches.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tagComponents = matches.slice(1);
|
||||
const componentName = tagComponents[0];
|
||||
const componentVersion = 'v' + tagComponents[1];
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import core from "@actions/core";
|
||||
import github from "@actions/github";
|
||||
import { createHashesFromReleaseTagOrNameOrId } from './create-hashes.mjs';
|
||||
|
||||
const algorithm = core.getInput('hash-type');
|
||||
const filename = core.getInput("file-name");
|
||||
const owner = core.getInput("owner");
|
||||
const repo = core.getInput("repo");
|
||||
|
||||
async function main() {
|
||||
// use the release id from the payload if it is set
|
||||
const releaseTagOrNameOrId = core.getInput("release-tag-or-name-or-id") || github.context.payload.release?.id;
|
||||
|
||||
try {
|
||||
await createHashesFromReleaseTagOrNameOrId({releaseTagOrNameOrId, algorithm, filename, owner, repo})
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => core.setFailed(error.message));
|
||||
+72
-35
@@ -1,26 +1,28 @@
|
||||
{
|
||||
"name": "ghaction-generate-release-hashes",
|
||||
"name": "nym-hash-release",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ghaction-generate-release-hashes",
|
||||
"name": "nym-hash-release",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/auth-action": "^4.0.0",
|
||||
"@octokit/rest": "^20.0.1",
|
||||
"@octokit/auth-action": "^4.0.1",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"hasha": "^5.2.0",
|
||||
"node-fetch": "^3.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.38.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
|
||||
"integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
@@ -46,12 +48,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-action": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-action/-/auth-action-4.0.0.tgz",
|
||||
"integrity": "sha512-sMm9lWZdiX6e89YFaLrgE9EFs94k58BwIkvjOtozNWUqyTmsrnWFr/M5LolaRzZ7Kmb5FbhF9hi7FEeE274SoQ==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-action/-/auth-action-4.0.1.tgz",
|
||||
"integrity": "sha512-mJLOcFFafIivLZ7BEkGDCTFoHPJv7BeL5Zwy7j5qMDU0b/DKshhi6GCU9tw3vmKhOxTNquYfvwqsEfPpemaaxg==",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/types": "^11.0.0"
|
||||
"@octokit/types": "^12.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
@@ -66,16 +68,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-action/node_modules/@octokit/openapi-types": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz",
|
||||
"integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw=="
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
|
||||
},
|
||||
"node_modules/@octokit/auth-action/node_modules/@octokit/types": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-11.1.0.tgz",
|
||||
"integrity": "sha512-Fz0+7GyLm/bHt8fwEqgvRBWwIV1S6wRRyq+V6exRKLVWaKGsuy6H9QFYeBVDV7rK6fO3XwHgQOPxv+cLj2zpXQ==",
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^18.0.0"
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
@@ -191,14 +193,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "20.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.1.tgz",
|
||||
"integrity": "sha512-wROV21RwHQIMNb2Dgd4+pY+dVy1Dwmp85pBrgr6YRRDYRBu9Gb+D73f4Bl2EukZSj5hInq2Tui9o7gAQpc2k2Q==",
|
||||
"version": "20.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.2.tgz",
|
||||
"integrity": "sha512-Ux8NDgEraQ/DMAU1PlAohyfBBXDwhnX2j33Z1nJNziqAfHi70PuxkFYIcIt8aIAxtRE7KVuKp8lSR8pA0J5iOQ==",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^5.0.0",
|
||||
"@octokit/plugin-paginate-rest": "^8.0.0",
|
||||
"@octokit/plugin-paginate-rest": "^9.0.0",
|
||||
"@octokit/plugin-request-log": "^4.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^9.0.0"
|
||||
"@octokit/plugin-rest-endpoint-methods": "^10.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
@@ -261,17 +263,30 @@
|
||||
"integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw=="
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-8.0.0.tgz",
|
||||
"integrity": "sha512-2xZ+baZWUg+qudVXnnvXz7qfrTmDeYPCzangBVq/1gXxii/OiS//4shJp9dnCCvj1x+JAm9ji1Egwm1BA47lPQ==",
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz",
|
||||
"integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^11.0.0"
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=5"
|
||||
"@octokit/core": "5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": {
|
||||
@@ -286,17 +301,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-9.0.0.tgz",
|
||||
"integrity": "sha512-KquMF/VB1IkKNiVnzJKspY5mFgGyLd7HzdJfVEGTJFzqu9BRFNWt+nwTCMuUiWc72gLQhRWYubTwOkQj+w/1PA==",
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz",
|
||||
"integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^11.0.0"
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=5"
|
||||
"@octokit/core": "5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request": {
|
||||
@@ -343,6 +371,15 @@
|
||||
"@octokit/openapi-types": "^12.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.38.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz",
|
||||
"integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "nym-hash-release",
|
||||
"version": "1.0.0",
|
||||
"description": "Generate hashes and signatures for assets in Nym releases",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"local": "node run-local.mjs",
|
||||
"build": "ncc build index.js -o dist",
|
||||
"dist:copy": "mkdir -p ../dist && cp dist/*.js ../dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@octokit/auth-action": "^4.0.1",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"hasha": "^5.2.0",
|
||||
"node-fetch": "^3.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.38.1"
|
||||
}
|
||||
}
|
||||
Generated
+59
-37
@@ -1419,14 +1419,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpu-cycles"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
@@ -1906,12 +1898,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.3"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8"
|
||||
dependencies = [
|
||||
"darling_core 0.20.3",
|
||||
"darling_macro 0.20.3",
|
||||
"darling_core 0.20.5",
|
||||
"darling_macro 0.20.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1944,9 +1936,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.3"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||
checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
@@ -1980,11 +1972,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.3"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77"
|
||||
dependencies = [
|
||||
"darling_core 0.20.3",
|
||||
"darling_core 0.20.5",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
@@ -5588,7 +5580,9 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
"wasmtimer",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -5717,6 +5711,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-metrics"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"prometheus",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnet-client"
|
||||
version = "0.1.0"
|
||||
@@ -5757,19 +5762,19 @@ dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"bs58 0.5.0",
|
||||
"cfg-if",
|
||||
"clap 4.4.7",
|
||||
"colored",
|
||||
"cpu-cycles",
|
||||
"cupid",
|
||||
"dirs 4.0.0",
|
||||
"futures",
|
||||
"humantime-serde",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-config",
|
||||
"nym-contracts-common",
|
||||
"nym-crypto",
|
||||
"nym-metrics",
|
||||
"nym-mixnet-client",
|
||||
"nym-mixnode-common",
|
||||
"nym-node",
|
||||
@@ -5782,7 +5787,6 @@ dependencies = [
|
||||
"nym-topology",
|
||||
"nym-types",
|
||||
"nym-validator-client",
|
||||
"opentelemetry",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5791,7 +5795,6 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"toml 0.5.11",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -5800,13 +5803,12 @@ name = "nym-mixnode-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
"cpu-cycles",
|
||||
"futures",
|
||||
"humantime-serde",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-crypto",
|
||||
"nym-metrics",
|
||||
"nym-network-defaults",
|
||||
"nym-sphinx-acknowledgements",
|
||||
"nym-sphinx-addressing",
|
||||
@@ -5821,7 +5823,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -7441,6 +7442,21 @@ dependencies = [
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"parking_lot 0.12.1",
|
||||
"protobuf",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus-client"
|
||||
version = "0.19.0"
|
||||
@@ -7563,10 +7579,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psl"
|
||||
version = "2.1.14"
|
||||
name = "protobuf"
|
||||
version = "2.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "383703acfc34f7a00724846c14dc5ea4407c59e5aedcbbb18a1c0c1a23fe5013"
|
||||
checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
|
||||
|
||||
[[package]]
|
||||
name = "psl"
|
||||
version = "2.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc74a6e6a56708be1cf5c4c4d1a0dc21d33b2dcaa24e731b7fa9c287ce4f916f"
|
||||
dependencies = [
|
||||
"psl-types",
|
||||
]
|
||||
@@ -7962,13 +7984,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
version = "1.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.3",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
@@ -7983,9 +8005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -8808,9 +8830,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.4.0"
|
||||
version = "3.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
|
||||
checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"chrono",
|
||||
@@ -8825,11 +8847,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.4.0"
|
||||
version = "3.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
|
||||
checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15"
|
||||
dependencies = [
|
||||
"darling 0.20.3",
|
||||
"darling 0.20.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
|
||||
+19
-6
@@ -32,7 +32,7 @@ members = [
|
||||
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
# "common/cosmwasm-smart-contracts/ephemera",
|
||||
# "common/cosmwasm-smart-contracts/ephemera",
|
||||
"common/cosmwasm-smart-contracts/group-contract",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||
@@ -57,6 +57,7 @@ members = [
|
||||
"common/nonexhaustive-delayqueue",
|
||||
"common/nymcoconut",
|
||||
"common/nym-id",
|
||||
"common/nym-metrics",
|
||||
"common/nymsphinx",
|
||||
"common/nymsphinx/acknowledgements",
|
||||
"common/nymsphinx/addressing",
|
||||
@@ -112,9 +113,10 @@ members = [
|
||||
"tools/nymvisor",
|
||||
"tools/ts-rs-cli",
|
||||
"wasm/client",
|
||||
# "wasm/full-nym-wasm",
|
||||
# "wasm/full-nym-wasm",
|
||||
"wasm/mix-fetch",
|
||||
"wasm/node-tester",
|
||||
"common/nym-metrics",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
@@ -130,7 +132,16 @@ default-members = [
|
||||
"nym-validator-rewarder",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles", "sdk/ffi/cpp"]
|
||||
exclude = [
|
||||
"explorer",
|
||||
"contracts",
|
||||
"nym-wallet",
|
||||
"nym-connect/mobile/src-tauri",
|
||||
"nym-connect/desktop",
|
||||
"nym-vpn/ui/src-tauri",
|
||||
"cpu-cycles",
|
||||
"sdk/ffi/cpp",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Nym Technologies SA"]
|
||||
@@ -180,10 +191,12 @@ utoipa-swagger-ui = "3.1.5"
|
||||
url = "2.4"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
prometheus = { version = "0.13.0" }
|
||||
|
||||
# coconut/DKG related
|
||||
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
|
||||
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="feature/gt-serialization-0.8.0" }
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "feature/gt-serialization-0.8.0" }
|
||||
group = "0.13.0"
|
||||
ff = "0.13.0"
|
||||
|
||||
@@ -208,9 +221,9 @@ cw-controllers = { version = "=1.1.0" }
|
||||
bip32 = "0.5.1"
|
||||
|
||||
# temporarily using a fork again (yay.) because we need staking and slashing support
|
||||
cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch ="nym-temp/all-validator-features" }
|
||||
cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" }
|
||||
#cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" } # unfortuntely we need a fork by yours truly to get the staking support
|
||||
tendermint = "0.34" # same version as used by cosmrs
|
||||
tendermint = "0.34" # same version as used by cosmrs
|
||||
tendermint-rpc = "0.34" # same version as used by cosmrs
|
||||
prost = "0.12"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ use nym_gateway_requests::authentication::encrypted_address::EncryptedAddressByt
|
||||
use nym_gateway_requests::iv::IV;
|
||||
use nym_gateway_requests::registration::handshake::{client_handshake, SharedKeys};
|
||||
use nym_gateway_requests::{
|
||||
BinaryRequest, ClientControlRequest, ServerResponse, CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION,
|
||||
BinaryRequest, ClientControlRequest, ServerResponse, CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION,
|
||||
CURRENT_PROTOCOL_VERSION,
|
||||
};
|
||||
use nym_network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
|
||||
@@ -438,6 +438,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
ws_stream,
|
||||
self.local_identity.as_ref(),
|
||||
self.gateway_identity,
|
||||
!self.disabled_credentials_mode,
|
||||
)
|
||||
.await
|
||||
.map_err(GatewayClientError::RegistrationFailure),
|
||||
@@ -494,8 +495,13 @@ impl<C, St> GatewayClient<C, St> {
|
||||
.derive_destination_address();
|
||||
let encrypted_address = EncryptedAddressBytes::new(&self_address, shared_key, &iv);
|
||||
|
||||
let msg =
|
||||
ClientControlRequest::new_authenticate(self_address, encrypted_address, iv).into();
|
||||
let msg = ClientControlRequest::new_authenticate(
|
||||
self_address,
|
||||
encrypted_address,
|
||||
iv,
|
||||
!self.disabled_credentials_mode,
|
||||
)
|
||||
.into();
|
||||
|
||||
match self.send_websocket_message(msg).await? {
|
||||
ServerResponse::Authenticate {
|
||||
@@ -599,7 +605,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
});
|
||||
};
|
||||
|
||||
if gateway_protocol < CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION {
|
||||
if gateway_protocol < CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION {
|
||||
return Err(GatewayClientError::OutdatedGatewayCredentialVersion {
|
||||
negotiated_protocol: Some(gateway_protocol),
|
||||
});
|
||||
|
||||
@@ -8,7 +8,8 @@ pub mod response;
|
||||
|
||||
// version 3: initial version
|
||||
// version 4: IPv6 support
|
||||
pub const CURRENT_VERSION: u8 = 4;
|
||||
// version 5: Add severity level to info response
|
||||
pub const CURRENT_VERSION: u8 = 5;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct IpPair {
|
||||
@@ -24,7 +25,7 @@ impl IpPair {
|
||||
|
||||
impl Display for IpPair {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "IPv4: {}, IPV6: {}", self.ipv4, self.ipv6)
|
||||
write!(f, "IPv4: {}, IPv6: {}", self.ipv4, self.ipv6)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,34 @@ impl IpPacketRequest {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_ping(reply_to: Recipient) -> (Self, u64) {
|
||||
let request_id = generate_random();
|
||||
(
|
||||
Self {
|
||||
version: CURRENT_VERSION,
|
||||
data: IpPacketRequestData::Ping(PingRequest {
|
||||
request_id,
|
||||
reply_to,
|
||||
}),
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_health_request(reply_to: Recipient) -> (Self, u64) {
|
||||
let request_id = generate_random();
|
||||
(
|
||||
Self {
|
||||
version: CURRENT_VERSION,
|
||||
data: IpPacketRequestData::Health(HealthRequest {
|
||||
request_id,
|
||||
reply_to,
|
||||
}),
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> Option<u64> {
|
||||
match &self.data {
|
||||
IpPacketRequestData::StaticConnect(request) => Some(request.request_id),
|
||||
|
||||
@@ -116,24 +116,59 @@ impl IpPacketResponse {
|
||||
) -> Self {
|
||||
Self {
|
||||
version: CURRENT_VERSION,
|
||||
data: IpPacketResponseData::Error(ErrorResponse {
|
||||
data: IpPacketResponseData::Info(InfoResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: ErrorResponseReply::VersionMismatch {
|
||||
reply: InfoResponseReply::VersionMismatch {
|
||||
request_version,
|
||||
response_version: our_version,
|
||||
},
|
||||
level: InfoLevel::Error,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_data_error_response(reply_to: Recipient, reply: ErrorResponseReply) -> Self {
|
||||
pub fn new_data_info_response(
|
||||
reply_to: Recipient,
|
||||
reply: InfoResponseReply,
|
||||
level: InfoLevel,
|
||||
) -> Self {
|
||||
Self {
|
||||
version: CURRENT_VERSION,
|
||||
data: IpPacketResponseData::Error(ErrorResponse {
|
||||
data: IpPacketResponseData::Info(InfoResponse {
|
||||
request_id: 0,
|
||||
reply_to,
|
||||
reply,
|
||||
level,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_pong(request_id: u64, reply_to: Recipient) -> Self {
|
||||
Self {
|
||||
version: CURRENT_VERSION,
|
||||
data: IpPacketResponseData::Pong(PongResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_health_response(
|
||||
request_id: u64,
|
||||
reply_to: Recipient,
|
||||
build_info: nym_bin_common::build_information::BinaryBuildInformationOwned,
|
||||
routable: Option<bool>,
|
||||
) -> Self {
|
||||
Self {
|
||||
version: CURRENT_VERSION,
|
||||
data: IpPacketResponseData::Health(HealthResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: HealthResponseReply {
|
||||
build_info,
|
||||
routable,
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -147,7 +182,7 @@ impl IpPacketResponse {
|
||||
IpPacketResponseData::Data(_) => None,
|
||||
IpPacketResponseData::Pong(response) => Some(response.request_id),
|
||||
IpPacketResponseData::Health(response) => Some(response.request_id),
|
||||
IpPacketResponseData::Error(response) => Some(response.request_id),
|
||||
IpPacketResponseData::Info(response) => Some(response.request_id),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +195,7 @@ impl IpPacketResponse {
|
||||
IpPacketResponseData::Data(_) => None,
|
||||
IpPacketResponseData::Pong(response) => Some(&response.reply_to),
|
||||
IpPacketResponseData::Health(response) => Some(&response.reply_to),
|
||||
IpPacketResponseData::Error(response) => Some(&response.reply_to),
|
||||
IpPacketResponseData::Info(response) => Some(&response.reply_to),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,8 +236,8 @@ pub enum IpPacketResponseData {
|
||||
// Response for a health request
|
||||
Health(HealthResponse),
|
||||
|
||||
// Error response
|
||||
Error(ErrorResponse),
|
||||
// Info response. This can be anything from informative messages to errors
|
||||
Info(InfoResponse),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
@@ -338,14 +373,15 @@ pub struct HealthResponseReply {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ErrorResponse {
|
||||
pub struct InfoResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: ErrorResponseReply,
|
||||
pub reply: InfoResponseReply,
|
||||
pub level: InfoLevel,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
pub enum ErrorResponseReply {
|
||||
pub enum InfoResponseReply {
|
||||
#[error("{msg}")]
|
||||
Generic { msg: String },
|
||||
#[error(
|
||||
@@ -358,3 +394,10 @@ pub enum ErrorResponseReply {
|
||||
#[error("destination failed exit policy filter check: {dst}")]
|
||||
ExitPolicyFilterCheckFailed { dst: String },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum InfoLevel {
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
|
||||
@@ -25,9 +25,6 @@ tokio-util = { workspace = true, features = ["codec"] }
|
||||
url = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
## tracing
|
||||
tracing = { version = "0.1.37", optional = true }
|
||||
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-sphinx-acknowledgements = { path = "../nymsphinx/acknowledgements" }
|
||||
@@ -39,9 +36,4 @@ nym-sphinx-types = { path = "../nymsphinx/types" }
|
||||
nym-task = { path = "../task" }
|
||||
nym-validator-client = { path = "../client-libs/validator-client" }
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
|
||||
cfg-if = "1.0.0"
|
||||
cpu-cycles = { path = "../../cpu-cycles", optional = true }
|
||||
|
||||
[features]
|
||||
cpucycles = ["cpu-cycles", "tracing"]
|
||||
nym-metrics = { path = "../nym-metrics" }
|
||||
|
||||
@@ -2,40 +2,3 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pub mod packet_processor;
|
||||
pub mod verloc;
|
||||
|
||||
pub fn cpu_cycles() -> Result<i64, Box<dyn std::error::Error>> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpucycles")] {
|
||||
Ok(cpu_cycles::cpucycles()?)
|
||||
} else {
|
||||
Err("`cpucycles` feature is not turned on!".into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! measure {
|
||||
( $x:expr ) => {{
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpucycles")] {
|
||||
let start_cycles = $crate::cpu_cycles();
|
||||
// if the block needs to return something, we can return it
|
||||
let r = $x;
|
||||
let end_cycles = $crate::cpu_cycles();
|
||||
let name = if let Some(meta) = tracing::Span::current().metadata() {
|
||||
meta.name()
|
||||
} else {
|
||||
"measure"
|
||||
};
|
||||
match (start_cycles, end_cycles) {
|
||||
(Ok(start), Ok(end)) => log::trace!("{} cpucycles: {}", name, end - start),
|
||||
(Err(e), _) => error!("{e}"),
|
||||
(_, Err(e)) => error!("{e}"),
|
||||
}
|
||||
r
|
||||
} else {
|
||||
$x
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::measure;
|
||||
use crate::packet_processor::error::MixProcessingError;
|
||||
use log::*;
|
||||
use nym_metrics::nanos;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
@@ -15,8 +15,6 @@ use nym_sphinx_types::{
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "cpucycles")]
|
||||
use tracing::instrument;
|
||||
|
||||
type ForwardAck = MixPacket;
|
||||
|
||||
@@ -51,15 +49,11 @@ impl SphinxPacketProcessor {
|
||||
}
|
||||
|
||||
/// Performs a fresh sphinx unwrapping using no cache.
|
||||
#[cfg_attr(
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, packet), fields(cpucycles))
|
||||
)]
|
||||
fn perform_initial_packet_processing(
|
||||
&self,
|
||||
packet: NymPacket,
|
||||
) -> Result<NymProcessedPacket, MixProcessingError> {
|
||||
measure!({
|
||||
nanos!("perform_initial_packet_processing", {
|
||||
packet.process(&self.sphinx_key).map_err(|err| {
|
||||
debug!("Failed to unwrap NymPacket packet: {err}");
|
||||
MixProcessingError::NymPacketProcessingError(err)
|
||||
@@ -68,17 +62,12 @@ impl SphinxPacketProcessor {
|
||||
}
|
||||
|
||||
/// Takes the received framed packet and tries to unwrap it from the sphinx encryption.
|
||||
#[cfg_attr(
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, received), fields(cpucycles))
|
||||
)]
|
||||
fn perform_initial_unwrapping(
|
||||
&self,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<NymProcessedPacket, MixProcessingError> {
|
||||
measure!({
|
||||
nanos!("perform_initial_unwrapping", {
|
||||
let packet = received.into_inner();
|
||||
|
||||
self.perform_initial_packet_processing(packet)
|
||||
})
|
||||
}
|
||||
@@ -223,16 +212,12 @@ impl SphinxPacketProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, received), fields(cpucycles))
|
||||
)]
|
||||
pub fn process_received(
|
||||
&self,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
// explicit packet size will help to correctly parse final hop
|
||||
measure!({
|
||||
nanos!("process_received", {
|
||||
let packet_size = received.packet_size();
|
||||
let packet_type = received.packet_type();
|
||||
|
||||
|
||||
@@ -185,6 +185,12 @@ impl NymNetworkDetails {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_chain_details(mut self, chain_details: ChainDetails) -> Self {
|
||||
self.chain_details = chain_details;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
|
||||
self.chain_details.bech32_account_prefix = prefix.into();
|
||||
@@ -227,6 +233,12 @@ impl NymNetworkDetails {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_contracts(mut self, contracts: NymContracts) -> Self {
|
||||
self.contracts = contracts;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_mixnet_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.mixnet_contract_address = contract.map(Into::into);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "nym-metrics"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
prometheus = { workspace = true }
|
||||
log = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
regex = "1.1"
|
||||
lazy_static = "1.4"
|
||||
@@ -0,0 +1,180 @@
|
||||
use dashmap::DashMap;
|
||||
pub use log::error;
|
||||
use log::{debug, warn};
|
||||
use regex::Regex;
|
||||
use std::fmt;
|
||||
pub use std::time::Instant;
|
||||
|
||||
use prometheus::{core::Collector, Counter, Encoder as _, Gauge, Registry, TextEncoder};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! nanos {
|
||||
( $name:literal, $x:expr ) => {{
|
||||
let start = $crate::Instant::now();
|
||||
// if the block needs to return something, we can return it
|
||||
let r = $x;
|
||||
let duration = start.elapsed().as_nanos() as f64;
|
||||
$crate::REGISTRY.inc_by(&format!("{}_nanos", $name), duration);
|
||||
r
|
||||
}};
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref RE: Regex = Regex::new(r"[^a-zA-Z0-9_]").unwrap();
|
||||
pub static ref REGISTRY: MetricsController = MetricsController::default();
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MetricsController {
|
||||
registry: Registry,
|
||||
registry_index: DashMap<String, Metric>,
|
||||
}
|
||||
|
||||
enum Metric {
|
||||
C(Box<Counter>),
|
||||
G(Box<Gauge>),
|
||||
}
|
||||
|
||||
fn fq_name(c: &dyn Collector) -> String {
|
||||
c.desc()
|
||||
.first()
|
||||
.map(|d| d.fq_name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
impl Metric {
|
||||
fn fq_name(&self) -> String {
|
||||
match self {
|
||||
Metric::C(c) => fq_name(c.as_ref()),
|
||||
Metric::G(g) => fq_name(g.as_ref()),
|
||||
}
|
||||
}
|
||||
|
||||
fn inc_by(&self, value: f64) {
|
||||
match self {
|
||||
Metric::C(c) => c.inc_by(value),
|
||||
Metric::G(g) => g.add(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&self, value: f64) {
|
||||
match self {
|
||||
Metric::C(_c) => {
|
||||
warn!("Cannot set value for counter {:?}", self.fq_name());
|
||||
}
|
||||
Metric::G(g) => g.set(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MetricsController {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut buffer = vec![];
|
||||
let encoder = TextEncoder::new();
|
||||
let metrics = self.registry.gather();
|
||||
match encoder.encode(&metrics, &mut buffer) {
|
||||
Ok(_) => {}
|
||||
Err(e) => return write!(f, "Error encoding metrics to buffer: {}", e),
|
||||
}
|
||||
let output = match String::from_utf8(buffer) {
|
||||
Ok(output) => output,
|
||||
Err(e) => return write!(f, "Error decoding metrics to String: {}", e),
|
||||
};
|
||||
write!(f, "{}", output)
|
||||
}
|
||||
}
|
||||
|
||||
impl MetricsController {
|
||||
pub fn set(&self, name: &str, value: f64) {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.set(value);
|
||||
} else {
|
||||
let gauge = match Gauge::new(sanitize_metric_name(name), name) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
debug!("Failed to create gauge {:?}:\n{}", name, e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.register_gauge(Box::new(gauge));
|
||||
self.set(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inc_by(&self, name: &str, value: f64) {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.inc_by(value);
|
||||
} else {
|
||||
let counter = match Counter::new(sanitize_metric_name(name), name) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
debug!("Failed to create counter {:?}:\n{}", name, e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.register_counter(Box::new(counter));
|
||||
self.inc_by(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn register_gauge(&self, metric: Box<Gauge>) {
|
||||
let fq_name = metric
|
||||
.desc()
|
||||
.first()
|
||||
.map(|d| d.fq_name.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.registry_index.contains_key(&fq_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.registry.register(metric.clone()) {
|
||||
Ok(_) => {
|
||||
self.registry_index
|
||||
.insert(fq_name, Metric::G(metric.clone()));
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Failed to register {:?}:\n{}", fq_name, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn register_counter(&self, metric: Box<Counter>) {
|
||||
let fq_name = metric
|
||||
.desc()
|
||||
.first()
|
||||
.map(|d| d.fq_name.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.registry_index.contains_key(&fq_name) {
|
||||
return;
|
||||
}
|
||||
match self.registry.register(metric.clone()) {
|
||||
Ok(_) => {
|
||||
self.registry_index
|
||||
.insert(fq_name, Metric::C(metric.clone()));
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Failed to register {:?}:\n{}", fq_name, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn sanitize_metric_name(name: &str) -> String {
|
||||
RE.replace_all(name, "_").to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_sanitization() {
|
||||
assert_eq!(
|
||||
sanitize_metric_name("packets_sent_34.242.65.133:1789"),
|
||||
"packets_sent_34_242_65_133_1789"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ use nym_client_core::init::types::GatewaySetup;
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::manager::TaskStatus;
|
||||
use nym_task::{TaskClient, TaskHandle};
|
||||
|
||||
use anyhow::anyhow;
|
||||
@@ -177,7 +178,9 @@ where
|
||||
))?;
|
||||
|
||||
// Listen to status messages from task, that we forward back to the caller
|
||||
shutdown.start_status_listener(sender).await;
|
||||
shutdown
|
||||
.start_status_listener(sender, TaskStatus::Ready)
|
||||
.await;
|
||||
|
||||
let res = tokio::select! {
|
||||
biased;
|
||||
|
||||
@@ -46,6 +46,8 @@ enum TaskError {
|
||||
pub enum TaskStatus {
|
||||
#[error("Ready")]
|
||||
Ready,
|
||||
#[error("Ready and connected to gateway: {0}")]
|
||||
ReadyWithGateway(String),
|
||||
}
|
||||
|
||||
/// Listens to status and error messages from tasks, as well as notifying them to gracefully
|
||||
@@ -161,10 +163,14 @@ impl TaskManager {
|
||||
self.notify_tx.send(())
|
||||
}
|
||||
|
||||
pub async fn start_status_listener(&mut self, mut sender: StatusSender) {
|
||||
pub async fn start_status_listener(
|
||||
&mut self,
|
||||
mut sender: StatusSender,
|
||||
start_status: TaskStatus,
|
||||
) {
|
||||
// Announce that we are operational. This means that in the application where this is used,
|
||||
// everything is up and running and ready to go.
|
||||
if let Err(msg) = sender.send(Box::new(TaskStatus::Ready)).await {
|
||||
if let Err(msg) = sender.send(Box::new(start_status)).await {
|
||||
log::error!("Error sending status message: {}", msg);
|
||||
};
|
||||
|
||||
|
||||
@@ -31,9 +31,13 @@ assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
minimum_rust_version = "1.66"
|
||||
wallet_release_version = "1.2.8"
|
||||
# nym-vpn related variables
|
||||
nym_vpn_latest_binary_url = "https://github.com/nymtech/nym/releases/tag/nym-vpn-alpha-0.0.4"
|
||||
nym_vpn_releases = "https://github.com/nymtech/nym-vpn-client/releases"
|
||||
nym_vpn_form_url = "https://opnform.com/forms/nymvpn-user-research-at-37c3-yccqko-2"
|
||||
|
||||
# versions are pulled by cmdrun now
|
||||
# nym_vpn_gui_version = "0.0.6"
|
||||
# nym_vpn_cli_version = "0.0.4"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
command = "mdbook-last-changed"
|
||||
renderer = ["html"]
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
- [CLI](nymvpn/cli.md)
|
||||
- [Linux](nymvpn/cli-linux.md)
|
||||
- [MacOS](nymvpn/cli-mac.md)
|
||||
- [Testing](nymvpn/testing.md)
|
||||
- [Troubleshooting](nymvpn/troubleshooting.md)
|
||||
- [NymVPN FAQ](nymvpn/faq.md)
|
||||
- [NymConnect X Monero](tutorials/monero.md)
|
||||
|
||||
@@ -8,25 +8,29 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for Debian based Linux
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the binary for Debian based Linux
|
||||
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_0.1.0_ubuntu-22.04_amd64.zip" | shasum -a 256 -c
|
||||
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_amd64.tar.gz" | shasum -a 256 -c
|
||||
```
|
||||
1. Extract files:
|
||||
|
||||
3. Extract files:
|
||||
```sh
|
||||
tar -xvf <BINARY>
|
||||
tar -xvf <BINARY>.tar.gz
|
||||
# for example
|
||||
# tar -xvf nym-vpn-cli_0.0.2_ubuntu-22.04_x86_64.tar.gz
|
||||
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
|
||||
```
|
||||
2. Make executable by running:
|
||||
|
||||
4. Make executable by running:
|
||||
```sh
|
||||
# possibly you may have to cd into a sub-directory
|
||||
# make sure you are in the right sub-directory
|
||||
chmod u+x ./nym-vpn-cli
|
||||
```
|
||||
|
||||
5. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
```sh
|
||||
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
|
||||
@@ -8,19 +8,19 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for MacOS
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the binary for MacOS
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
# echo "96623ccc69bc4cc0e4e3e18528b6dae6be69f645d0a592d926a3158ce2d0c269 nym-vpn-cli_0.1.0_macos_x86_64.zip" | shasum -a 256 -c
|
||||
# echo "96623ccc69bc4cc0e4e3e18528b6dae6be69f645d0a592d926a3158ce2d0c269 nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_macos_x86_64.zip" | shasum -a 256 -c
|
||||
```
|
||||
3. Extract files:
|
||||
```sh
|
||||
tar -xvf <BINARY>
|
||||
# for example
|
||||
# tar -xvf nym-vpn-cli_0.0.2_macos_aarch64.tar.gz
|
||||
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_macos_aarch64.tar.gz
|
||||
```
|
||||
4. Make executable by running:
|
||||
```sh
|
||||
|
||||
@@ -5,33 +5,22 @@ Our alpha testing round is done with participants at live workshop events. This
|
||||
|
||||
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
|
||||
```
|
||||
|
||||
NymVPN CLI is a fundamental way to run the client for different purposes, currently it is a must for users who want to run the [testing scripts](testing.md).
|
||||
|
||||
Follow the simple [automated script](#automated-script-for-cli-installation) below to install and run NymVPN CLI. If you prefer to do a manual setup follow the steps in the guide for [Linux](cli-linux.md) or [MacOS](cli-mac.md).
|
||||
|
||||
Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums or download the binaries directly.
|
||||
|
||||
## Automated Script for CLI Installation
|
||||
|
||||
We wrote a [script](https://gist.github.com/serinko/d65450653d6bbafacbcee71c9cb8fb31) which does download of the CLI, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
|
||||
1. Open a terminal window in a directory where you want the script and NymVPN CLI binary be downloaded and run
|
||||
```sh
|
||||
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/serinko/d65450653d6bbafacbcee71c9cb8fb31/raw/0cbcdd18f7ee94f559692b936061248ebbbf2773/execute-nym-vpn-cli-binary.sh
|
||||
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/serinko/d65450653d6bbafacbcee71c9cb8fb31/raw/4b70371fb000fd08910c0f778e78566d002e1319/execute-nym-vpn-cli-binary.sh && chmod u+x execute-nym-vpn-cli-binary.sh && sudo -E ./execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
|
||||
2. Make the script executable
|
||||
```sh
|
||||
chmod u+x execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
2. Follow the prompts in the program
|
||||
|
||||
3. Start the script, turn off any VPN and run
|
||||
```sh
|
||||
sudo -E ./execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
|
||||
4. Follow the prompts in the program
|
||||
|
||||
5. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
|
||||
3. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
|
||||
|
||||
* It prints a JSON view of existing Gateways and prompt you to:
|
||||
- *Make sure to use two different Gateways for entry and exit!*
|
||||
|
||||
@@ -12,33 +12,35 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
|
||||
### Installation
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for Debian based Linux
|
||||
2. Required (if you don't want to check shasum, skip this point): Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the binary for Debian based Linux
|
||||
|
||||
2. Required (if you don't want to check shasum, skip this point): Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
# echo "a5f91f20d587975e30b6a75d3a9e195234cf1269eac278139a5b9c39b039e807 nym-vpn-desktop_0.0.3_ubuntu-22.04_x86_64.zip" | shasum -a 256 -c
|
||||
# echo "a5f91f20d587975e30b6a75d3a9e195234cf1269eac278139a5b9c39b039e807 nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_ubuntu-22.04_x86_64.tar.gz" | shasum -a 256 -c
|
||||
```
|
||||
|
||||
3. Extract files:
|
||||
```sh
|
||||
tar -xvf <BINARY>
|
||||
tar -xvf <BINARY>.tar.gz
|
||||
# for example
|
||||
# tar -xvf nym-vpn-desktop_0.0.4_ubuntu-22.04_x86_64.tar.gz
|
||||
# tar -xvf nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_ubuntu-22.04_x86_64.tar.gz
|
||||
```
|
||||
|
||||
4. If you prefer to run `.AppImage` make executable by running:
|
||||
```sh
|
||||
# make sure you cd into the right sub-directory after extraction
|
||||
chmod u+x ./appimage/nym-vpn_0.0.4_amd64.AppImage
|
||||
chmod u+x ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.AppImage
|
||||
```
|
||||
|
||||
5. If you prefer to use the `.deb` version for installation (works on Debian based Linux only), open terminal in the same directory and run:
|
||||
```sh
|
||||
cd deb
|
||||
|
||||
sudo dpkg -i ./nym-vpn_0.0.4_amd64.deb
|
||||
# make sure you cd into the right sub-directory after extraction
|
||||
sudo dpkg -i ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.deb
|
||||
# or
|
||||
sudo apt-get install -f ./nym-vpn_0.0.4_amd64.deb
|
||||
sudo apt-get install -f ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.deb
|
||||
```
|
||||
|
||||
NymVPN alpha version runs over Nym testnet (called sandbox), a little extra configuration is needed for the application to work.
|
||||
@@ -72,7 +74,7 @@ Open terminal and run:
|
||||
|
||||
```sh
|
||||
# .AppImage must be run from the same directory as the binary
|
||||
sudo -E ./nym-vpn_0.0.4_amd64.AppImage
|
||||
sudo -E ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.AppImage
|
||||
|
||||
# .deb installation shall be executable from anywhere as
|
||||
sudo -E nym-vpn
|
||||
|
||||
@@ -17,21 +17,21 @@ mkdir -p "$HOME/nym-vpn-latest"
|
||||
```
|
||||
-->
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for your version of MacOS
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the binary for your version of MacOS
|
||||
|
||||
2. Recommended (skip this point if you don't want to verify): Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
2. Recommended (skip this point if you don't want to verify): Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
# echo "da4c0bf8e8b52658312d341fa3581954cfcb6efd516d9a448c76d042a454b5df nym-vpn-desktop_0.0.3_macos_x86_64.zip" | shasum -a 256 -c
|
||||
# echo "da4c0bf8e8b52658312d341fa3581954cfcb6efd516d9a448c76d042a454b5df nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_macos_x86_64.zip" | shasum -a 256 -c
|
||||
```
|
||||
|
||||
3. Extract the downloaded file manually or by a command:
|
||||
```sh
|
||||
tar -xvf <BINARY>
|
||||
tar -xvf <BINARY>.tar.gz
|
||||
# for example
|
||||
# tar -xvf nym-vpn-desktop_0.0.4_macos_aarch64.tar.gz
|
||||
# tar -xvf nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_macos_aarch64.tar.gz
|
||||
```
|
||||
<!-- seems redundant
|
||||
5. Move to the application content directory:
|
||||
@@ -71,7 +71,7 @@ env_config_file = "sandbox.env"
|
||||
```
|
||||
Alternatively do it by using this command:
|
||||
```sh
|
||||
echo "env_config_file = sandbox.env" > /Applications/nym-vpn.app/Contents/MacOS//config.toml
|
||||
echo "env_config_file = sandbox.env" > /Applications/nym-vpn.app/Contents/MacOS/config.toml
|
||||
```
|
||||
## Run NymVPN
|
||||
|
||||
|
||||
@@ -10,23 +10,26 @@ This is the alpha version of NymVPN desktop application (GUI). A demo of how the
|
||||
|
||||
Follow the simple [automated script](#automated-script-for-gui-installation) below to install and run NymVPN GUI. If the script didn't work for your distribution or you prefer to do a manual setup follow the steps in the guide for [Linux](gui-linux.md) or [MacOS](gui-mac.md) .
|
||||
|
||||
Visit NymVPN alpha latest [release page]({{nym_vpn_latest_binary_url}}) to check sha sums or download the binaries directly.
|
||||
Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums or download the binaries directly.
|
||||
|
||||
## Automated Script for GUI Installation
|
||||
|
||||
We wrote a [script](https://gist.github.com/serinko/e0a9f7ff3d79e974ec6f6783caa1137e) which does download of dependencies and the application, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically. Turn off all VPNs and follow the steps below.
|
||||
We wrote a [script](https://gist.github.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19) which does download of dependencies and the application, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically. Turn off all VPNs and follow the steps below.
|
||||
|
||||
1. Open a terminal window in a directory where you want the script to be downloaded and run
|
||||
```sh
|
||||
curl -o nym-vpn-desktop-install-run.sh -L https://gist.githubusercontent.com/serinko/e0a9f7ff3d79e974ec6f6783caa1137e/raw/227c8c348a1e58f68cb500e4504b22412177c680/nym-vpn-desktop-install-run.sh && chmod u+x nym-vpn-desktop-install-run.sh && sudo -E ./nym-vpn-desktop-install-run.sh
|
||||
curl -o nym-vpn-desktop-install-run.sh -L https://gist.githubusercontent.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19/raw/6c81619ec26b092dfa174bce79335f4163c657ff/nym-vpn-client-install-run.sh && chmod u+x nym-vpn-desktop-install-run.sh && sudo -E ./nym-vpn-desktop-install-run.sh
|
||||
```
|
||||
|
||||
2. Follow the prompts in the program
|
||||
|
||||
To start the application again, reconnect your wifi and run
|
||||
```sh
|
||||
# Linux
|
||||
sudo -E ~/nym-vpn-latest/nym-vpn_0.0.4_amd64.AppImage
|
||||
# Linux .AppImage
|
||||
sudo -E ~/nym-vpn-latest/nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_ubuntu-22.04_x86_64/nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.AppImage
|
||||
|
||||
# Linux .deb
|
||||
sudo -E nym-vpn
|
||||
|
||||
# MacOS
|
||||
sudo -E $HOME/nym-vpn-latest/nym-vpn
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
**Nym proudly presents NymVPN alpha** - a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
|
||||
|
||||
|
||||
**You are invited to take part in the alpha testing** of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN [CLI](cli.md) and [GUI](gui.md) on the Sandbox testnet environment as well as provide some scripts for [qualitative testing](testing.md).
|
||||
**You are invited to take part in the alpha testing** of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN [CLI](cli.md) and [GUI](gui.md) on the Sandbox testnet environment.
|
||||
|
||||
**Here is how**
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
2. Please consent to the GDPR so we can use the results
|
||||
3. To test the GUI, [go here](gui.md)
|
||||
4. To test the CLI, [go here](cli.md)
|
||||
5. Run [qualitative testing script](testing.md)
|
||||
6. Fill and submit the [form!]({{nym_vpn_form_url}})
|
||||
7. Join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers
|
||||
5. Fill and submit the [form!]({{nym_vpn_form_url}})
|
||||
6. Join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers
|
||||
|
||||
***NymVPN alpha testing will last from 15th of January - 15th of February.***
|
||||
|
||||
*NOTE: NymVPN alpha is experimental software for [testing purposes](testing.md) only.*
|
||||
*NOTE: NymVPN alpha is experimental software for testing purposes only.*
|
||||
|
||||
|
||||
## NymVPN Overview
|
||||
@@ -45,10 +44,9 @@ The client can optionally do the first hop (local client to Entry Gateway) using
|
||||
## NymVPN Resources & Guides
|
||||
|
||||
* [NymVPN webpage](https://nymvpn.com)
|
||||
* [Alpha release page]({{nym_vpn_latest_binary_url}})
|
||||
* [Alpha release page]({{nym_vpn_releases}})
|
||||
* [NymVPN application (GUI) guide](gui.md)
|
||||
* [NymVPN Command Line Interface (CLI) guide](cli.md)
|
||||
* [Testing scripts](testing.md)
|
||||
* [Troubleshooting](troubleshooting.md)
|
||||
* [NymVPN FAQ](faq.md)
|
||||
* [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat)
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# NymVPN alpha - Desktop: Guide for Mac OS
|
||||
|
||||
```admonish info
|
||||
NymVPN is an experimental software and it's for [testing](./testing.md) purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
|
||||
```
|
||||
|
||||
## Preparation
|
||||
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
### Installation
|
||||
|
||||
1. Create a directory `~/nym-vpn-latest`
|
||||
```sh
|
||||
mkdir -p "$HOME/nym-vpn-latest"
|
||||
```
|
||||
2. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for MacOS
|
||||
3. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
# echo "da4c0bf8e8b52658312d341fa3581954cfcb6efd516d9a448c76d042a454b5df nym-vpn-desktop_0.0.3_macos_x86_64.zip" | shasum -a 256 -c
|
||||
```
|
||||
4. Extract files:
|
||||
```sh
|
||||
tar -xvf <BINARY>
|
||||
# for example
|
||||
# tar -xvf nym-vpn-desktop_0.0.4_macos_aarch64.tar.gz
|
||||
```
|
||||
5. Move to the application directory and make executable
|
||||
```sh
|
||||
cd "macos/nym-vpn.app/Contents/MacOS"
|
||||
|
||||
chmod u+x nym-vpn
|
||||
```
|
||||
6. Move `nym-vpn` to your `~/nym-vpn-latest` directory
|
||||
```sh
|
||||
mv nym-vpn "$HOME/nym-vpn-latest"
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
7. Create the configuration file by opening a text editor and saving the lines below as `config.toml` in the same directory `~/nym-vpn-latest`
|
||||
```toml
|
||||
env_config_file = ".env"
|
||||
```
|
||||
8. Create testnet configuration file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `.env` in the same directory `~/nym-vpn-latest`
|
||||
```sh
|
||||
curl -L "https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env" -o "$HOME/nym-vpn-latest/.env"
|
||||
```
|
||||
## Run NymVPN
|
||||
|
||||
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
|
||||
|
||||
Run:
|
||||
```sh
|
||||
sudo -E $HOME/nym-vpn-latest/nym-vpn
|
||||
```
|
||||
|
||||
In case of errors check out the [troubleshooting](troubleshooting.html#installing-gui-on-macos-not-working) section.
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
release_url="https://api.github.com/repos/nymtech/nym-vpn-client/releases"
|
||||
current_cli_version=$(curl -s $release_url | jq -r '.[].tag_name' | grep '^nym-vpn-cli-v' | sort -Vr | head -n 1 | awk -F'-v' '{print $NF}')
|
||||
|
||||
echo "${current_cli_version}"
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
release_url="https://api.github.com/repos/nymtech/nym-vpn-client/releases"
|
||||
version=$(curl -s $release_url | jq -r '.[].tag_name' | grep '^nym-vpn-desktop-v' | sort -Vr | head -n 1 | awk -F'-v' '{print $NF}')
|
||||
|
||||
echo "${version}"
|
||||
@@ -14,7 +14,7 @@ One of the main aims of NymVPN alpha release is testing; your results will help
|
||||
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Create a directory called `nym-vpn-tests` and copy your `nym-vpn-cli` binary ([download here]({{nym_vpn_latest_binary_url}}))
|
||||
1. Create a directory called `nym-vpn-tests` and copy your `nym-vpn-cli` binary ([download here]({{nym_vpn_releases}}))
|
||||
2. Copy or download [`sandbox.env`](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) testnet config file to the same directory
|
||||
```sh
|
||||
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
|
||||
@@ -46,6 +46,8 @@ If you are running NymVPN on mac OS for the first time, you may see this alert m
|
||||
|
||||
3. Possibly you may have to confirm again upon running the application
|
||||
|
||||
<!--
|
||||
|
||||
#### Missing `jq` error
|
||||
|
||||
In case of missing `jq` on Linux (Debian) install it with:
|
||||
@@ -84,3 +86,4 @@ NEW_ENDPOINT="http://localhost:8000/data.json"
|
||||
python3 -m http.server 8000
|
||||
```
|
||||
6. Continue with the steps listed in [testing section](testing.md)
|
||||
-->
|
||||
|
||||
@@ -6,7 +6,9 @@ use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
// Re-export request types
|
||||
pub use nym_explorer_api_requests::{PrettyDetailedGatewayBond, PrettyDetailedMixNodeBond};
|
||||
pub use nym_explorer_api_requests::{
|
||||
Location, PrettyDetailedGatewayBond, PrettyDetailedMixNodeBond,
|
||||
};
|
||||
|
||||
// Paths
|
||||
const API_VERSION: &str = "v1";
|
||||
|
||||
@@ -28,6 +28,14 @@ nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credentials-interface = { path = "../../common/credentials-interface" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
|
||||
workspace = true
|
||||
features = ["time"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
|
||||
[dependencies.tungstenite]
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
@@ -13,7 +13,7 @@ pub mod models;
|
||||
pub mod registration;
|
||||
pub mod types;
|
||||
|
||||
pub const CURRENT_PROTOCOL_VERSION: u8 = CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION;
|
||||
pub const CURRENT_PROTOCOL_VERSION: u8 = CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION;
|
||||
|
||||
/// Defines the current version of the communication protocol between gateway and clients.
|
||||
/// It has to be incremented for any breaking change.
|
||||
@@ -21,7 +21,7 @@ pub const CURRENT_PROTOCOL_VERSION: u8 = CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION;
|
||||
// 1 - initial release
|
||||
// 2 - changes to client credentials structure
|
||||
pub const INITIAL_PROTOCOL_VERSION: u8 = 1;
|
||||
pub const CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION: u8 = 2;
|
||||
pub const CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION: u8 = 2;
|
||||
|
||||
pub type GatewayMac = HmacOutput<GatewayIntegrityHmacAlgorithm>;
|
||||
|
||||
|
||||
@@ -24,11 +24,18 @@ impl<'a> ClientHandshake<'a> {
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a nym_crypto::asymmetric::identity::KeyPair,
|
||||
gateway_pubkey: identity::PublicKey,
|
||||
expects_credential_usage: bool,
|
||||
) -> Self
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
{
|
||||
let mut state = State::new(rng, ws_stream, identity, Some(gateway_pubkey));
|
||||
let mut state = State::new(
|
||||
rng,
|
||||
ws_stream,
|
||||
identity,
|
||||
Some(gateway_pubkey),
|
||||
expects_credential_usage,
|
||||
);
|
||||
|
||||
ClientHandshake {
|
||||
handshake_future: Box::pin(async move {
|
||||
|
||||
@@ -25,4 +25,7 @@ pub enum HandshakeError {
|
||||
MalformedRequest,
|
||||
#[error("sent request was malformed")]
|
||||
HandshakeFailure,
|
||||
|
||||
#[error("timed out waiting for a handshake message")]
|
||||
Timeout,
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ impl<'a> GatewayHandshake<'a> {
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
{
|
||||
let mut state = State::new(rng, ws_stream, identity, None);
|
||||
let mut state = State::new(rng, ws_stream, identity, None, true);
|
||||
GatewayHandshake {
|
||||
handshake_future: Box::pin(async move {
|
||||
// If any step along the way failed (that are non-network related),
|
||||
|
||||
@@ -30,11 +30,19 @@ pub async fn client_handshake<'a, S>(
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a identity::KeyPair,
|
||||
gateway_pubkey: identity::PublicKey,
|
||||
expects_credential_usage: bool,
|
||||
) -> Result<SharedKeys, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
{
|
||||
ClientHandshake::new(rng, ws_stream, identity, gateway_pubkey).await
|
||||
ClientHandshake::new(
|
||||
rng,
|
||||
ws_stream,
|
||||
identity,
|
||||
gateway_pubkey,
|
||||
expects_credential_usage,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2020-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::registration::handshake::error::HandshakeError;
|
||||
@@ -15,9 +15,17 @@ use nym_crypto::{
|
||||
};
|
||||
use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use tungstenite::Message as WsMessage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::timeout;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::timeout;
|
||||
|
||||
/// Handshake state.
|
||||
pub(crate) struct State<'a, S> {
|
||||
/// The underlying WebSocket stream.
|
||||
@@ -36,6 +44,10 @@ pub(crate) struct State<'a, S> {
|
||||
/// The known or received public identity key of the remote.
|
||||
/// Ideally it would always be known before the handshake was initiated.
|
||||
remote_pubkey: Option<identity::PublicKey>,
|
||||
|
||||
// this field is really out of place here, however, we need to propagate this information somehow
|
||||
// in order to establish correct protocol for backwards compatibility reasons
|
||||
expects_credential_usage: bool,
|
||||
}
|
||||
|
||||
impl<'a, S> State<'a, S> {
|
||||
@@ -44,6 +56,7 @@ impl<'a, S> State<'a, S> {
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a identity::KeyPair,
|
||||
remote_pubkey: Option<identity::PublicKey>,
|
||||
expects_credential_usage: bool,
|
||||
) -> Self {
|
||||
let ephemeral_keypair = encryption::KeyPair::new(rng);
|
||||
State {
|
||||
@@ -52,6 +65,7 @@ impl<'a, S> State<'a, S> {
|
||||
identity,
|
||||
remote_pubkey,
|
||||
derived_shared_keys: None,
|
||||
expects_credential_usage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,15 +81,8 @@ impl<'a, S> State<'a, S> {
|
||||
self.identity
|
||||
.public_key()
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(
|
||||
self.ephemeral_keypair
|
||||
.public_key()
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.into_iter()
|
||||
.chain(self.ephemeral_keypair.public_key().to_bytes())
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -132,9 +139,8 @@ impl<'a, S> State<'a, S> {
|
||||
.ephemeral_keypair
|
||||
.public_key()
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(remote_ephemeral_key.to_bytes().iter().cloned())
|
||||
.into_iter()
|
||||
.chain(remote_ephemeral_key.to_bytes())
|
||||
.collect();
|
||||
|
||||
let signature = self.identity.private_key().sign(message);
|
||||
@@ -177,15 +183,8 @@ impl<'a, S> State<'a, S> {
|
||||
// g^y || g^x, if y is remote and x is local
|
||||
let signed_payload: Vec<_> = remote_ephemeral_key
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(
|
||||
self.ephemeral_keypair
|
||||
.public_key()
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.into_iter()
|
||||
.chain(self.ephemeral_keypair.public_key().to_bytes())
|
||||
.collect();
|
||||
|
||||
self.remote_pubkey
|
||||
@@ -200,35 +199,56 @@ impl<'a, S> State<'a, S> {
|
||||
self.remote_pubkey = Some(remote_pubkey)
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_handshake_message(&mut self) -> Result<Vec<u8>, HandshakeError>
|
||||
async fn _receive_handshake_message(&mut self) -> Result<Vec<u8>, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Unpin,
|
||||
{
|
||||
loop {
|
||||
if let Some(msg) = self.ws_stream.next().await {
|
||||
if let Ok(msg) = msg {
|
||||
match msg {
|
||||
WsMessage::Text(ws_msg) => match types::RegistrationHandshake::try_from(ws_msg) {
|
||||
Ok(reg_handshake_msg) => return match reg_handshake_msg {
|
||||
let Some(msg) = self.ws_stream.next().await else {
|
||||
return Err(HandshakeError::ClosedStream);
|
||||
};
|
||||
|
||||
let Ok(msg) = msg else {
|
||||
return Err(HandshakeError::NetworkError);
|
||||
};
|
||||
|
||||
match msg {
|
||||
WsMessage::Text(ref ws_msg) => {
|
||||
match types::RegistrationHandshake::from_str(ws_msg) {
|
||||
Ok(reg_handshake_msg) => {
|
||||
return match reg_handshake_msg {
|
||||
// hehe, that's a bit disgusting that the type system requires we explicitly ignore the
|
||||
// protocol_version field that we actually never attach at this point
|
||||
// yet another reason for the overdue refactor
|
||||
types::RegistrationHandshake::HandshakePayload { data, .. } => Ok(data),
|
||||
types::RegistrationHandshake::HandshakeError { message } => Err(HandshakeError::RemoteError(message)),
|
||||
},
|
||||
Err(_) => error!("Received a non-handshake message during the registration handshake! It's getting dropped."),
|
||||
},
|
||||
_ => error!("Received non-text message during registration handshake"),
|
||||
types::RegistrationHandshake::HandshakePayload { data, .. } => {
|
||||
Ok(data)
|
||||
}
|
||||
types::RegistrationHandshake::HandshakeError { message } => {
|
||||
Err(HandshakeError::RemoteError(message))
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(_) => {
|
||||
error!("Received a non-handshake message during the registration handshake! It's getting dropped. The received content was: '{msg}'");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(HandshakeError::NetworkError);
|
||||
}
|
||||
} else {
|
||||
return Err(HandshakeError::ClosedStream);
|
||||
_ => error!("Received non-text message during registration handshake"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_handshake_message(&mut self) -> Result<Vec<u8>, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Unpin,
|
||||
{
|
||||
// TODO: make timeout duration configurable
|
||||
timeout(Duration::from_secs(5), self._receive_handshake_message())
|
||||
.await
|
||||
.map_err(|_| HandshakeError::Timeout)?
|
||||
}
|
||||
|
||||
// upon receiving this, the receiver should terminate the handshake
|
||||
pub(crate) async fn send_handshake_error<M: Into<String>>(
|
||||
&mut self,
|
||||
@@ -251,7 +271,8 @@ impl<'a, S> State<'a, S> {
|
||||
where
|
||||
S: Sink<WsMessage> + Unpin,
|
||||
{
|
||||
let handshake_message = types::RegistrationHandshake::new_payload(payload);
|
||||
let handshake_message =
|
||||
types::RegistrationHandshake::new_payload(payload, self.expects_credential_usage);
|
||||
self.ws_stream
|
||||
.send(WsMessage::Text(handshake_message.try_into().unwrap()))
|
||||
.await
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::authentication::encrypted_address::EncryptedAddressBytes;
|
||||
use crate::iv::IV;
|
||||
use crate::models::{CredentialSpendingRequest, OldV1Credential};
|
||||
use crate::registration::handshake::SharedKeys;
|
||||
use crate::{GatewayMacSize, CURRENT_PROTOCOL_VERSION};
|
||||
use crate::{GatewayMacSize, CURRENT_PROTOCOL_VERSION, INITIAL_PROTOCOL_VERSION};
|
||||
use log::error;
|
||||
use nym_credentials::coconut::bandwidth::CredentialSpendingData;
|
||||
use nym_credentials_interface::{CoconutError, UnknownCredentialType};
|
||||
@@ -19,6 +19,7 @@ use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewayIntegrityHmacAlgorit
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::str::FromStr;
|
||||
use std::string::FromUtf8Error;
|
||||
use thiserror::Error;
|
||||
use tungstenite::protocol::Message;
|
||||
@@ -37,9 +38,17 @@ pub enum RegistrationHandshake {
|
||||
}
|
||||
|
||||
impl RegistrationHandshake {
|
||||
pub fn new_payload(data: Vec<u8>) -> Self {
|
||||
pub fn new_payload(data: Vec<u8>, will_use_credentials: bool) -> Self {
|
||||
// if we're not going to be using credentials, advertise lower protocol version to allow connection
|
||||
// to wider range of gateways
|
||||
let protocol_version = if will_use_credentials {
|
||||
Some(CURRENT_PROTOCOL_VERSION)
|
||||
} else {
|
||||
Some(INITIAL_PROTOCOL_VERSION)
|
||||
};
|
||||
|
||||
RegistrationHandshake::HandshakePayload {
|
||||
protocol_version: Some(CURRENT_PROTOCOL_VERSION),
|
||||
protocol_version,
|
||||
data,
|
||||
}
|
||||
}
|
||||
@@ -51,11 +60,19 @@ impl RegistrationHandshake {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for RegistrationHandshake {
|
||||
type Err = serde_json::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
serde_json::from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for RegistrationHandshake {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(msg: String) -> Result<Self, serde_json::Error> {
|
||||
serde_json::from_str(&msg)
|
||||
msg.parse()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,9 +172,18 @@ impl ClientControlRequest {
|
||||
address: DestinationAddressBytes,
|
||||
enc_address: EncryptedAddressBytes,
|
||||
iv: IV,
|
||||
uses_credentials: bool,
|
||||
) -> Self {
|
||||
// if we're not going to be using credentials, advertise lower protocol version to allow connection
|
||||
// to wider range of gateways
|
||||
let protocol_version = if uses_credentials {
|
||||
Some(CURRENT_PROTOCOL_VERSION)
|
||||
} else {
|
||||
Some(INITIAL_PROTOCOL_VERSION)
|
||||
};
|
||||
|
||||
ClientControlRequest::Authenticate {
|
||||
protocol_version: Some(CURRENT_PROTOCOL_VERSION),
|
||||
protocol_version,
|
||||
address: address.as_base58_string(),
|
||||
enc_address: enc_address.to_base58_string(),
|
||||
iv: iv.to_base58_string(),
|
||||
|
||||
@@ -88,18 +88,19 @@ impl OverrideConfig {
|
||||
if config.network_requester.enabled
|
||||
&& config.storage_paths.network_requester_config.is_none()
|
||||
{
|
||||
Ok(config.with_default_network_requester_config_path())
|
||||
} else if config.ip_packet_router.enabled
|
||||
&& config.storage_paths.ip_packet_router_config.is_none()
|
||||
{
|
||||
Ok(config.with_default_ip_packet_router_config_path())
|
||||
} else {
|
||||
Ok(config)
|
||||
config = config.with_default_network_requester_config_path();
|
||||
}
|
||||
|
||||
if config.ip_packet_router.enabled && config.storage_paths.ip_packet_router_config.is_none()
|
||||
{
|
||||
config = config.with_default_ip_packet_router_config_path();
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub(crate) struct OverrideNetworkRequesterConfig {
|
||||
pub(crate) fastmode: bool,
|
||||
pub(crate) no_cover: bool,
|
||||
@@ -112,7 +113,7 @@ pub(crate) struct OverrideNetworkRequesterConfig {
|
||||
pub(crate) statistics_recipient: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub(crate) struct OverrideIpPacketRouterConfig {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::{fs, io};
|
||||
|
||||
use super::helpers::OverrideIpPacketRouterConfig;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct Init {
|
||||
/// Id of the gateway we want to create config for
|
||||
#[clap(long)]
|
||||
@@ -82,11 +82,11 @@ pub struct Init {
|
||||
statistics_service_url: Option<url::Url>,
|
||||
|
||||
/// Allows this gateway to run an embedded network requester for minimal network overhead
|
||||
#[clap(long, conflicts_with = "with_ip_packet_router")]
|
||||
#[clap(long)]
|
||||
with_network_requester: bool,
|
||||
|
||||
/// Allows this gateway to run an embedded network requester for minimal network overhead
|
||||
#[clap(long, hide = true, conflicts_with = "with_network_requester")]
|
||||
#[clap(long, hide = true)]
|
||||
with_ip_packet_router: bool,
|
||||
|
||||
// ##### NETWORK REQUESTER FLAGS #####
|
||||
@@ -243,7 +243,9 @@ pub async fn execute(args: Init) -> anyhow::Result<()> {
|
||||
if config.network_requester.enabled {
|
||||
initialise_local_network_requester(&config, nr_opts, *identity_keys.public_key())
|
||||
.await?;
|
||||
} else if config.ip_packet_router.enabled {
|
||||
}
|
||||
|
||||
if config.ip_packet_router.enabled {
|
||||
initialise_local_ip_packet_router(&config, ip_opts, *identity_keys.public_key())
|
||||
.await?;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::Cli;
|
||||
use clap::CommandFactory;
|
||||
use clap::Subcommand;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use std::error::Error;
|
||||
|
||||
pub(crate) mod build_info;
|
||||
pub(crate) mod helpers;
|
||||
@@ -50,7 +49,7 @@ pub(crate) enum Commands {
|
||||
GenerateFigSpec,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
pub(crate) async fn execute(args: Cli) -> anyhow::Result<()> {
|
||||
let bin_name = "nym-gateway";
|
||||
|
||||
match args.command {
|
||||
|
||||
@@ -87,11 +87,11 @@ pub struct Run {
|
||||
statistics_service_url: Option<url::Url>,
|
||||
|
||||
/// Allows this gateway to run an embedded network requester for minimal network overhead
|
||||
#[arg(long, conflicts_with = "with_ip_packet_router")]
|
||||
#[arg(long)]
|
||||
with_network_requester: Option<bool>,
|
||||
|
||||
/// Allows this gateway to run an embedded network requester for minimal network overhead
|
||||
#[arg(long, hide = true, conflicts_with = "with_network_requester")]
|
||||
#[arg(long, hide = true)]
|
||||
with_ip_packet_router: Option<bool>,
|
||||
|
||||
// ##### NETWORK REQUESTER FLAGS #####
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@ use nym_bin_common::bin_info;
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_network_defaults::setup_env;
|
||||
use std::error::Error;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
mod commands;
|
||||
@@ -42,7 +41,7 @@ struct Cli {
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
setup_logging();
|
||||
|
||||
let args = Cli::parse();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use super::websocket::message_receiver::{IsActiveRequestSender, MixMessageSender};
|
||||
use crate::node::client_handling::embedded_network_requester::LocalNetworkRequesterHandle;
|
||||
use crate::node::client_handling::embedded_clients::LocalEmbeddedClientHandle;
|
||||
use dashmap::DashMap;
|
||||
use log::warn;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
@@ -12,8 +12,8 @@ enum ActiveClient {
|
||||
/// Handle to a remote client connected via a network socket.
|
||||
Remote(ClientIncomingChannels),
|
||||
|
||||
/// Handle to a locally (inside the same process) running network requester client.
|
||||
Embedded(LocalNetworkRequesterHandle),
|
||||
/// Handle to a locally (inside the same process) running client.
|
||||
Embedded(LocalEmbeddedClientHandle),
|
||||
}
|
||||
|
||||
impl ActiveClient {
|
||||
@@ -149,13 +149,14 @@ impl ActiveClientsStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a handle to the embedded network requester
|
||||
pub(crate) fn insert_embedded(&self, local_nr_handle: LocalNetworkRequesterHandle) {
|
||||
let key = local_nr_handle.client_destination();
|
||||
let entry = ActiveClient::Embedded(local_nr_handle);
|
||||
/// Inserts a handle to the embedded client
|
||||
pub(crate) fn insert_embedded(&self, local_client_handle: LocalEmbeddedClientHandle) {
|
||||
let key = local_client_handle.client_destination();
|
||||
let entry = ActiveClient::Embedded(local_client_handle);
|
||||
if self.inner.insert(key, entry).is_some() {
|
||||
// this is literally impossible since we're starting local NR before even spawning the websocket listener task
|
||||
panic!("somehow we already had a client with the same address as our local NR!")
|
||||
// this is literally impossible since we're starting the local embedded client before
|
||||
// even spawning the websocket listener task
|
||||
panic!("somehow we already had a client with the same address as our local embedded client!")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-22
@@ -12,15 +12,15 @@ use nym_sphinx::DestinationAddressBytes;
|
||||
use nym_task::TaskClient;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LocalNetworkRequesterHandle {
|
||||
/// Nym address of the embedded network requester.
|
||||
pub(crate) struct LocalEmbeddedClientHandle {
|
||||
/// Nym address of the embedded client.
|
||||
pub(crate) address: Recipient,
|
||||
|
||||
/// Message channel used internally to forward any received mix packets to the network requester.
|
||||
/// Message channel used internally to forward any received mix packets to the client.
|
||||
pub(crate) mix_message_sender: MixMessageSender,
|
||||
}
|
||||
|
||||
impl LocalNetworkRequesterHandle {
|
||||
impl LocalEmbeddedClientHandle {
|
||||
pub(crate) fn new(address: Recipient, mix_message_sender: MixMessageSender) -> Self {
|
||||
Self {
|
||||
address,
|
||||
@@ -28,17 +28,6 @@ impl LocalNetworkRequesterHandle {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: generalize this whole thing to be general. And change the name(s).
|
||||
pub(crate) fn new_ip(
|
||||
start_data: nym_ip_packet_router::OnStartData,
|
||||
mix_message_sender: MixMessageSender,
|
||||
) -> Self {
|
||||
Self {
|
||||
address: start_data.address,
|
||||
mix_message_sender,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn client_destination(&self) -> DestinationAddressBytes {
|
||||
self.address.identity().derive_destination_address()
|
||||
}
|
||||
@@ -48,8 +37,8 @@ impl LocalNetworkRequesterHandle {
|
||||
// calling the method. however, this would have caused slightly more complexity and more overhead
|
||||
// (due to more data being copied to every [mix] connection)
|
||||
//
|
||||
/// task responsible for receiving messages for locally NR requester from multiple mix connections
|
||||
/// and forwarding them via the router. kinda equivalent of a client socket handler
|
||||
/// task responsible for receiving messages for locally embedded clients from multiple mix
|
||||
/// connections and forwarding them via the router. kinda equivalent of a client socket handler
|
||||
pub(crate) struct MessageRouter {
|
||||
mix_receiver: MixMessageReceiver,
|
||||
packet_router: PacketRouter,
|
||||
@@ -71,29 +60,29 @@ impl MessageRouter {
|
||||
if let Err(err) = self.packet_router.route_received(messages) {
|
||||
// TODO: what should we do here? I don't think this could/should ever fail.
|
||||
// is panicking the appropriate thing to do then?
|
||||
error!("failed to route packets to local NR: {err}")
|
||||
error!("failed to route packets to local embedded client: {err}")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn run_with_shutdown(mut self, mut shutdown: TaskClient) {
|
||||
debug!("Started embedded network requester message router with graceful shutdown support");
|
||||
debug!("Started embedded client message router with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
messages = self.mix_receiver.next() => match messages {
|
||||
Some(messages) => self.handle_received_messages(messages),
|
||||
None => {
|
||||
log::trace!("embedded_network_requester::MessageRouter: Stopping since channel closed");
|
||||
log::trace!("embedded_clients::MessageRouter: Stopping since channel closed");
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("embedded_network_requester::MessageRouter: Received shutdown");
|
||||
log::trace!("embedded_clients::MessageRouter: Received shutdown");
|
||||
debug_assert!(shutdown.is_shutdown());
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("embedded_network_requester::MessageRouter: Exiting")
|
||||
debug!("embedded_network_clients::MessageRouter: Exiting")
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use crate::node::client_handling::bandwidth::Bandwidth;
|
||||
|
||||
pub(crate) mod active_clients;
|
||||
mod bandwidth;
|
||||
pub(crate) mod embedded_network_requester;
|
||||
pub(crate) mod embedded_clients;
|
||||
pub(crate) mod websocket;
|
||||
|
||||
pub(crate) const FREE_TESTNET_BANDWIDTH_VALUE: Bandwidth = Bandwidth::new(64 * 1024 * 1024 * 1024); // 64GB
|
||||
|
||||
+10
-21
@@ -11,9 +11,7 @@ use crate::config::Config;
|
||||
use crate::error::GatewayError;
|
||||
use crate::http::HttpApiBuilder;
|
||||
use crate::node::client_handling::active_clients::ActiveClientsStore;
|
||||
use crate::node::client_handling::embedded_network_requester::{
|
||||
LocalNetworkRequesterHandle, MessageRouter,
|
||||
};
|
||||
use crate::node::client_handling::embedded_clients::{LocalEmbeddedClientHandle, MessageRouter};
|
||||
use crate::node::client_handling::websocket;
|
||||
use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier;
|
||||
use crate::node::helpers::{initialise_main_storage, load_network_requester_config};
|
||||
@@ -51,7 +49,7 @@ struct StartedNetworkRequester {
|
||||
used_request_filter: RequestFilter,
|
||||
|
||||
/// Handle to interact with the local network requester
|
||||
handle: LocalNetworkRequesterHandle,
|
||||
handle: LocalEmbeddedClientHandle,
|
||||
}
|
||||
|
||||
/// Wire up and create Gateway instance
|
||||
@@ -80,7 +78,7 @@ pub(crate) async fn create_gateway(
|
||||
let cfg = load_ip_packet_router_config(&config.gateway.id, path)?;
|
||||
Some(override_ip_packet_router_config(cfg, ip_config_override))
|
||||
} else {
|
||||
// if NR is enabled, the config path must be specified
|
||||
// if IPR is enabled, the config path must be specified
|
||||
return Err(GatewayError::UnspecifiedIpPacketRouterConfig);
|
||||
}
|
||||
} else {
|
||||
@@ -319,7 +317,7 @@ impl<St> Gateway<St> {
|
||||
info!("the local network requester is running on {address}",);
|
||||
Ok(StartedNetworkRequester {
|
||||
used_request_filter: start_data.request_filter,
|
||||
handle: LocalNetworkRequesterHandle::new(address, nr_mix_sender),
|
||||
handle: LocalEmbeddedClientHandle::new(address, nr_mix_sender),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -327,17 +325,16 @@ impl<St> Gateway<St> {
|
||||
&self,
|
||||
forwarding_channel: MixForwardingSender,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<LocalNetworkRequesterHandle, GatewayError> {
|
||||
) -> Result<LocalEmbeddedClientHandle, GatewayError> {
|
||||
info!("Starting IP packet provider...");
|
||||
|
||||
// if network requester is enabled, configuration file must be provided!
|
||||
let Some(ip_opts) = &self.ip_packet_router_opts else {
|
||||
log::error!("IP packet router is enabled but no configuration file was provided!");
|
||||
return Err(GatewayError::UnspecifiedIpPacketRouterConfig);
|
||||
};
|
||||
|
||||
// this gateway, whenever it has anything to send to its local NR will use fake_client_tx
|
||||
let (nr_mix_sender, nr_mix_receiver) = mpsc::unbounded();
|
||||
let (ipr_mix_sender, ipr_mix_receiver) = mpsc::unbounded();
|
||||
let router_shutdown = shutdown.fork("message_router");
|
||||
|
||||
let (router_tx, mut router_rx) = oneshot::channel();
|
||||
@@ -348,7 +345,6 @@ impl<St> Gateway<St> {
|
||||
router_tx,
|
||||
);
|
||||
|
||||
// TODO: well, wire it up internally to gateway traffic, shutdowns, etc.
|
||||
let (on_start_tx, on_start_rx) = oneshot::channel();
|
||||
let mut ip_packet_router =
|
||||
nym_ip_packet_router::IpPacketRouter::new(ip_opts.config.clone())
|
||||
@@ -379,16 +375,11 @@ impl<St> Gateway<St> {
|
||||
return Err(GatewayError::IpPacketRouterStartupFailure);
|
||||
};
|
||||
|
||||
MessageRouter::new(nr_mix_receiver, packet_router).start_with_shutdown(router_shutdown);
|
||||
info!(
|
||||
"the local ip packet router is running on {}",
|
||||
start_data.address
|
||||
);
|
||||
MessageRouter::new(ipr_mix_receiver, packet_router).start_with_shutdown(router_shutdown);
|
||||
let address = start_data.address;
|
||||
|
||||
Ok(LocalNetworkRequesterHandle::new_ip(
|
||||
start_data,
|
||||
nr_mix_sender,
|
||||
))
|
||||
info!("the local ip packet router is running on {address}");
|
||||
Ok(LocalEmbeddedClientHandle::new(address, ipr_mix_sender))
|
||||
}
|
||||
|
||||
async fn wait_for_interrupt(
|
||||
@@ -504,8 +495,6 @@ impl<St> Gateway<St> {
|
||||
None
|
||||
};
|
||||
|
||||
// NOTE: this is mutually exclusive with the network requester (for now). This is reflected
|
||||
// in the command line arguments as well.
|
||||
if self.config.ip_packet_router.enabled {
|
||||
let embedded_ip_sp = self
|
||||
.start_ip_packet_router(
|
||||
|
||||
+2
-15
@@ -26,6 +26,7 @@ cupid = "0.6.1"
|
||||
dirs = "4.0"
|
||||
futures = { workspace = true }
|
||||
humantime-serde = "1.0"
|
||||
lazy_static = "1.4"
|
||||
log = { workspace = true }
|
||||
rand = "0.7.3"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
@@ -35,14 +36,8 @@ tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
toml = "0.5.8"
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
cfg-if = "1.0.0"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
## tracing
|
||||
tracing = { workspace = true, optional = true }
|
||||
opentelemetry = { version = "0.19.0", optional = true }
|
||||
|
||||
|
||||
# internal
|
||||
nym-node = { path = "../nym-node" }
|
||||
|
||||
@@ -51,6 +46,7 @@ nym-crypto = { path = "../common/crypto" }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
nym-mixnet-client = { path = "../common/client-libs/mixnet-client" }
|
||||
nym-mixnode-common = { path = "../common/mixnode-common" }
|
||||
nym-metrics = { path = "../common/nym-metrics" }
|
||||
nym-nonexhaustive-delayqueue = { path = "../common/nonexhaustive-delayqueue" }
|
||||
nym-sphinx = { path = "../common/nymsphinx" }
|
||||
nym-sphinx-params = { path = "../common/nymsphinx/params" }
|
||||
@@ -60,7 +56,6 @@ nym-types = { path = "../common/types" }
|
||||
nym-topology = { path = "../common/topology" }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client" }
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["output_format"] }
|
||||
cpu-cycles = { path = "../cpu-cycles", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = [
|
||||
@@ -73,14 +68,6 @@ tokio = { workspace = true, features = [
|
||||
nym-sphinx-types = { path = "../common/nymsphinx/types" }
|
||||
nym-sphinx-params = { path = "../common/nymsphinx/params" }
|
||||
|
||||
[features]
|
||||
cpucycles = [
|
||||
"nym-mixnode-common/cpucycles",
|
||||
"tracing",
|
||||
"opentelemetry",
|
||||
"nym-bin-common/tracing",
|
||||
]
|
||||
|
||||
[package.metadata.deb]
|
||||
name = "nym-mixnode"
|
||||
maintainer-scripts = "debian"
|
||||
|
||||
@@ -42,6 +42,9 @@ pub(crate) struct Init {
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
|
||||
#[clap(long)]
|
||||
metrics_key: Option<String>,
|
||||
}
|
||||
|
||||
impl From<Init> for OverrideConfig {
|
||||
@@ -53,6 +56,7 @@ impl From<Init> for OverrideConfig {
|
||||
verloc_port: init_config.verloc_port,
|
||||
http_api_port: init_config.http_api_port,
|
||||
nym_apis: init_config.nym_apis,
|
||||
metrics_key: init_config.metrics_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ struct OverrideConfig {
|
||||
verloc_port: Option<u16>,
|
||||
http_api_port: Option<u16>,
|
||||
nym_apis: Option<Vec<url::Url>>,
|
||||
metrics_key: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Cli) -> anyhow::Result<()> {
|
||||
@@ -83,6 +84,7 @@ fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
.with_optional(Config::with_mix_port, args.mix_port)
|
||||
.with_optional(Config::with_verloc_port, args.verloc_port)
|
||||
.with_optional(Config::with_http_api_port, args.http_api_port)
|
||||
.with_optional(Config::with_metrics_key, args.metrics_key)
|
||||
.with_optional_custom_env(
|
||||
Config::with_custom_nym_apis,
|
||||
args.nym_apis,
|
||||
|
||||
@@ -44,6 +44,9 @@ pub(crate) struct Run {
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
|
||||
#[clap(long)]
|
||||
metrics_key: Option<String>,
|
||||
}
|
||||
|
||||
impl From<Run> for OverrideConfig {
|
||||
@@ -55,6 +58,7 @@ impl From<Run> for OverrideConfig {
|
||||
verloc_port: run_config.verloc_port,
|
||||
http_api_port: run_config.http_api_port,
|
||||
nym_apis: run_config.nym_apis,
|
||||
metrics_key: run_config.metrics_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ fn default_mixnode_http_config() -> config::Http {
|
||||
DEFAULT_HTTP_API_LISTENING_PORT,
|
||||
),
|
||||
landing_page_assets_path: None,
|
||||
metrics_key: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +209,15 @@ impl Config {
|
||||
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
|
||||
self.mixnode.nym_api_urls.clone()
|
||||
}
|
||||
|
||||
pub fn with_metrics_key(mut self, metrics_key: String) -> Self {
|
||||
self.http.metrics_key = Some(metrics_key);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn metrics_key(&self) -> Option<&String> {
|
||||
self.http.metrics_key.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
|
||||
@@ -95,6 +95,7 @@ impl From<ConfigV1_1_32> for Config {
|
||||
value.mixnode.http_api_port,
|
||||
),
|
||||
landing_page_assets_path: None,
|
||||
metrics_key: None,
|
||||
},
|
||||
// /\ ADDED
|
||||
mixnode: MixNode {
|
||||
|
||||
@@ -57,6 +57,8 @@ bind_address = '{{ http.bind_address }}'
|
||||
# Path to assets directory of custom landing page of this node
|
||||
landing_page_assets_path = '{{ http.landing_page_assets_path }}'
|
||||
|
||||
metrics_key = '{{ http.metrics_key }}'
|
||||
|
||||
[storage_paths]
|
||||
|
||||
# Path to file containing private identity key.
|
||||
|
||||
+1
-27
@@ -3,18 +3,11 @@
|
||||
|
||||
use ::nym_config::defaults::setup_env;
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
use log::info;
|
||||
use nym_bin_common::bin_info;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
#[cfg(feature = "cpucycles")]
|
||||
use nym_bin_common::setup_tracing;
|
||||
#[cfg(feature = "cpucycles")]
|
||||
use nym_mixnode_common::measure;
|
||||
#[cfg(feature = "cpucycles")]
|
||||
use tracing::instrument;
|
||||
|
||||
mod commands;
|
||||
mod config;
|
||||
@@ -41,12 +34,6 @@ struct Cli {
|
||||
command: commands::Commands,
|
||||
}
|
||||
|
||||
#[cfg(feature = "cpucycles")]
|
||||
#[instrument(fields(cpucycles))]
|
||||
fn test_function() {
|
||||
measure!({})
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let args = Cli::parse();
|
||||
@@ -56,23 +43,10 @@ async fn main() -> anyhow::Result<()> {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpucycles")] {
|
||||
setup_tracing!("mixnode");
|
||||
info!("CPU cycles measurement is ON")
|
||||
} else {
|
||||
setup_logging();
|
||||
info!("CPU cycles measurement is OFF")
|
||||
}
|
||||
}
|
||||
setup_logging();
|
||||
|
||||
commands::execute(args).await?;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpucycles")] {
|
||||
opentelemetry::global::shutdown_tracer_provider();
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use crate::node::http::legacy::description::description;
|
||||
use crate::node::http::legacy::hardware::hardware;
|
||||
use crate::node::http::legacy::state::MixnodeAppState;
|
||||
use crate::node::http::legacy::stats::metrics;
|
||||
use crate::node::http::legacy::stats::stats;
|
||||
use crate::node::http::legacy::verloc::verloc;
|
||||
use crate::node::node_description::NodeDescription;
|
||||
@@ -29,6 +30,7 @@ pub(crate) mod api_routes {
|
||||
pub(crate) const VERLOC: &str = "/verloc";
|
||||
pub(crate) const DESCRIPTION: &str = "/description";
|
||||
pub(crate) const STATS: &str = "/stats";
|
||||
pub(crate) const METRICS: &str = "/metrics";
|
||||
pub(crate) const HARDWARE: &str = "/hardware";
|
||||
}
|
||||
|
||||
@@ -44,6 +46,7 @@ pub(crate) fn routes<S: Send + Sync + 'static + Clone>(
|
||||
)
|
||||
.route(api_routes::STATS, get(stats))
|
||||
.route(api_routes::HARDWARE, get(hardware))
|
||||
.route(api_routes::METRICS, get(metrics))
|
||||
.fallback(not_found)
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use axum::extract::FromRef;
|
||||
pub(crate) struct MixnodeAppState {
|
||||
pub(crate) verloc: VerlocState,
|
||||
pub(crate) stats: SharedNodeStats,
|
||||
pub(crate) metrics_key: Option<String>,
|
||||
}
|
||||
|
||||
impl FromRef<MixnodeAppState> for VerlocState {
|
||||
|
||||
@@ -1,33 +1,59 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::node_statistics::{NodeStats, NodeStatsSimple, SharedNodeStats};
|
||||
use axum::extract::{Query, State};
|
||||
use crate::node::node_statistics::{NodeStatsSimple, SharedNodeStats};
|
||||
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
http::HeaderMap,
|
||||
};
|
||||
use nym_metrics::REGISTRY;
|
||||
use nym_node::http::api::{FormattedResponse, Output};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::state::MixnodeAppState;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum NodeStatsResponse {
|
||||
Full(NodeStats),
|
||||
Full(String),
|
||||
Simple(NodeStatsSimple),
|
||||
}
|
||||
|
||||
pub(crate) async fn metrics(State(state): State<MixnodeAppState>, headers: HeaderMap) -> String {
|
||||
if let Some(metrics_key) = state.metrics_key {
|
||||
if let Some(auth) = headers.get("Authorization") {
|
||||
if auth.to_str().unwrap_or_default() == format!("Bearer {}", metrics_key) {
|
||||
REGISTRY.to_string()
|
||||
} else {
|
||||
"Unauthorized".to_string()
|
||||
}
|
||||
} else {
|
||||
"Unauthorized".to_string()
|
||||
}
|
||||
} else {
|
||||
"Set metrics_key in config to enable Prometheus metrics".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn stats(
|
||||
Query(params): Query<StatsQueryParams>,
|
||||
State(stats): State<SharedNodeStats>,
|
||||
) -> MixnodeStatsResponse {
|
||||
let output = params.output.unwrap_or_default();
|
||||
|
||||
let snapshot_data = stats.clone_data().await;
|
||||
|
||||
// there's no point in returning the entire hashmap of sending destinations in regular mode
|
||||
let response = if params.debug {
|
||||
NodeStatsResponse::Full(snapshot_data)
|
||||
let response = generate_stats(params.debug, stats).await;
|
||||
output.to_response(response)
|
||||
}
|
||||
|
||||
async fn generate_stats(full: bool, stats: SharedNodeStats) -> NodeStatsResponse {
|
||||
let snapshot_data = stats.clone_data().await;
|
||||
if full {
|
||||
NodeStatsResponse::Full(REGISTRY.to_string())
|
||||
} else {
|
||||
NodeStatsResponse::Simple(snapshot_data.simplify())
|
||||
};
|
||||
output.to_response(response)
|
||||
}
|
||||
}
|
||||
|
||||
pub type MixnodeStatsResponse = FormattedResponse<NodeStatsResponse>;
|
||||
|
||||
@@ -64,6 +64,12 @@ impl<'a> HttpApiBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn with_metrics_key(mut self, metrics_key: Option<&String>) -> Self {
|
||||
self.legacy_mixnode.metrics_key = metrics_key.map(|k| k.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn with_verloc(mut self, verloc: VerlocState) -> Self {
|
||||
self.legacy_mixnode.verloc = verloc;
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::node::TaskClient;
|
||||
use futures::StreamExt;
|
||||
use log::debug;
|
||||
use log::{error, info, warn};
|
||||
use nym_mixnode_common::measure;
|
||||
use nym_metrics::nanos;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
@@ -19,9 +19,6 @@ use tokio::net::TcpStream;
|
||||
use tokio::time::Instant;
|
||||
use tokio_util::codec::Framed;
|
||||
|
||||
#[cfg(feature = "cpucycles")]
|
||||
use tracing::instrument;
|
||||
|
||||
pub(crate) mod packet_processing;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -53,10 +50,6 @@ impl ConnectionHandler {
|
||||
.expect("the delay-forwarder has died!");
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, framed_sphinx_packet), fields(cpucycles))
|
||||
)]
|
||||
fn handle_received_packet(&self, framed_sphinx_packet: FramedNymPacket) {
|
||||
//
|
||||
// TODO: here be replay attack detection - it will require similar key cache to the one in
|
||||
@@ -66,7 +59,7 @@ impl ConnectionHandler {
|
||||
|
||||
// all processing such, key caching, etc. was done.
|
||||
// however, if it was a forward hop, we still need to delay it
|
||||
measure!({
|
||||
nanos!("handle_received_packet", {
|
||||
match self.packet_processor.process_received(framed_sphinx_packet) {
|
||||
Err(err) => debug!("We failed to process received sphinx packet - {err}"),
|
||||
Ok(res) => match res {
|
||||
|
||||
@@ -72,11 +72,13 @@ impl MixNode {
|
||||
&self,
|
||||
atomic_verloc_result: AtomicVerlocResult,
|
||||
node_stats_pointer: SharedNodeStats,
|
||||
metrics_key: Option<&String>,
|
||||
task_client: TaskClient,
|
||||
) -> Result<(), MixnodeError> {
|
||||
HttpApiBuilder::new(&self.config, &self.identity_keypair, &self.sphinx_keypair)
|
||||
.with_verloc(VerlocState::new(atomic_verloc_result))
|
||||
.with_mixing_stats(node_stats_pointer)
|
||||
.with_metrics_key(metrics_key)
|
||||
.with_descriptor(self.descriptor.clone())
|
||||
.start(task_client)
|
||||
}
|
||||
@@ -249,6 +251,7 @@ impl MixNode {
|
||||
self.start_http_api(
|
||||
atomic_verloc_results,
|
||||
node_stats_pointer,
|
||||
self.config.metrics_key(),
|
||||
shutdown.subscribe().named("http-api"),
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use nym_metrics::REGISTRY;
|
||||
|
||||
use super::TaskClient;
|
||||
use futures::channel::mpsc;
|
||||
use futures::lock::Mutex;
|
||||
@@ -15,7 +17,7 @@ use std::time::{Duration, SystemTime};
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
// convenience aliases
|
||||
type PacketsMap = HashMap<String, u64>;
|
||||
type PacketsMap = HashMap<String, f64>;
|
||||
type PacketDataReceiver = mpsc::UnboundedReceiver<PacketEvent>;
|
||||
type PacketDataSender = mpsc::UnboundedSender<PacketEvent>;
|
||||
|
||||
@@ -27,14 +29,15 @@ pub(crate) struct SharedNodeStats {
|
||||
impl SharedNodeStats {
|
||||
pub(crate) fn new() -> Self {
|
||||
let now = SystemTime::now();
|
||||
|
||||
SharedNodeStats {
|
||||
inner: Arc::new(RwLock::new(NodeStats {
|
||||
update_time: now,
|
||||
previous_update_time: now,
|
||||
packets_received_since_startup: 0,
|
||||
packets_sent_since_startup: HashMap::new(),
|
||||
packets_explicitly_dropped_since_startup: HashMap::new(),
|
||||
packets_received_since_last_update: 0,
|
||||
packets_received_since_startup: 0.,
|
||||
packets_sent_since_startup_all: 0.,
|
||||
packets_dropped_since_startup_all: 0.,
|
||||
packets_received_since_last_update: 0.,
|
||||
packets_sent_since_last_update: HashMap::new(),
|
||||
packets_explicitly_dropped_since_last_update: HashMap::new(),
|
||||
})),
|
||||
@@ -43,7 +46,7 @@ impl SharedNodeStats {
|
||||
|
||||
pub(crate) async fn update(
|
||||
&self,
|
||||
new_received: u64,
|
||||
new_received: f64,
|
||||
new_sent: PacketsMap,
|
||||
new_dropped: PacketsMap,
|
||||
) {
|
||||
@@ -54,20 +57,21 @@ impl SharedNodeStats {
|
||||
guard.update_time = snapshot_time;
|
||||
|
||||
guard.packets_received_since_startup += new_received;
|
||||
for (mix, count) in &new_sent {
|
||||
*guard
|
||||
.packets_sent_since_startup
|
||||
.entry(mix.clone())
|
||||
.or_insert(0) += *count;
|
||||
for count in new_sent.values() {
|
||||
guard.packets_sent_since_startup_all += count;
|
||||
}
|
||||
|
||||
for (mix, count) in &new_dropped {
|
||||
*guard
|
||||
.packets_explicitly_dropped_since_last_update
|
||||
.entry(mix.clone())
|
||||
.or_insert(0) += *count;
|
||||
for count in new_dropped.values() {
|
||||
guard.packets_dropped_since_startup_all += count;
|
||||
}
|
||||
|
||||
REGISTRY.inc_by("packets_received_since_startup", new_received);
|
||||
REGISTRY.inc_by("packets_sent_since_startup_all", new_sent.values().sum());
|
||||
REGISTRY.inc_by(
|
||||
"packets_dropped_since_startup_all",
|
||||
new_dropped.values().sum(),
|
||||
);
|
||||
|
||||
guard.packets_received_since_last_update = new_received;
|
||||
guard.packets_sent_since_last_update = new_sent;
|
||||
guard.packets_explicitly_dropped_since_last_update = new_dropped;
|
||||
@@ -82,27 +86,18 @@ impl SharedNodeStats {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct NodeStats {
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
update_time: SystemTime,
|
||||
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
previous_update_time: SystemTime,
|
||||
|
||||
packets_received_since_startup: u64,
|
||||
|
||||
// note: sent does not imply forwarded. We don't know if it was delivered successfully
|
||||
packets_sent_since_startup: PacketsMap,
|
||||
|
||||
// we know for sure we dropped packets to those destinations
|
||||
packets_explicitly_dropped_since_startup: PacketsMap,
|
||||
|
||||
packets_received_since_last_update: u64,
|
||||
|
||||
packets_received_since_startup: f64,
|
||||
packets_sent_since_startup_all: f64,
|
||||
packets_dropped_since_startup_all: f64,
|
||||
packets_received_since_last_update: f64,
|
||||
// note: sent does not imply forwarded. We don't know if it was delivered successfully
|
||||
packets_sent_since_last_update: PacketsMap,
|
||||
|
||||
// we know for sure we dropped packets to those destinations
|
||||
packets_explicitly_dropped_since_last_update: PacketsMap,
|
||||
}
|
||||
@@ -112,10 +107,10 @@ impl Default for NodeStats {
|
||||
NodeStats {
|
||||
update_time: SystemTime::UNIX_EPOCH,
|
||||
previous_update_time: SystemTime::UNIX_EPOCH,
|
||||
packets_received_since_startup: 0,
|
||||
packets_sent_since_startup: Default::default(),
|
||||
packets_explicitly_dropped_since_startup: Default::default(),
|
||||
packets_received_since_last_update: 0,
|
||||
packets_received_since_startup: 0.,
|
||||
packets_sent_since_startup_all: 0.,
|
||||
packets_dropped_since_startup_all: 0.,
|
||||
packets_received_since_last_update: 0.,
|
||||
packets_sent_since_last_update: Default::default(),
|
||||
packets_explicitly_dropped_since_last_update: Default::default(),
|
||||
}
|
||||
@@ -128,11 +123,8 @@ impl NodeStats {
|
||||
update_time: self.update_time,
|
||||
previous_update_time: self.previous_update_time,
|
||||
packets_received_since_startup: self.packets_received_since_startup,
|
||||
packets_sent_since_startup: self.packets_sent_since_startup.values().sum(),
|
||||
packets_explicitly_dropped_since_startup: self
|
||||
.packets_explicitly_dropped_since_startup
|
||||
.values()
|
||||
.sum(),
|
||||
packets_sent_since_startup: self.packets_sent_since_startup_all,
|
||||
packets_explicitly_dropped_since_startup: self.packets_dropped_since_startup_all,
|
||||
packets_received_since_last_update: self.packets_received_since_last_update,
|
||||
packets_sent_since_last_update: self.packets_sent_since_last_update.values().sum(),
|
||||
packets_explicitly_dropped_since_last_update: self
|
||||
@@ -151,21 +143,21 @@ pub struct NodeStatsSimple {
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
previous_update_time: SystemTime,
|
||||
|
||||
packets_received_since_startup: u64,
|
||||
packets_received_since_startup: f64,
|
||||
|
||||
// note: sent does not imply forwarded. We don't know if it was delivered successfully
|
||||
packets_sent_since_startup: u64,
|
||||
packets_sent_since_startup: f64,
|
||||
|
||||
// we know for sure we dropped those packets
|
||||
packets_explicitly_dropped_since_startup: u64,
|
||||
packets_explicitly_dropped_since_startup: f64,
|
||||
|
||||
packets_received_since_last_update: u64,
|
||||
packets_received_since_last_update: f64,
|
||||
|
||||
// note: sent does not imply forwarded. We don't know if it was delivered successfully
|
||||
packets_sent_since_last_update: u64,
|
||||
packets_sent_since_last_update: f64,
|
||||
|
||||
// we know for sure we dropped those packets
|
||||
packets_explicitly_dropped_since_last_update: u64,
|
||||
packets_explicitly_dropped_since_last_update: f64,
|
||||
}
|
||||
|
||||
pub(crate) enum PacketEvent {
|
||||
@@ -203,14 +195,14 @@ impl CurrentPacketData {
|
||||
|
||||
async fn increment_sent(&self, destination: String) {
|
||||
let mut unlocked = self.inner.sent.lock().await;
|
||||
let receiver_count = unlocked.entry(destination).or_insert(0);
|
||||
*receiver_count += 1;
|
||||
let receiver_count = unlocked.entry(destination).or_insert(0.);
|
||||
*receiver_count += 1.;
|
||||
}
|
||||
|
||||
async fn increment_dropped(&self, destination: String) {
|
||||
let mut unlocked = self.inner.dropped.lock().await;
|
||||
let dropped_count = unlocked.entry(destination).or_insert(0);
|
||||
*dropped_count += 1;
|
||||
let dropped_count = unlocked.entry(destination).or_insert(0.);
|
||||
*dropped_count += 1.;
|
||||
}
|
||||
|
||||
async fn acquire_and_reset(&self) -> (u64, PacketsMap, PacketsMap) {
|
||||
@@ -332,7 +324,9 @@ impl StatsUpdater {
|
||||
async fn update_stats(&self) {
|
||||
// grab new data since last update
|
||||
let (received, sent, dropped) = self.current_packet_data.acquire_and_reset().await;
|
||||
self.current_stats.update(received, sent, dropped).await;
|
||||
self.current_stats
|
||||
.update(received as f64, sent, dropped)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn run(&mut self) {
|
||||
@@ -376,21 +370,18 @@ impl PacketStatsConsoleLogger {
|
||||
|
||||
info!(
|
||||
"Since startup mixed {} packets! ({} in last {} seconds)",
|
||||
stats.packets_sent_since_startup.values().sum::<u64>(),
|
||||
stats.packets_sent_since_last_update.values().sum::<u64>(),
|
||||
stats.packets_sent_since_startup_all,
|
||||
stats.packets_sent_since_last_update.values().sum::<f64>(),
|
||||
difference_secs,
|
||||
);
|
||||
if !stats.packets_explicitly_dropped_since_startup.is_empty() {
|
||||
if stats.packets_dropped_since_startup_all > 0. {
|
||||
info!(
|
||||
"Since startup dropped {} packets! ({} in last {} seconds)",
|
||||
stats
|
||||
.packets_explicitly_dropped_since_startup
|
||||
.values()
|
||||
.sum::<u64>(),
|
||||
stats.packets_dropped_since_startup_all,
|
||||
stats
|
||||
.packets_explicitly_dropped_since_last_update
|
||||
.values()
|
||||
.sum::<u64>(),
|
||||
.sum::<f64>(),
|
||||
difference_secs,
|
||||
);
|
||||
}
|
||||
@@ -403,22 +394,19 @@ impl PacketStatsConsoleLogger {
|
||||
);
|
||||
trace!(
|
||||
"Since startup sent packets to the following: \n{:#?} \n And in last {} seconds: {:#?})",
|
||||
stats.packets_sent_since_startup,
|
||||
stats.packets_sent_since_startup_all,
|
||||
difference_secs,
|
||||
stats.packets_sent_since_last_update
|
||||
);
|
||||
} else {
|
||||
info!(
|
||||
"Since startup mixed {} packets!",
|
||||
stats.packets_sent_since_startup.values().sum::<u64>(),
|
||||
stats.packets_sent_since_startup_all,
|
||||
);
|
||||
if !stats.packets_explicitly_dropped_since_startup.is_empty() {
|
||||
if stats.packets_dropped_since_startup_all > 0. {
|
||||
info!(
|
||||
"Since startup dropped {} packets!",
|
||||
stats
|
||||
.packets_explicitly_dropped_since_startup
|
||||
.values()
|
||||
.sum::<u64>(),
|
||||
stats.packets_dropped_since_startup_all,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -427,8 +415,8 @@ impl PacketStatsConsoleLogger {
|
||||
stats.packets_received_since_startup
|
||||
);
|
||||
trace!(
|
||||
"Since startup sent packets to the following: \n{:#?}",
|
||||
stats.packets_sent_since_startup
|
||||
"Since startup sent packets {}",
|
||||
stats.packets_sent_since_startup_all
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -545,14 +533,11 @@ mod tests {
|
||||
|
||||
// Get output (stats)
|
||||
let stats = node_stats_pointer.read().await;
|
||||
assert_eq!(&stats.packets_sent_since_startup.get("foo"), &Some(&2u64));
|
||||
assert_eq!(&stats.packets_sent_since_startup.len(), &1);
|
||||
assert_eq!(
|
||||
&stats.packets_sent_since_last_update.get("foo"),
|
||||
&Some(&2u64)
|
||||
);
|
||||
assert_eq!(&stats.packets_sent_since_startup_all, &2.);
|
||||
assert_eq!(&stats.packets_sent_since_last_update.get("foo"), &Some(&2.));
|
||||
assert_eq!(&stats.packets_sent_since_last_update.len(), &1);
|
||||
assert_eq!(&stats.packets_received_since_startup, &0u64);
|
||||
assert!(&stats.packets_explicitly_dropped_since_startup.is_empty());
|
||||
assert_eq!(&stats.packets_received_since_startup, &0.);
|
||||
assert_eq!(&stats.packets_dropped_since_startup_all, &0.);
|
||||
assert_eq!(REGISTRY.to_string(), "# HELP packets_dropped_since_startup_all packets_dropped_since_startup_all\n# TYPE packets_dropped_since_startup_all counter\npackets_dropped_since_startup_all 0\n# HELP packets_received_since_startup packets_received_since_startup\n# TYPE packets_received_since_startup counter\npackets_received_since_startup 0\n# HELP packets_sent_since_startup_all packets_sent_since_startup_all\n# TYPE packets_sent_since_startup_all counter\npackets_sent_since_startup_all 2\n")
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2
@@ -4087,7 +4087,9 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
"wasmtimer",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ pub async fn handle_task_status(
|
||||
window: &tauri::Window,
|
||||
) {
|
||||
match task_status {
|
||||
TaskStatus::Ready => {
|
||||
TaskStatus::Ready | TaskStatus::ReadyWithGateway(_) => {
|
||||
{
|
||||
let mut state_w = state.write().await;
|
||||
state_w.mark_connected(window);
|
||||
|
||||
@@ -49,6 +49,9 @@ pub struct Http {
|
||||
/// Path to assets directory of custom landing page of this node.
|
||||
#[serde(deserialize_with = "de_maybe_path")]
|
||||
pub landing_page_assets_path: Option<PathBuf>,
|
||||
|
||||
#[serde(default)]
|
||||
pub metrics_key: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Http {
|
||||
@@ -56,6 +59,7 @@ impl Default for Http {
|
||||
Http {
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), DEFAULT_HTTP_PORT),
|
||||
landing_page_assets_path: None,
|
||||
metrics_key: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ echo "Using $localnetdir for the localnet"
|
||||
|
||||
# initialise mixnet
|
||||
echo "initialising mixnode1..."
|
||||
cargo run --release --bin nym-mixnode -- init --id "mix1-$suffix" --host 127.0.0.1 --mix-port 10001 --verloc-port 20001 --http-api-port 30001 --output=json >>"$localnetdir/mix1.json"
|
||||
cargo run --release --bin nym-mixnode -- init --id "mix1-$suffix" --host 127.0.0.1 --mix-port 10001 --verloc-port 20001 --http-api-port 30001 --metrics-key=lala --output=json >>"$localnetdir/mix1.json"
|
||||
|
||||
echo "initialising mixnode2..."
|
||||
cargo run --release --bin nym-mixnode -- init --id "mix2-$suffix" --host 127.0.0.1 --mix-port 10002 --verloc-port 20002 --http-api-port 30002 --output=json >>"$localnetdir/mix2.json"
|
||||
cargo run --release --bin nym-mixnode -- init --id "mix2-$suffix" --host 127.0.0.1 --mix-port 10002 --verloc-port 20002 --http-api-port 30002 --metrics-key=lala --output=json >>"$localnetdir/mix2.json"
|
||||
|
||||
echo "initialising mixnode3..."
|
||||
cargo run --release --bin nym-mixnode -- init --id "mix3-$suffix" --host 127.0.0.1 --mix-port 10003 --verloc-port 20003 --http-api-port 30003 --output=json >>"$localnetdir/mix3.json"
|
||||
cargo run --release --bin nym-mixnode -- init --id "mix3-$suffix" --host 127.0.0.1 --mix-port 10003 --verloc-port 20003 --http-api-port 30003 --metrics-key=lala --output=json >>"$localnetdir/mix3.json"
|
||||
|
||||
echo "initialising gateway..."
|
||||
cargo run --release --bin nym-gateway -- init --id "gateway-$suffix" --host 127.0.0.1 --mix-port 10004 --clients-port 9000 --output=json >>"$localnetdir/gateway.json"
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if the script is run as root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "This script must be run as root. Please use sudo or log in as the root user."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Hardcoded node_exporter version
|
||||
node_exporter_version="1.7.0"
|
||||
|
||||
# Create a user for node_exporter without a home directory
|
||||
useradd --no-create-home --shell /bin/false node_exporter
|
||||
|
||||
# Download node_exporter
|
||||
echo "Downloading node_exporter version $node_exporter_version..."
|
||||
wget "https://github.com/prometheus/node_exporter/releases/download/v$node_exporter_version/node_exporter-$node_exporter_version.linux-amd64.tar.gz" -O /tmp/node_exporter-$node_exporter_version.linux-amd64.tar.gz
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to download node_exporter."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Unarchive node_exporter
|
||||
echo "Unarchiving node_exporter..."
|
||||
tar xvfz /tmp/node_exporter-$node_exporter_version.linux-amd64.tar.gz -C /tmp
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to unarchive node_exporter."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Move node_exporter to /usr/local/bin
|
||||
echo "Moving node_exporter to /usr/local/bin..."
|
||||
mv /tmp/node_exporter-$node_exporter_version.linux-amd64/node_exporter /usr/local/bin/node_exporter
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to move node_exporter."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set ownership and permissions
|
||||
chown node_exporter:node_exporter /usr/local/bin/node_exporter
|
||||
chmod 0755 /usr/local/bin/node_exporter
|
||||
|
||||
# Create node_exporter service file
|
||||
echo "Creating node_exporter service file..."
|
||||
cat <<EOF > /etc/systemd/system/node_exporter.service
|
||||
[Unit]
|
||||
Description=Node Exporter
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=node_exporter
|
||||
Group=node_exporter
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/node_exporter --web.config.file /etc/prometheus_node_exporter/configuration.yml
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
|
||||
mkdir -p /etc/prometheus_node_exporter/
|
||||
|
||||
sudo cat << EOF > /etc/prometheus_node_exporter/configuration.yml
|
||||
basic_auth_users:
|
||||
prometheus: "\$2y\$10\$aB1RMr6ZGg2psbMOezmfluVzGcH/VHIqP4Lksx0DWuw/QSr9Iccwu"
|
||||
|
||||
EOF
|
||||
|
||||
ufw allow 9100
|
||||
|
||||
# Reload systemd, enable and start node_exporter service
|
||||
echo "Configuring systemd for node_exporter..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable node_exporter.service
|
||||
systemctl start node_exporter.service
|
||||
|
||||
# Cleanup
|
||||
echo "Cleaning up..."
|
||||
rm -rf /tmp/node_exporter-${node_exporter_version}.linux-amd64.tar.gz
|
||||
rm -rf /tmp/node_exporter-${node_exporter_version}.linux-amd64
|
||||
|
||||
echo "node_exporter installation and configuration complete."
|
||||
@@ -0,0 +1,117 @@
|
||||
import argparse
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from collections import namedtuple
|
||||
|
||||
Config = namedtuple("Config", ["port", "outfile", "outlink", "env"])
|
||||
|
||||
|
||||
def gateway_targets(entry):
|
||||
targets = [
|
||||
# Config(
|
||||
# None,
|
||||
# "/tmp/temp_targets_gateway.json",
|
||||
# f"/tmp/prom_targets_gateway_{entry['env']}.json",
|
||||
# entry["env"],
|
||||
# ),
|
||||
Config(
|
||||
9100,
|
||||
"/tmp/temp_targets_gateway_node.json",
|
||||
f"/tmp/prom_targets_gateway_node_{entry['env']}.json",
|
||||
entry["env"],
|
||||
),
|
||||
]
|
||||
|
||||
gateways = requests.get(f"{entry['nym_api']}/api/v1/gateways").json()
|
||||
|
||||
for config in targets:
|
||||
config_to_targets(config, gateways, {"kind": "gateway"})
|
||||
|
||||
|
||||
def mixnode_targets(entry):
|
||||
targets = [
|
||||
Config(
|
||||
None,
|
||||
"/tmp/temp_targets_mix.json",
|
||||
f"/tmp/prom_targets_mix_{entry['env']}.json",
|
||||
entry["env"],
|
||||
),
|
||||
Config(
|
||||
9100,
|
||||
"/tmp/temp_targets_node.json",
|
||||
f"/tmp/prom_targets_node_{entry['env']}.json",
|
||||
entry["env"],
|
||||
),
|
||||
]
|
||||
|
||||
mixnodes = requests.get(f"{entry['nym_api']}/api/v1/mixnodes").json()
|
||||
|
||||
for config in targets:
|
||||
config_to_targets(config, mixnodes, {"kind": "mixnode"})
|
||||
|
||||
|
||||
def validate_config_entry(entry):
|
||||
return entry.get("nym_api") and entry.get("env")
|
||||
|
||||
|
||||
def config_to_targets(config, mixnodes, labels=None):
|
||||
prom_targets = [
|
||||
make_prom_target(config.env, mixnode, config.port, labels)
|
||||
for mixnode in mixnodes
|
||||
]
|
||||
with open(config.outfile, "w") as f:
|
||||
json.dump(prom_targets, f)
|
||||
|
||||
os.chmod(config.outfile, 0o777)
|
||||
os.rename(config.outfile, config.outlink)
|
||||
os.chmod(config.outlink, 0o777)
|
||||
|
||||
print(f"Prometheus -> {len(prom_targets)} targets written to {config.outlink}")
|
||||
|
||||
|
||||
def make_prom_target(env, mixnode, port=None, labels=None):
|
||||
bond_info = mixnode.get("bond_information", {})
|
||||
mix_node = bond_info.get("mix_node", {})
|
||||
host = mix_node.get("host", None)
|
||||
port = port if port else mix_node.get("http_api_port", None)
|
||||
if host is None or port is None:
|
||||
return None
|
||||
|
||||
target = {
|
||||
"targets": [f"{host}:{port}"],
|
||||
"labels": {
|
||||
"mix_node_host": host,
|
||||
"identity_key": mix_node.get("identity_key", None),
|
||||
"sphinx_key": mix_node.get("sphinx_key", None),
|
||||
"mix_node_version": mix_node.get("version", None),
|
||||
"mixnet_env": env,
|
||||
},
|
||||
}
|
||||
|
||||
for k, v in labels.items():
|
||||
target["labels"][k] = v
|
||||
|
||||
return target
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Create prometheus targets for rewarded set mixnodes."
|
||||
)
|
||||
parser.add_argument(
|
||||
"config",
|
||||
type=str,
|
||||
help="Config file, see scripts/prom_targets_config.json",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
config_file = args.config
|
||||
|
||||
with open(config_file, "r") as f:
|
||||
config = json.load(f)
|
||||
|
||||
for entry in config:
|
||||
mixnode_targets(entry)
|
||||
|
||||
gateway_targets(entry)
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{ "nym_api": "https://sandbox-nym-api1.nymtech.net", "env": "sandbox" },
|
||||
{ "nym_api": "https://api.performance.nymte.ch", "env": "performance" }
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
requests
|
||||
@@ -0,0 +1,7 @@
|
||||
# FFI
|
||||
This repo contains bindings for C/C++ and Go in the respectively named directories.
|
||||
|
||||
`shared/` contains shared 'internal' functions which are imported by bindings. Primarily these functions rely on managing:
|
||||
* that the client is not mutated by multiple threads simultaneously
|
||||
* that client actions happen in blocking threads
|
||||
|
||||
Generated
+346
-15
@@ -155,6 +155,47 @@ version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_escape"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.77"
|
||||
@@ -240,6 +281,15 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -474,6 +524,38 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver 1.0.21",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
@@ -1466,6 +1548,15 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e"
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
@@ -1650,6 +1741,12 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-net"
|
||||
version = "0.3.1"
|
||||
@@ -1696,6 +1793,17 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.10.0"
|
||||
@@ -2283,6 +2391,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
@@ -2300,9 +2418,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
@@ -2561,6 +2679,20 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-cpp-ffi"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58 0.5.0",
|
||||
"lazy_static",
|
||||
"nym-bin-common",
|
||||
"nym-ffi-shared",
|
||||
"nym-sdk",
|
||||
"nym-sphinx-anonymous-replies",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-credential-storage"
|
||||
version = "0.1.0"
|
||||
@@ -2696,6 +2828,21 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-ffi-shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58 0.5.0",
|
||||
"lazy_static",
|
||||
"nym-bin-common",
|
||||
"nym-sdk",
|
||||
"nym-sphinx-anonymous-replies",
|
||||
"tokio",
|
||||
"uniffi",
|
||||
"uniffi_build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway-client"
|
||||
version = "0.1.0"
|
||||
@@ -3292,19 +3439,6 @@ dependencies = [
|
||||
"x25519-dalek 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym_cpp_ffi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58 0.5.0",
|
||||
"lazy_static",
|
||||
"nym-bin-common",
|
||||
"nym-sdk",
|
||||
"nym-sphinx-anonymous-replies",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
@@ -3320,6 +3454,12 @@ version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "oneshot-uniffi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
@@ -3611,6 +3751,12 @@ version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "platforms"
|
||||
version = "3.3.0"
|
||||
@@ -4149,6 +4295,26 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.6.1"
|
||||
@@ -4220,6 +4386,9 @@ name = "semver"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
@@ -4382,6 +4551,12 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@@ -4649,6 +4824,12 @@ dependencies = [
|
||||
"tokio-rustls 0.23.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.4"
|
||||
@@ -5184,6 +5365,15 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
@@ -5217,6 +5407,138 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "uniffi"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
"clap",
|
||||
"uniffi_bindgen",
|
||||
"uniffi_build",
|
||||
"uniffi_core",
|
||||
"uniffi_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_bindgen"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"camino",
|
||||
"cargo_metadata",
|
||||
"clap",
|
||||
"fs-err",
|
||||
"glob",
|
||||
"goblin",
|
||||
"heck",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"serde",
|
||||
"toml 0.5.11",
|
||||
"uniffi_meta",
|
||||
"uniffi_testing",
|
||||
"uniffi_udl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_build"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
"uniffi_bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_checksum_derive"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_core"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"camino",
|
||||
"log",
|
||||
"once_cell",
|
||||
"oneshot-uniffi",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_macros"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"camino",
|
||||
"fs-err",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.48",
|
||||
"toml 0.5.11",
|
||||
"uniffi_build",
|
||||
"uniffi_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_meta"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"siphasher",
|
||||
"uniffi_checksum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_testing"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
"cargo_metadata",
|
||||
"fs-err",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_udl"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"uniffi_meta",
|
||||
"uniffi_testing",
|
||||
"weedle2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
@@ -5473,6 +5795,15 @@ dependencies = [
|
||||
"webpki 0.22.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weedle2"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym_cpp_ffi"
|
||||
version = "0.1.0"
|
||||
name = "nym-cpp-ffi"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
@@ -10,11 +10,11 @@ crate-type = ["cdylib"]
|
||||
[dependencies]
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
# Nym clients, addressing, packet format, common tools (logging)
|
||||
# Nym clients, addressing, packet format, common tools (logging), ffi shared
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-bin-common = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-sphinx-anonymous-replies = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
# static var macro
|
||||
nym-ffi-shared = { path = "../shared" }
|
||||
lazy_static = "1.4.0"
|
||||
# error handling
|
||||
anyhow = "1.0.75"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# C++ FFI
|
||||
> ⚠️ This is an initial version of this library in order to give developers something to experiment with. If you use this code to begin testing out Mixnet integration and run into issues, errors, or have feedback, please feel free to open an issue; feedback from developers trying to use it will help us improve it. If you have questions feel free to reach out via our [Matrix channel]().
|
||||
> ⚠️ This is an initial version of this library in order to give developers something to experiment with. If you use this code to begin testing out Mixnet integration and run into issues, errors, or have feedback, please feel free to open an issue; feedback from developers trying to use it will help us improve it. If you have questions feel free to reach out via our [Matrix channel](https://matrix.to/#/#dev:nymtech.chat).
|
||||
|
||||
This repo contains:
|
||||
* `lib.rs`: an initial version of bindings for interacting with the Mixnet via the Rust SDK from C++.
|
||||
* `lib.rs`: an initial version of bindings for interacting with the Mixnet via the Rust SDK from C++. These are essentially match statements wrapping imported functions from the `nym-ffi-shared` lib allowing for nicer [error handling](#error-handling-).
|
||||
* `main.cpp`: an example of using this library, relying on `Boost` for threads.
|
||||
|
||||
The example `.cpp` file is a simple example flow of:
|
||||
|
||||
@@ -44,7 +44,7 @@ else
|
||||
build_artifacts_and_link;
|
||||
./main;
|
||||
else
|
||||
echo "unknown optional argument - the only available optional argument is 'clean'"
|
||||
printf "unknown optional argument - the only available optional argument is 'clean'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
+45
-171
@@ -1,49 +1,13 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use lazy_static::lazy_static;
|
||||
use nym_sdk::mixnet::{MixnetClient, MixnetMessageSender, ReconstructedMessage};
|
||||
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_ffi_shared;
|
||||
use std::ffi::{c_char, c_int, CStr, CString};
|
||||
|
||||
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
||||
use std::mem::forget;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
/*
|
||||
NYM_CLIENT: Static reference (only init-ed once) to:
|
||||
- Arc: share ownership
|
||||
- Mutex: thread-safe way to share data between threads
|
||||
- Option: init-ed or not
|
||||
RUNTIME: Tokio runtime: no need to pass back to C and deal with raw pointers as it was previously
|
||||
*/
|
||||
lazy_static! {
|
||||
static ref NYM_CLIENT: Arc<Mutex<Option<MixnetClient>>> = Arc::new(Mutex::new(None));
|
||||
static ref RUNTIME: Runtime = Runtime::new().unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StatusCode {
|
||||
NoError = 0,
|
||||
ClientInitError = -1,
|
||||
ClientUninitialisedError = -2,
|
||||
SelfAddrError = -3,
|
||||
SendMsgError = -4,
|
||||
ReplyError = -5,
|
||||
ListenError = -6,
|
||||
}
|
||||
|
||||
// pub type CIntCallback = extern "C" fn(i32);
|
||||
pub type CStringCallback = extern "C" fn(*const c_char);
|
||||
pub type CMessageCallback = extern "C" fn(ReceivedMessage);
|
||||
|
||||
// FFI-sanitised way of sending back a ReconstructedMessage to C
|
||||
#[repr(C)]
|
||||
pub struct ReceivedMessage {
|
||||
message: *const u8,
|
||||
size: usize,
|
||||
sender_tag: *const c_char,
|
||||
}
|
||||
mod types;
|
||||
use crate::types::types::{CMessageCallback, CStringCallback, ReceivedMessage, StatusCode};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn init_logging() {
|
||||
@@ -52,76 +16,31 @@ pub extern "C" fn init_logging() {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn init_ephemeral() -> c_int {
|
||||
match init_ephemeral_internal() {
|
||||
match nym_ffi_shared::init_ephemeral_internal() {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::ClientInitError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn init_ephemeral_internal() -> anyhow::Result<(), anyhow::Error> {
|
||||
if NYM_CLIENT.lock().unwrap().as_ref().is_some() {
|
||||
bail!("client already exists");
|
||||
} else {
|
||||
RUNTIME.block_on(async move {
|
||||
let init_client = MixnetClient::connect_new().await?;
|
||||
let mut client = NYM_CLIENT.try_lock();
|
||||
if let Ok(ref mut client) = client {
|
||||
**client = Some(init_client);
|
||||
} else {
|
||||
anyhow!("couldnt lock NYM_CLIENT");
|
||||
}
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_self_address(callback: CStringCallback) -> c_int {
|
||||
match get_self_address_internal(callback) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
match nym_ffi_shared::get_self_address_internal(/*callback*/) {
|
||||
Ok(addr) => {
|
||||
let c_ptr = CString::new(addr).expect("could not convert Nym address to CString");
|
||||
let call = CStringCallback::new(callback.callback);
|
||||
// as_ptr() keeps ownership in rust unlike into_raw() so no need to free it
|
||||
call.trigger(c_ptr.as_ptr());
|
||||
StatusCode::NoError as c_int
|
||||
}
|
||||
Err(_) => StatusCode::SelfAddrError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_self_address_internal(callback: CStringCallback) -> anyhow::Result<(), anyhow::Error> {
|
||||
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if client.is_none() {
|
||||
bail!("Client is not yet initialised");
|
||||
}
|
||||
let nym_client = client
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
// get address as cstring
|
||||
let c_string = CString::new(nym_client.nym_address().to_string())?;
|
||||
// as_ptr() keeps ownership in rust unlike into_raw() so no need to free it
|
||||
callback(c_string.as_ptr());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn send_message(recipient: *const c_char, message: *const c_char) -> c_int {
|
||||
match send_message_internal(recipient, message) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::SendMsgError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn send_message_internal(
|
||||
recipient: *const c_char,
|
||||
message: *const c_char,
|
||||
) -> anyhow::Result<(), anyhow::Error> {
|
||||
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if client.is_none() {
|
||||
bail!("Client is not yet initialised");
|
||||
}
|
||||
let nym_client = client
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
|
||||
let c_str = unsafe {
|
||||
if recipient.is_null() {
|
||||
bail!("recipient is null");
|
||||
return StatusCode::RecipientNullError as c_int;
|
||||
}
|
||||
let c_str = CStr::from_ptr(recipient);
|
||||
c_str
|
||||
@@ -130,44 +49,24 @@ fn send_message_internal(
|
||||
let recipient = r_str.parse().unwrap();
|
||||
let c_str = unsafe {
|
||||
if message.is_null() {
|
||||
bail!("message is null");
|
||||
return StatusCode::MessageNullError as c_int;
|
||||
}
|
||||
let c_str = CStr::from_ptr(message);
|
||||
c_str
|
||||
};
|
||||
let message = c_str.to_str().unwrap();
|
||||
|
||||
// send message
|
||||
RUNTIME.block_on(async move {
|
||||
nym_client.send_plain_message(recipient, message).await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
Ok(())
|
||||
match nym_ffi_shared::send_message_internal(recipient, message) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::SendMsgError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn reply(recipient: *const c_char, message: *const c_char) -> c_int {
|
||||
match reply_internal(recipient, message) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::ReplyError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn reply_internal(
|
||||
recipient: *const c_char,
|
||||
message: *const c_char,
|
||||
) -> anyhow::Result<(), anyhow::Error> {
|
||||
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if client.is_none() {
|
||||
bail!("Client is not yet initialised");
|
||||
}
|
||||
let nym_client = client
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
|
||||
let recipient = unsafe {
|
||||
if recipient.is_null() {
|
||||
bail!("recipient is null");
|
||||
return StatusCode::RecipientNullError as c_int;
|
||||
}
|
||||
let r_str = CStr::from_ptr(recipient).to_string_lossy().into_owned();
|
||||
AnonymousSenderTag::try_from_base58_string(r_str)
|
||||
@@ -175,64 +74,39 @@ fn reply_internal(
|
||||
};
|
||||
let message = unsafe {
|
||||
if message.is_null() {
|
||||
bail!("message is null");
|
||||
return StatusCode::MessageNullError as c_int;
|
||||
}
|
||||
let c_str = CStr::from_ptr(message);
|
||||
let r_str = c_str.to_str().unwrap();
|
||||
r_str
|
||||
};
|
||||
RUNTIME.block_on(async move {
|
||||
nym_client.send_reply(recipient, message).await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
Ok(())
|
||||
|
||||
match nym_ffi_shared::reply_internal(recipient, message) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::ReplyError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn listen_for_incoming(callback: CMessageCallback) -> c_int {
|
||||
match listen_for_incoming_internal(callback) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
match nym_ffi_shared::listen_for_incoming_internal() {
|
||||
Ok(received) => {
|
||||
let message_ptr = received.message.as_ptr();
|
||||
let message_length = received.message.len();
|
||||
let c_string = CString::new(received.sender_tag.unwrap().to_string()).unwrap();
|
||||
let sender_ptr = c_string.as_ptr();
|
||||
// stop deallocation when out of scope as passing raw ptr to it elsewhere
|
||||
forget(received);
|
||||
let rec_for_c = ReceivedMessage {
|
||||
message: message_ptr,
|
||||
size: message_length,
|
||||
sender_tag: sender_ptr,
|
||||
};
|
||||
let call = CMessageCallback::new(callback.callback);
|
||||
call.trigger(rec_for_c);
|
||||
|
||||
StatusCode::NoError as c_int
|
||||
}
|
||||
Err(_) => StatusCode::ListenError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn listen_for_incoming_internal(callback: CMessageCallback) -> anyhow::Result<(), anyhow::Error> {
|
||||
let mut binding = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if binding.is_none() {
|
||||
bail!("recipient is null");
|
||||
}
|
||||
let client = binding
|
||||
.as_mut()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
|
||||
RUNTIME.block_on(async move {
|
||||
let received = wait_for_non_empty_message(client).await?;
|
||||
let message_ptr = received.message.as_ptr();
|
||||
let message_length = received.message.len();
|
||||
let c_string = CString::new(received.sender_tag.unwrap().to_string())?;
|
||||
let sender_ptr = c_string.as_ptr();
|
||||
// stop deallocation when out of scope as passing raw ptr to it elsewhere
|
||||
forget(received);
|
||||
let rec_for_c = ReceivedMessage {
|
||||
message: message_ptr,
|
||||
size: message_length,
|
||||
sender_tag: sender_ptr,
|
||||
};
|
||||
callback(rec_for_c);
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn wait_for_non_empty_message(
|
||||
client: &mut MixnetClient,
|
||||
) -> anyhow::Result<ReconstructedMessage> {
|
||||
while let Some(mut new_message) = client.wait_for_messages().await {
|
||||
if !new_message.is_empty() {
|
||||
return new_message
|
||||
.pop()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"));
|
||||
}
|
||||
}
|
||||
bail!("(Rust) did not receive any non-empty message")
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ int main() {
|
||||
// - execute
|
||||
// - get() returned val
|
||||
// - handle val
|
||||
// initialise an ephemeral client - aka one without specified keystore
|
||||
boost::packaged_task<char> init(boost::bind(init_ephemeral));
|
||||
boost::unique_future<char> init_future = init.get_future();
|
||||
init();
|
||||
@@ -77,7 +78,7 @@ int main() {
|
||||
return_code = get_self_address(string_callback_function);
|
||||
handle(return_code);
|
||||
|
||||
// send a message through the mixnet - in this case to ourselves
|
||||
// send a message through the mixnet - in this case to ourselves using the value from get_self_address
|
||||
std::cout << "(c++) message to send through mixnet: " << message << std::endl;
|
||||
boost::packaged_task<char> send(boost::bind(send_message, addr, message));
|
||||
boost::unique_future<char> send_future = send.get_future();
|
||||
@@ -94,16 +95,17 @@ int main() {
|
||||
return_code = listen_future.get();
|
||||
handle(return_code);
|
||||
|
||||
// replying to incoming message (from ourselves) with SURBs- note that sending a message to a recipient and
|
||||
// replying to an incoming are different functions
|
||||
// replying to incoming message (from ourselves) with SURBs - note that sending a message to a recipient and
|
||||
// replying to an incoming are different functions: replying relies on parsing the incoming sender_tag on the Rust
|
||||
// side and creating an AnonymousSenderTag type, instead of the Recipient type which relies on a nym address
|
||||
boost::packaged_task<char> reply_fn(boost::bind(reply, sender_tag, reply_message));
|
||||
boost::unique_future<char> reply_future = reply_fn.get_future();
|
||||
reply_fn();
|
||||
return_code = reply_future.get();
|
||||
handle(return_code);
|
||||
|
||||
// sleep so that the nym side logging can catch up - in reality you'd have another process running to keep logging
|
||||
// going, so this is only necessary for this reference implementation
|
||||
// sleep so that the client processes can catch up - in reality you'd have another process running to keep logging
|
||||
// going, so this is only necessary for this reference
|
||||
std::this_thread::sleep_for(std::chrono::seconds(40));
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
pub mod types {
|
||||
|
||||
use std::ffi::c_char;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StatusCode {
|
||||
NoError = 0,
|
||||
ClientInitError = -1,
|
||||
ClientUninitialisedError = -2,
|
||||
SelfAddrError = -3,
|
||||
SendMsgError = -4,
|
||||
ReplyError = -5,
|
||||
ListenError = -6,
|
||||
RecipientNullError = -7,
|
||||
MessageNullError = -8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CStringCallback {
|
||||
pub callback: extern "C" fn(*const c_char),
|
||||
}
|
||||
|
||||
impl CStringCallback {
|
||||
pub fn new(callback: extern "C" fn(*const c_char)) -> Self {
|
||||
CStringCallback { callback }
|
||||
}
|
||||
pub fn trigger(&self, char: *const c_char) {
|
||||
(self.callback)(char);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CMessageCallback {
|
||||
pub callback: extern "C" fn(ReceivedMessage),
|
||||
}
|
||||
|
||||
impl CMessageCallback {
|
||||
pub fn new(callback: extern "C" fn(ReceivedMessage)) -> Self {
|
||||
CMessageCallback { callback }
|
||||
}
|
||||
pub fn trigger(&self, message: ReceivedMessage) {
|
||||
(self.callback)(message)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ReceivedMessage {
|
||||
pub message: *const u8,
|
||||
pub size: usize,
|
||||
pub sender_tag: *const c_char,
|
||||
}
|
||||
}
|
||||
Generated
+6061
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "nym-go-ffi" #"goffitest"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
name = "nym_go_ffi" #"go_ffi"
|
||||
|
||||
[dependencies]
|
||||
# Bindgen
|
||||
uniffi = { version = "0.25.2", features = ["cli"] }
|
||||
# Nym clients, addressing, packet format, common tools (logging), ffi shared
|
||||
nym-bin-common = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-sphinx-anonymous-replies = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-ffi-shared = { path = "../shared" }
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
lazy_static = "1.4.0"
|
||||
# error handling
|
||||
anyhow = "1.0.79"
|
||||
thiserror = "1.0.56"
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25.2", features = ["build" ] }
|
||||
uniffi_build = { version = "0.25.2", features=["builtin-bindgen"] }
|
||||
|
||||
[[bin]]
|
||||
name = "uniffi-bindgen"
|
||||
path = "uniffi-bindgen.rs"
|
||||
@@ -0,0 +1,47 @@
|
||||
# Go FFI
|
||||
> ⚠️ This is an initial version of this library in order to give developers something to experiment with. If you use this code to begin testing out Mixnet integration and run into issues, errors, or have feedback, please feel free to open an issue; feedback from developers trying to use it will help us improve it. If you have questions feel free to reach out via our [Matrix channel](https://matrix.to/#/#dev:nymtech.chat).
|
||||
|
||||
This repo contains:
|
||||
* `lib.rs`: an initial version of bindings for interacting with the Mixnet via the Rust SDK from Go. These are essentially match statemtns wrapping imported functions from the `nym-ffi-shared` lib.
|
||||
* `ffi/`: a directory containing:
|
||||
* the `bindings/` files generated using [`uniffi-bindgen-go`](https://github.com/NordSecurity/uniffi-bindgen-go)
|
||||
* [`example.go`](./example.go): an example of using this library.
|
||||
|
||||
The `example.go` file is an example flow of:
|
||||
* setting up Nym client logging
|
||||
* creating an ephemeral Nym client (no key storage / persistent address - this will come in a future iteration)
|
||||
* getting its [Nym address](https://nymtech.net/docs/clients/addressing-system.html)
|
||||
* using that address to send a message to yourself via the Mixnet
|
||||
* listen for and parse the incoming message for the `sender_tag` used for [anonymous replies with SURBs](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs)
|
||||
* send a reply to yourself using SURBs
|
||||
|
||||
## Useage - Consuming the Library
|
||||
You can import the bindings as normal and interact with them as shown in the [example file](./example.go). This example imports the bindings from the this repository (hence the `go.mod` and `go.sum` in the crate root) but you can import them remotely as usual.
|
||||
|
||||
## Useage - Developing on the Library
|
||||
If you want to fork and add new features/functions to this library use the following instructions to rebuild the Go bindings.
|
||||
|
||||
Rust functions exposed to the Go binding library are in `./src/lib.rs`.
|
||||
|
||||
The `build.sh` script in the root of the repository speeds up the task of building and linking the Rust and Go code.
|
||||
* if want to quickly recompile your code run it as-is with `./build.sh`
|
||||
* if you want to clean build both the Rust and Go code after removing existing compiled binaries run it with the optional `clean` argument: `./build.sh clean`.
|
||||
|
||||
> Make sure to run the script from the root of the project directory, and that your LD PATH is set first!
|
||||
> ```
|
||||
> RUST_BINARIES=target/release
|
||||
> echo 'export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:'${RUST_BINARIES} >> ~/.zshrc
|
||||
> source ~/.zshrc
|
||||
> ```
|
||||
|
||||
This script will:
|
||||
* (optionally if called with `clean` argument) remove existing Rust and Go artifacts
|
||||
* build `lib.rs` with the `--release` flag
|
||||
* compile the Go bindings
|
||||
|
||||
**WIP** you need to manually add the following `cgo` flags to the generated bindings immediately underneath LN3 (`// #include <bindings.h`). In the future this will be automated in `build.sh`:
|
||||
|
||||
```
|
||||
// #cgo LDFLAGS: -L../../target/release -lnym_go_ffi
|
||||
```
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
uniffi::generate_scaffolding("src/bindings.udl").unwrap();
|
||||
}
|
||||
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
PROJECT_NAME="go"
|
||||
|
||||
set -eu
|
||||
MODE="--release"
|
||||
|
||||
GO_DIR="./go-nym"
|
||||
UDL_PATH="./src/bindings.udl"
|
||||
|
||||
build_artifacts() {
|
||||
# build rust
|
||||
cargo build $MODE
|
||||
# build go bindings
|
||||
printf "building go bindings \n"
|
||||
uniffi-bindgen-go $UDL_PATH --out-dir $GO_DIR
|
||||
printf "bindings built \n\n"
|
||||
|
||||
# something not right with these - having to add it manually to bindings.go for the moment
|
||||
# pushd $GO_DIR/bindings
|
||||
# echo $(pwd)
|
||||
# LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}:../../target/release" \
|
||||
# CGO_LDFLAGS="-L../target/release -lnym_go_ffi -lm -ldl" \
|
||||
# CGO_ENABLED=1 \
|
||||
# go run ../main.go
|
||||
}
|
||||
|
||||
clean_artifacts() {
|
||||
# clean up existing things
|
||||
rm -rf $GO_DIR
|
||||
cargo clean
|
||||
}
|
||||
|
||||
|
||||
if [ $(pwd | awk -F/ '{print $NF}') != ${PROJECT_NAME} ]
|
||||
then
|
||||
printf "please run from root dir of project"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -eq 0 ];
|
||||
then
|
||||
build_artifacts;
|
||||
else
|
||||
arg=$1
|
||||
if [ "$arg" == "clean" ]; then
|
||||
clean_artifacts;
|
||||
build_artifacts;
|
||||
else
|
||||
printf "unknown optional argument - the only available optional argument is 'clean'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"nymffi/go-nym/bindings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// initialise Nym client logging - this is quite verbose but very informative
|
||||
bindings.InitLogging()
|
||||
|
||||
// initialise an ephemeral client - aka one without specified keystore
|
||||
err := bindings.InitEphemeral()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// get our client's address
|
||||
str, err2 := bindings.GetSelfAddress()
|
||||
if err2 != nil {
|
||||
fmt.Println("(Go) Error:", err2)
|
||||
return
|
||||
}
|
||||
fmt.Println("(Go) response:")
|
||||
fmt.Println(str)
|
||||
|
||||
// send a message through the mixnet - in this case to ourselves using the value from GetSelfAddress
|
||||
err3 := bindings.SendMessage(str, "helloworld")
|
||||
if err3 != nil {
|
||||
fmt.Println("(Go) Error:", err3)
|
||||
return
|
||||
}
|
||||
|
||||
// listen out for incoming messages: in the future the client can be split into a listening and a sending client,
|
||||
// allowing for this to run as a persistent process in its own thread and not have to block but instead be running
|
||||
// concurrently
|
||||
//
|
||||
// assuming a data type like so:
|
||||
// type IncomingMessage struct {
|
||||
// Message string
|
||||
// SenderTag vec<u8>
|
||||
// }
|
||||
incomingMessage, err4 := bindings.ListenForIncoming()
|
||||
if err4 != nil {
|
||||
fmt.Println("(Go) Error:", err4)
|
||||
return
|
||||
}
|
||||
fmt.Println("(Go) incoming message: ", incomingMessage.Message, " from: ", incomingMessage.Sender)
|
||||
|
||||
// we can just use the byte array we parsed from the incoming message to reply with: this is a
|
||||
// byte representation of the sender_tag used for Single Use Reply Blocks (SURBs)
|
||||
//
|
||||
// replying to incoming message (from ourselves) with SURBs - note that sending a message to a recipient and
|
||||
// replying to an incoming are different functions: replying relies on parsing the incoming sender_tag on the Rust
|
||||
// side and creating an AnonymousSenderTag type, instead of the Recipient type which relies on a nym address
|
||||
//
|
||||
// you will see in the client logs that there are requests for more SURBs that we send to ourselves to
|
||||
// be able to fit the full reply message in there. In a future iteration of this code we can also expose
|
||||
// a send() which allows for developers to dictate the number of SURBs to send along with their outgoing message
|
||||
fmt.Println("(Go) replying to received message")
|
||||
err5 := bindings.Reply(incomingMessage.Sender, "replyworld")
|
||||
if err5 != nil {
|
||||
fmt.Println("(Go) Error:", err5)
|
||||
return
|
||||
}
|
||||
|
||||
// sleep so that the nym client processes can catch up - in reality you'd have another process
|
||||
// running to keep logging going, so this is only necessary for this reference
|
||||
time.Sleep(30 * time.Second)
|
||||
fmt.Println("(Go) end go example")
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <bindings.h>
|
||||
|
||||
// This file exists beacause of
|
||||
// https://github.com/golang/go/issues/11263
|
||||
|
||||
void cgo_rust_task_callback_bridge_bindings(RustTaskCallback cb, const void * taskData, int8_t status) {
|
||||
cb(taskData, status);
|
||||
}
|
||||
@@ -0,0 +1,773 @@
|
||||
package bindings
|
||||
|
||||
// #include <bindings.h>
|
||||
// #cgo LDFLAGS: -L../../target/release -lnym_go_ffi
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type RustBuffer = C.RustBuffer
|
||||
|
||||
type RustBufferI interface {
|
||||
AsReader() *bytes.Reader
|
||||
Free()
|
||||
ToGoBytes() []byte
|
||||
Data() unsafe.Pointer
|
||||
Len() int
|
||||
Capacity() int
|
||||
}
|
||||
|
||||
func RustBufferFromExternal(b RustBufferI) RustBuffer {
|
||||
return RustBuffer{
|
||||
capacity: C.int(b.Capacity()),
|
||||
len: C.int(b.Len()),
|
||||
data: (*C.uchar)(b.Data()),
|
||||
}
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Capacity() int {
|
||||
return int(cb.capacity)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Len() int {
|
||||
return int(cb.len)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Data() unsafe.Pointer {
|
||||
return unsafe.Pointer(cb.data)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) AsReader() *bytes.Reader {
|
||||
b := unsafe.Slice((*byte)(cb.data), C.int(cb.len))
|
||||
return bytes.NewReader(b)
|
||||
}
|
||||
|
||||
func (cb RustBuffer) Free() {
|
||||
rustCall(func(status *C.RustCallStatus) bool {
|
||||
C.ffi_nym_go_ffi_rustbuffer_free(cb, status)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func (cb RustBuffer) ToGoBytes() []byte {
|
||||
return C.GoBytes(unsafe.Pointer(cb.data), C.int(cb.len))
|
||||
}
|
||||
|
||||
func stringToRustBuffer(str string) RustBuffer {
|
||||
return bytesToRustBuffer([]byte(str))
|
||||
}
|
||||
|
||||
func bytesToRustBuffer(b []byte) RustBuffer {
|
||||
if len(b) == 0 {
|
||||
return RustBuffer{}
|
||||
}
|
||||
// We can pass the pointer along here, as it is pinned
|
||||
// for the duration of this call
|
||||
foreign := C.ForeignBytes{
|
||||
len: C.int(len(b)),
|
||||
data: (*C.uchar)(unsafe.Pointer(&b[0])),
|
||||
}
|
||||
|
||||
return rustCall(func(status *C.RustCallStatus) RustBuffer {
|
||||
return C.ffi_nym_go_ffi_rustbuffer_from_bytes(foreign, status)
|
||||
})
|
||||
}
|
||||
|
||||
type BufLifter[GoType any] interface {
|
||||
Lift(value RustBufferI) GoType
|
||||
}
|
||||
|
||||
type BufLowerer[GoType any] interface {
|
||||
Lower(value GoType) RustBuffer
|
||||
}
|
||||
|
||||
type FfiConverter[GoType any, FfiType any] interface {
|
||||
Lift(value FfiType) GoType
|
||||
Lower(value GoType) FfiType
|
||||
}
|
||||
|
||||
type BufReader[GoType any] interface {
|
||||
Read(reader io.Reader) GoType
|
||||
}
|
||||
|
||||
type BufWriter[GoType any] interface {
|
||||
Write(writer io.Writer, value GoType)
|
||||
}
|
||||
|
||||
type FfiRustBufConverter[GoType any, FfiType any] interface {
|
||||
FfiConverter[GoType, FfiType]
|
||||
BufReader[GoType]
|
||||
}
|
||||
|
||||
func LowerIntoRustBuffer[GoType any](bufWriter BufWriter[GoType], value GoType) RustBuffer {
|
||||
// This might be not the most efficient way but it does not require knowing allocation size
|
||||
// beforehand
|
||||
var buffer bytes.Buffer
|
||||
bufWriter.Write(&buffer, value)
|
||||
|
||||
bytes, err := io.ReadAll(&buffer)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("reading written data: %w", err))
|
||||
}
|
||||
return bytesToRustBuffer(bytes)
|
||||
}
|
||||
|
||||
func LiftFromRustBuffer[GoType any](bufReader BufReader[GoType], rbuf RustBufferI) GoType {
|
||||
defer rbuf.Free()
|
||||
reader := rbuf.AsReader()
|
||||
item := bufReader.Read(reader)
|
||||
if reader.Len() > 0 {
|
||||
// TODO: Remove this
|
||||
leftover, _ := io.ReadAll(reader)
|
||||
panic(fmt.Errorf("Junk remaining in buffer after lifting: %s", string(leftover)))
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func rustCallWithError[U any](converter BufLifter[error], callback func(*C.RustCallStatus) U) (U, error) {
|
||||
var status C.RustCallStatus
|
||||
returnValue := callback(&status)
|
||||
err := checkCallStatus(converter, status)
|
||||
|
||||
return returnValue, err
|
||||
}
|
||||
|
||||
func checkCallStatus(converter BufLifter[error], status C.RustCallStatus) error {
|
||||
switch status.code {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return converter.Lift(status.errorBuf)
|
||||
case 2:
|
||||
// when the rust code sees a panic, it tries to construct a rustbuffer
|
||||
// with the message. but if that code panics, then it just sends back
|
||||
// an empty buffer.
|
||||
if status.errorBuf.len > 0 {
|
||||
panic(fmt.Errorf("%s", FfiConverterStringINSTANCE.Lift(status.errorBuf)))
|
||||
} else {
|
||||
panic(fmt.Errorf("Rust panicked while handling Rust panic"))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown status code: %d", status.code)
|
||||
}
|
||||
}
|
||||
|
||||
func checkCallStatusUnknown(status C.RustCallStatus) error {
|
||||
switch status.code {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
panic(fmt.Errorf("function not returning an error returned an error"))
|
||||
case 2:
|
||||
// when the rust code sees a panic, it tries to construct a rustbuffer
|
||||
// with the message. but if that code panics, then it just sends back
|
||||
// an empty buffer.
|
||||
if status.errorBuf.len > 0 {
|
||||
panic(fmt.Errorf("%s", FfiConverterStringINSTANCE.Lift(status.errorBuf)))
|
||||
} else {
|
||||
panic(fmt.Errorf("Rust panicked while handling Rust panic"))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown status code: %d", status.code)
|
||||
}
|
||||
}
|
||||
|
||||
func rustCall[U any](callback func(*C.RustCallStatus) U) U {
|
||||
returnValue, err := rustCallWithError(nil, callback)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return returnValue
|
||||
}
|
||||
|
||||
func writeInt8(writer io.Writer, value int8) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint8(writer io.Writer, value uint8) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeInt16(writer io.Writer, value int16) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint16(writer io.Writer, value uint16) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeInt32(writer io.Writer, value int32) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint32(writer io.Writer, value uint32) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeInt64(writer io.Writer, value int64) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint64(writer io.Writer, value uint64) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeFloat32(writer io.Writer, value float32) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeFloat64(writer io.Writer, value float64) {
|
||||
if err := binary.Write(writer, binary.BigEndian, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func readInt8(reader io.Reader) int8 {
|
||||
var result int8
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint8(reader io.Reader) uint8 {
|
||||
var result uint8
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readInt16(reader io.Reader) int16 {
|
||||
var result int16
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint16(reader io.Reader) uint16 {
|
||||
var result uint16
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readInt32(reader io.Reader) int32 {
|
||||
var result int32
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint32(reader io.Reader) uint32 {
|
||||
var result uint32
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readInt64(reader io.Reader) int64 {
|
||||
var result int64
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readUint64(reader io.Reader) uint64 {
|
||||
var result uint64
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readFloat32(reader io.Reader) float32 {
|
||||
var result float32
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readFloat64(reader io.Reader) float64 {
|
||||
var result float64
|
||||
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
uniffiCheckChecksums()
|
||||
}
|
||||
|
||||
func uniffiCheckChecksums() {
|
||||
// Get the bindings contract version from our ComponentInterface
|
||||
bindingsContractVersion := 24
|
||||
// Get the scaffolding contract version by calling the into the dylib
|
||||
scaffoldingContractVersion := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint32_t {
|
||||
return C.ffi_nym_go_ffi_uniffi_contract_version(uniffiStatus)
|
||||
})
|
||||
if bindingsContractVersion != int(scaffoldingContractVersion) {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: UniFFI contract version mismatch")
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_nym_go_ffi_checksum_func_get_self_address(uniffiStatus)
|
||||
})
|
||||
if checksum != 51546 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: uniffi_nym_go_ffi_checksum_func_get_self_address: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_nym_go_ffi_checksum_func_init_ephemeral(uniffiStatus)
|
||||
})
|
||||
if checksum != 28391 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: uniffi_nym_go_ffi_checksum_func_init_ephemeral: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_nym_go_ffi_checksum_func_init_logging(uniffiStatus)
|
||||
})
|
||||
if checksum != 1547 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: uniffi_nym_go_ffi_checksum_func_init_logging: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_nym_go_ffi_checksum_func_listen_for_incoming(uniffiStatus)
|
||||
})
|
||||
if checksum != 52894 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: uniffi_nym_go_ffi_checksum_func_listen_for_incoming: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_nym_go_ffi_checksum_func_reply(uniffiStatus)
|
||||
})
|
||||
if checksum != 50524 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: uniffi_nym_go_ffi_checksum_func_reply: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
{
|
||||
checksum := rustCall(func(uniffiStatus *C.RustCallStatus) C.uint16_t {
|
||||
return C.uniffi_nym_go_ffi_checksum_func_send_message(uniffiStatus)
|
||||
})
|
||||
if checksum != 33425 {
|
||||
// If this happens try cleaning and rebuilding your project
|
||||
panic("bindings: uniffi_nym_go_ffi_checksum_func_send_message: UniFFI API checksum mismatch")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type FfiConverterString struct{}
|
||||
|
||||
var FfiConverterStringINSTANCE = FfiConverterString{}
|
||||
|
||||
func (FfiConverterString) Lift(rb RustBufferI) string {
|
||||
defer rb.Free()
|
||||
reader := rb.AsReader()
|
||||
b, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("reading reader: %w", err))
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (FfiConverterString) Read(reader io.Reader) string {
|
||||
length := readInt32(reader)
|
||||
buffer := make([]byte, length)
|
||||
read_length, err := reader.Read(buffer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if read_length != int(length) {
|
||||
panic(fmt.Errorf("bad read length when reading string, expected %d, read %d", length, read_length))
|
||||
}
|
||||
return string(buffer)
|
||||
}
|
||||
|
||||
func (FfiConverterString) Lower(value string) RustBuffer {
|
||||
return stringToRustBuffer(value)
|
||||
}
|
||||
|
||||
func (FfiConverterString) Write(writer io.Writer, value string) {
|
||||
if len(value) > math.MaxInt32 {
|
||||
panic("String is too large to fit into Int32")
|
||||
}
|
||||
|
||||
writeInt32(writer, int32(len(value)))
|
||||
write_length, err := io.WriteString(writer, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if write_length != len(value) {
|
||||
panic(fmt.Errorf("bad write length when writing string, expected %d, written %d", len(value), write_length))
|
||||
}
|
||||
}
|
||||
|
||||
type FfiDestroyerString struct{}
|
||||
|
||||
func (FfiDestroyerString) Destroy(_ string) {}
|
||||
|
||||
type FfiConverterBytes struct{}
|
||||
|
||||
var FfiConverterBytesINSTANCE = FfiConverterBytes{}
|
||||
|
||||
func (c FfiConverterBytes) Lower(value []byte) RustBuffer {
|
||||
return LowerIntoRustBuffer[[]byte](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterBytes) Write(writer io.Writer, value []byte) {
|
||||
if len(value) > math.MaxInt32 {
|
||||
panic("[]byte is too large to fit into Int32")
|
||||
}
|
||||
|
||||
writeInt32(writer, int32(len(value)))
|
||||
write_length, err := writer.Write(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if write_length != len(value) {
|
||||
panic(fmt.Errorf("bad write length when writing []byte, expected %d, written %d", len(value), write_length))
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterBytes) Lift(rb RustBufferI) []byte {
|
||||
return LiftFromRustBuffer[[]byte](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterBytes) Read(reader io.Reader) []byte {
|
||||
length := readInt32(reader)
|
||||
buffer := make([]byte, length)
|
||||
read_length, err := reader.Read(buffer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if read_length != int(length) {
|
||||
panic(fmt.Errorf("bad read length when reading []byte, expected %d, read %d", length, read_length))
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
type FfiDestroyerBytes struct{}
|
||||
|
||||
func (FfiDestroyerBytes) Destroy(_ []byte) {}
|
||||
|
||||
type IncomingMessage struct {
|
||||
Message string
|
||||
Sender []byte
|
||||
}
|
||||
|
||||
func (r *IncomingMessage) Destroy() {
|
||||
FfiDestroyerString{}.Destroy(r.Message)
|
||||
FfiDestroyerBytes{}.Destroy(r.Sender)
|
||||
}
|
||||
|
||||
type FfiConverterTypeIncomingMessage struct{}
|
||||
|
||||
var FfiConverterTypeIncomingMessageINSTANCE = FfiConverterTypeIncomingMessage{}
|
||||
|
||||
func (c FfiConverterTypeIncomingMessage) Lift(rb RustBufferI) IncomingMessage {
|
||||
return LiftFromRustBuffer[IncomingMessage](c, rb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeIncomingMessage) Read(reader io.Reader) IncomingMessage {
|
||||
return IncomingMessage{
|
||||
FfiConverterStringINSTANCE.Read(reader),
|
||||
FfiConverterBytesINSTANCE.Read(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeIncomingMessage) Lower(value IncomingMessage) RustBuffer {
|
||||
return LowerIntoRustBuffer[IncomingMessage](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeIncomingMessage) Write(writer io.Writer, value IncomingMessage) {
|
||||
FfiConverterStringINSTANCE.Write(writer, value.Message)
|
||||
FfiConverterBytesINSTANCE.Write(writer, value.Sender)
|
||||
}
|
||||
|
||||
type FfiDestroyerTypeIncomingMessage struct{}
|
||||
|
||||
func (_ FfiDestroyerTypeIncomingMessage) Destroy(value IncomingMessage) {
|
||||
value.Destroy()
|
||||
}
|
||||
|
||||
type GoWrapError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (err GoWrapError) Error() string {
|
||||
return fmt.Sprintf("GoWrapError: %s", err.err.Error())
|
||||
}
|
||||
|
||||
func (err GoWrapError) Unwrap() error {
|
||||
return err.err
|
||||
}
|
||||
|
||||
// Err* are used for checking error type with `errors.Is`
|
||||
var ErrGoWrapErrorClientInitError = fmt.Errorf("GoWrapErrorClientInitError")
|
||||
var ErrGoWrapErrorClientUninitialisedError = fmt.Errorf("GoWrapErrorClientUninitialisedError")
|
||||
var ErrGoWrapErrorSelfAddrError = fmt.Errorf("GoWrapErrorSelfAddrError")
|
||||
var ErrGoWrapErrorSendMsgError = fmt.Errorf("GoWrapErrorSendMsgError")
|
||||
var ErrGoWrapErrorReplyError = fmt.Errorf("GoWrapErrorReplyError")
|
||||
var ErrGoWrapErrorListenError = fmt.Errorf("GoWrapErrorListenError")
|
||||
|
||||
// Variant structs
|
||||
type GoWrapErrorClientInitError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewGoWrapErrorClientInitError() *GoWrapError {
|
||||
return &GoWrapError{
|
||||
err: &GoWrapErrorClientInitError{},
|
||||
}
|
||||
}
|
||||
|
||||
func (err GoWrapErrorClientInitError) Error() string {
|
||||
return fmt.Sprintf("ClientInitError: %s", err.message)
|
||||
}
|
||||
|
||||
func (self GoWrapErrorClientInitError) Is(target error) bool {
|
||||
return target == ErrGoWrapErrorClientInitError
|
||||
}
|
||||
|
||||
type GoWrapErrorClientUninitialisedError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewGoWrapErrorClientUninitialisedError() *GoWrapError {
|
||||
return &GoWrapError{
|
||||
err: &GoWrapErrorClientUninitialisedError{},
|
||||
}
|
||||
}
|
||||
|
||||
func (err GoWrapErrorClientUninitialisedError) Error() string {
|
||||
return fmt.Sprintf("ClientUninitialisedError: %s", err.message)
|
||||
}
|
||||
|
||||
func (self GoWrapErrorClientUninitialisedError) Is(target error) bool {
|
||||
return target == ErrGoWrapErrorClientUninitialisedError
|
||||
}
|
||||
|
||||
type GoWrapErrorSelfAddrError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewGoWrapErrorSelfAddrError() *GoWrapError {
|
||||
return &GoWrapError{
|
||||
err: &GoWrapErrorSelfAddrError{},
|
||||
}
|
||||
}
|
||||
|
||||
func (err GoWrapErrorSelfAddrError) Error() string {
|
||||
return fmt.Sprintf("SelfAddrError: %s", err.message)
|
||||
}
|
||||
|
||||
func (self GoWrapErrorSelfAddrError) Is(target error) bool {
|
||||
return target == ErrGoWrapErrorSelfAddrError
|
||||
}
|
||||
|
||||
type GoWrapErrorSendMsgError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewGoWrapErrorSendMsgError() *GoWrapError {
|
||||
return &GoWrapError{
|
||||
err: &GoWrapErrorSendMsgError{},
|
||||
}
|
||||
}
|
||||
|
||||
func (err GoWrapErrorSendMsgError) Error() string {
|
||||
return fmt.Sprintf("SendMsgError: %s", err.message)
|
||||
}
|
||||
|
||||
func (self GoWrapErrorSendMsgError) Is(target error) bool {
|
||||
return target == ErrGoWrapErrorSendMsgError
|
||||
}
|
||||
|
||||
type GoWrapErrorReplyError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewGoWrapErrorReplyError() *GoWrapError {
|
||||
return &GoWrapError{
|
||||
err: &GoWrapErrorReplyError{},
|
||||
}
|
||||
}
|
||||
|
||||
func (err GoWrapErrorReplyError) Error() string {
|
||||
return fmt.Sprintf("ReplyError: %s", err.message)
|
||||
}
|
||||
|
||||
func (self GoWrapErrorReplyError) Is(target error) bool {
|
||||
return target == ErrGoWrapErrorReplyError
|
||||
}
|
||||
|
||||
type GoWrapErrorListenError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func NewGoWrapErrorListenError() *GoWrapError {
|
||||
return &GoWrapError{
|
||||
err: &GoWrapErrorListenError{},
|
||||
}
|
||||
}
|
||||
|
||||
func (err GoWrapErrorListenError) Error() string {
|
||||
return fmt.Sprintf("ListenError: %s", err.message)
|
||||
}
|
||||
|
||||
func (self GoWrapErrorListenError) Is(target error) bool {
|
||||
return target == ErrGoWrapErrorListenError
|
||||
}
|
||||
|
||||
type FfiConverterTypeGoWrapError struct{}
|
||||
|
||||
var FfiConverterTypeGoWrapErrorINSTANCE = FfiConverterTypeGoWrapError{}
|
||||
|
||||
func (c FfiConverterTypeGoWrapError) Lift(eb RustBufferI) error {
|
||||
return LiftFromRustBuffer[error](c, eb)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeGoWrapError) Lower(value *GoWrapError) RustBuffer {
|
||||
return LowerIntoRustBuffer[*GoWrapError](c, value)
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeGoWrapError) Read(reader io.Reader) error {
|
||||
errorID := readUint32(reader)
|
||||
|
||||
message := FfiConverterStringINSTANCE.Read(reader)
|
||||
switch errorID {
|
||||
case 1:
|
||||
return &GoWrapError{&GoWrapErrorClientInitError{message}}
|
||||
case 2:
|
||||
return &GoWrapError{&GoWrapErrorClientUninitialisedError{message}}
|
||||
case 3:
|
||||
return &GoWrapError{&GoWrapErrorSelfAddrError{message}}
|
||||
case 4:
|
||||
return &GoWrapError{&GoWrapErrorSendMsgError{message}}
|
||||
case 5:
|
||||
return &GoWrapError{&GoWrapErrorReplyError{message}}
|
||||
case 6:
|
||||
return &GoWrapError{&GoWrapErrorListenError{message}}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown error code %d in FfiConverterTypeGoWrapError.Read()", errorID))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c FfiConverterTypeGoWrapError) Write(writer io.Writer, value *GoWrapError) {
|
||||
switch variantValue := value.err.(type) {
|
||||
case *GoWrapErrorClientInitError:
|
||||
writeInt32(writer, 1)
|
||||
case *GoWrapErrorClientUninitialisedError:
|
||||
writeInt32(writer, 2)
|
||||
case *GoWrapErrorSelfAddrError:
|
||||
writeInt32(writer, 3)
|
||||
case *GoWrapErrorSendMsgError:
|
||||
writeInt32(writer, 4)
|
||||
case *GoWrapErrorReplyError:
|
||||
writeInt32(writer, 5)
|
||||
case *GoWrapErrorListenError:
|
||||
writeInt32(writer, 6)
|
||||
default:
|
||||
_ = variantValue
|
||||
panic(fmt.Sprintf("invalid error value `%v` in FfiConverterTypeGoWrapError.Write", value))
|
||||
}
|
||||
}
|
||||
|
||||
func GetSelfAddress() (string, error) {
|
||||
_uniffiRV, _uniffiErr := rustCallWithError(FfiConverterTypeGoWrapError{}, func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_nym_go_ffi_fn_func_get_self_address(_uniffiStatus)
|
||||
})
|
||||
if _uniffiErr != nil {
|
||||
var _uniffiDefaultValue string
|
||||
return _uniffiDefaultValue, _uniffiErr
|
||||
} else {
|
||||
return FfiConverterStringINSTANCE.Lift(_uniffiRV), _uniffiErr
|
||||
}
|
||||
}
|
||||
|
||||
func InitEphemeral() error {
|
||||
_, _uniffiErr := rustCallWithError(FfiConverterTypeGoWrapError{}, func(_uniffiStatus *C.RustCallStatus) bool {
|
||||
C.uniffi_nym_go_ffi_fn_func_init_ephemeral(_uniffiStatus)
|
||||
return false
|
||||
})
|
||||
return _uniffiErr
|
||||
}
|
||||
|
||||
func InitLogging() {
|
||||
rustCall(func(_uniffiStatus *C.RustCallStatus) bool {
|
||||
C.uniffi_nym_go_ffi_fn_func_init_logging(_uniffiStatus)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func ListenForIncoming() (IncomingMessage, error) {
|
||||
_uniffiRV, _uniffiErr := rustCallWithError(FfiConverterTypeGoWrapError{}, func(_uniffiStatus *C.RustCallStatus) RustBufferI {
|
||||
return C.uniffi_nym_go_ffi_fn_func_listen_for_incoming(_uniffiStatus)
|
||||
})
|
||||
if _uniffiErr != nil {
|
||||
var _uniffiDefaultValue IncomingMessage
|
||||
return _uniffiDefaultValue, _uniffiErr
|
||||
} else {
|
||||
return FfiConverterTypeIncomingMessageINSTANCE.Lift(_uniffiRV), _uniffiErr
|
||||
}
|
||||
}
|
||||
|
||||
func Reply(recipient []byte, message string) error {
|
||||
_, _uniffiErr := rustCallWithError(FfiConverterTypeGoWrapError{}, func(_uniffiStatus *C.RustCallStatus) bool {
|
||||
C.uniffi_nym_go_ffi_fn_func_reply(FfiConverterBytesINSTANCE.Lower(recipient), FfiConverterStringINSTANCE.Lower(message), _uniffiStatus)
|
||||
return false
|
||||
})
|
||||
return _uniffiErr
|
||||
}
|
||||
|
||||
func SendMessage(recipient string, message string) error {
|
||||
_, _uniffiErr := rustCallWithError(FfiConverterTypeGoWrapError{}, func(_uniffiStatus *C.RustCallStatus) bool {
|
||||
C.uniffi_nym_go_ffi_fn_func_send_message(FfiConverterStringINSTANCE.Lower(recipient), FfiConverterStringINSTANCE.Lower(message), _uniffiStatus)
|
||||
return false
|
||||
})
|
||||
return _uniffiErr
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
|
||||
|
||||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// The following structs are used to implement the lowest level
|
||||
// of the FFI, and thus useful to multiple uniffied crates.
|
||||
// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H.
|
||||
#ifdef UNIFFI_SHARED_H
|
||||
// We also try to prevent mixing versions of shared uniffi header structs.
|
||||
// If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V6
|
||||
#ifndef UNIFFI_SHARED_HEADER_V6
|
||||
#error Combining helper code from multiple versions of uniffi is not supported
|
||||
#endif // ndef UNIFFI_SHARED_HEADER_V6
|
||||
#else
|
||||
#define UNIFFI_SHARED_H
|
||||
#define UNIFFI_SHARED_HEADER_V6
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V6 in this file. ⚠️
|
||||
|
||||
typedef struct RustBuffer {
|
||||
int32_t capacity;
|
||||
int32_t len;
|
||||
uint8_t *data;
|
||||
} RustBuffer;
|
||||
|
||||
typedef int32_t (*ForeignCallback)(uint64_t, int32_t, uint8_t *, int32_t, RustBuffer *);
|
||||
|
||||
// Task defined in Rust that Go executes
|
||||
typedef void (*RustTaskCallback)(const void *, int8_t);
|
||||
|
||||
// Callback to execute Rust tasks using a Go routine
|
||||
//
|
||||
// Args:
|
||||
// executor: ForeignExecutor lowered into a uint64_t value
|
||||
// delay: Delay in MS
|
||||
// task: RustTaskCallback to call
|
||||
// task_data: data to pass the task callback
|
||||
typedef int8_t (*ForeignExecutorCallback)(uint64_t, uint32_t, RustTaskCallback, void *);
|
||||
|
||||
typedef struct ForeignBytes {
|
||||
int32_t len;
|
||||
const uint8_t *data;
|
||||
} ForeignBytes;
|
||||
|
||||
// Error definitions
|
||||
typedef struct RustCallStatus {
|
||||
int8_t code;
|
||||
RustBuffer errorBuf;
|
||||
} RustCallStatus;
|
||||
|
||||
// Continuation callback for UniFFI Futures
|
||||
typedef void (*RustFutureContinuation)(void * , int8_t);
|
||||
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V6 in this file. ⚠️
|
||||
#endif // def UNIFFI_SHARED_H
|
||||
|
||||
// Needed because we can't execute the callback directly from go.
|
||||
void cgo_rust_task_callback_bridge_bindings(RustTaskCallback, const void *, int8_t);
|
||||
|
||||
int8_t uniffiForeignExecutorCallbackbindings(uint64_t, uint32_t, RustTaskCallback, void*);
|
||||
|
||||
void uniffiFutureContinuationCallbackbindings(void*, int8_t);
|
||||
|
||||
RustBuffer uniffi_nym_go_ffi_fn_func_get_self_address(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void uniffi_nym_go_ffi_fn_func_init_ephemeral(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void uniffi_nym_go_ffi_fn_func_init_logging(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer uniffi_nym_go_ffi_fn_func_listen_for_incoming(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void uniffi_nym_go_ffi_fn_func_reply(
|
||||
RustBuffer recipient,
|
||||
RustBuffer message,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void uniffi_nym_go_ffi_fn_func_send_message(
|
||||
RustBuffer recipient,
|
||||
RustBuffer message,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_nym_go_ffi_rustbuffer_alloc(
|
||||
int32_t size,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_nym_go_ffi_rustbuffer_from_bytes(
|
||||
ForeignBytes bytes,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rustbuffer_free(
|
||||
RustBuffer buf,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_nym_go_ffi_rustbuffer_reserve(
|
||||
RustBuffer buf,
|
||||
int32_t additional,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_continuation_callback_set(
|
||||
RustFutureContinuation callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_u8(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_u8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_u8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint8_t ffi_nym_go_ffi_rust_future_complete_u8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_i8(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_i8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_i8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int8_t ffi_nym_go_ffi_rust_future_complete_i8(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_u16(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_u16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_u16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t ffi_nym_go_ffi_rust_future_complete_u16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_i16(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_i16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_i16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int16_t ffi_nym_go_ffi_rust_future_complete_i16(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_u32(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_u32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_u32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint32_t ffi_nym_go_ffi_rust_future_complete_u32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_i32(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_i32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_i32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int32_t ffi_nym_go_ffi_rust_future_complete_i32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_u64(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_u64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_u64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint64_t ffi_nym_go_ffi_rust_future_complete_u64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_i64(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_i64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_i64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
int64_t ffi_nym_go_ffi_rust_future_complete_i64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_f32(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_f32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_f32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
float ffi_nym_go_ffi_rust_future_complete_f32(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_f64(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_f64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_f64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
double ffi_nym_go_ffi_rust_future_complete_f64(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_pointer(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_pointer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_pointer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void* ffi_nym_go_ffi_rust_future_complete_pointer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_rust_buffer(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_rust_buffer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_rust_buffer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
RustBuffer ffi_nym_go_ffi_rust_future_complete_rust_buffer(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_poll_void(
|
||||
void* handle,
|
||||
void* uniffi_callback,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_cancel_void(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_free_void(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
void ffi_nym_go_ffi_rust_future_complete_void(
|
||||
void* handle,
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_nym_go_ffi_checksum_func_get_self_address(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_nym_go_ffi_checksum_func_init_ephemeral(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_nym_go_ffi_checksum_func_init_logging(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_nym_go_ffi_checksum_func_listen_for_incoming(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_nym_go_ffi_checksum_func_reply(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint16_t uniffi_nym_go_ffi_checksum_func_send_message(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
uint32_t ffi_nym_go_ffi_uniffi_contract_version(
|
||||
RustCallStatus* out_status
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
module nymffi
|
||||
|
||||
go 1.20
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user