Skip to content

Commit

Permalink
Merge branch 'development' into development_group_deployment_files
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamedElmdary committed Oct 15, 2023
2 parents 6c97d52 + 05a938a commit 03b4a91
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 16 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This repo contains the typescript clients and projects for Threefold grid.
- [rmb peer client](./packages/rmb_peer_client/README.md)
- [rmb peer server](./packages/rmb_peer_server/README.md)
- [Playground](./packages/playground/README.md)
- [UI](./packages/UI/README.md)

## Requirements

Expand Down
10 changes: 7 additions & 3 deletions packages/UI/docs/pdf_viewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ To use the PDF Signer Web Component, follow these steps:

2. Navigate to the `repository/packages/UI` directory.

3. Run `yarn build` to generate the required distribution files.
3. Choose which provider you are going to use [see providers section](#using-providers-and-extensions)

4. Locate the `dist` folder created in the previous step.
4. Run `yarn build` to generate the required distribution files.

5. Copy the `dist/threefold-ui.umd.js` file and include it in your project's HTML files.
5. Locate the `dist` folder created in the previous step.

6. Copy the `dist/threefold-ui.umd.js` file and include it in your project's HTML files.

```html
<body>
Expand Down Expand Up @@ -101,6 +103,8 @@ Here's an example of how to use the PDF Signer Web Component in your HTML file:

In the example above, replace `<pdf-url>` and `<endpoint-url>` with the actual URLs for your PDF document and the destination where signed documents should be sent. Also, for the `<network>`, use one of the following network options: `[main, test, qa, dev]`.

PS: Please make sure that you have a `PDF URL` with `CORS-ORIGIN` enabled.

Feel free to customize the HTML structure and styles to match your application's design and requirements.

**Now you can serve your HTML file on any live-server plugin.**
Expand Down
8 changes: 5 additions & 3 deletions packages/UI/docs/script_editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ To create an instance of the Script Editor, follow these steps:

2. Navigate to the `repository/packages/UI` directory.

3. Run `yarn build` to generate the required distribution files.
3. Choose which provider you are going to use [see providers section](#using-providers-and-extensions)

4. Locate the `dist` folder created in the previous step.
4. Run `yarn build` to generate the required distribution files.

5. Copy the `dist/threefold-ui.umd.js` file and include it in your project's HTML files.
5. Locate the `dist` folder created in the previous step.

6. Copy the `dist/threefold-ui.umd.js` file and include it in your project's HTML files.

```html
<body>
Expand Down
6 changes: 1 addition & 5 deletions packages/UI/examples/server-example/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,12 @@ const verify = async (payload: Payload) => {

app.post("/api/verify", async (req: Request, res: Response) => {
const payload: Payload = req.body;
let content: Uint8Array = new Uint8Array();
try {
if (payload.pdfUrl) {
const response = await axios.get(payload.pdfUrl, { responseType: "arraybuffer" });
content = Uint8Array.from(Buffer.from(response.data, "base64"));
} else {
content = Uint8Array.from(Buffer.from(payload.content || "", "base64"));
payload.content = Uint8Array.from(Buffer.from(response.data, "base64")).toString();
}

payload.content = content.toString();
const verified = await verify(payload);

if (verified) {
Expand Down
5 changes: 4 additions & 1 deletion packages/UI/src/components/PDFSignerViewComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ export default {
pdfData.value = data.toString();
numOfPages.value = pdf.numPages;
} catch (error: any) {
showError({ isError: true, errorMessage: error.message });
showError({
isError: true,
errorMessage: "Please make sure that you have provided a PDF URL with CORS enabled.",
});
} finally {
loadingPdf.value = false;
}
Expand Down
18 changes: 18 additions & 0 deletions packages/grid_client/scripts/add_node_to_network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getClient } from "./client_loader";
import { log } from "./utils";

async function main() {
const grid3 = await getClient();
try {
// if the network is not created, it will create one and add this node to it.
const res = await grid3.networks.addNode({
name: "wedtest",
ipRange: "10.249.0.0/16",
nodeId: 14,
});
log(res);
} finally {
grid3.disconnect();
}
}
main();
1 change: 1 addition & 0 deletions packages/grid_client/src/high_level/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class TwinDeployment {
public nodeId: number,
public network: Network | null = null,
public solutionProviderId: number | null = null,
public returnNetworkContracts = false,
) {}
}

Expand Down
57 changes: 57 additions & 0 deletions packages/grid_client/src/high_level/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Addr } from "netaddr";

import { DeploymentFactory, Network } from "../primitives";
import { WorkloadTypes, Znet } from "../zos";
import { HighLevelBase } from "./base";
import { Operations, TwinDeployment } from "./models";

class NetworkHL extends HighLevelBase {
async addNode(networkName: string, ipRange: string, nodeId: number, solutionProviderId: number, description = "") {
const network = new Network(networkName, ipRange, this.config);
await network.load();
const networkMetadata = JSON.stringify({
type: "network",
name: networkName,
projectName: this.config.projectName,
});

const workload = await network.addNode(nodeId, networkMetadata, description);
if (!workload) {
throw Error(`Node ${nodeId} is already exist on network ${networkName}`);
}

const twinDeployments: TwinDeployment[] = [];
const deploymentFactory = new DeploymentFactory(this.config);
const deployment = deploymentFactory.create([workload], 0, networkMetadata, description, 0);
twinDeployments.push(
new TwinDeployment(deployment, Operations.deploy, 0, nodeId, network, solutionProviderId, true),
);

if (!(await network.exists())) {
return twinDeployments;
}
// update network if it's already exist
for (const deployment of network.deployments) {
const d = await deploymentFactory.fromObj(deployment);
for (const workload of d.workloads) {
const data = workload.data as Znet;
if (workload.type !== WorkloadTypes.network || !Addr(network.ipRange).contains(Addr(data.subnet))) {
continue;
}
workload.data = network.updateNetwork(data);
workload.version += 1;
break;
}
twinDeployments.push(new TwinDeployment(d, Operations.update, 0, 0, network, solutionProviderId, true));
}
return twinDeployments;
}

async hasNode(networkName: string, ipRange: string, nodeId: number): Promise<boolean> {
const network = new Network(networkName, ipRange, this.config);
await network.load();
return network.nodeExists(nodeId);
}
}

export { NetworkHL };
41 changes: 41 additions & 0 deletions packages/grid_client/src/high_level/twinDeploymentHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,43 @@ class TwinDeploymentHandler {
return deployments;
}

async checkFarmIps(twinDeployments: TwinDeployment[]) {
const farmIPs: Map<number, number> = new Map();

for (const twinDeployment of twinDeployments) {
if (twinDeployment.operation !== Operations.deploy) {
continue;
}

if (twinDeployment.publicIps === 0) {
continue;
}

const node = await this.nodes.getNode(twinDeployment.nodeId);
if (!node) {
continue;
}
if (!farmIPs.has(node.farmId)) {
farmIPs.set(node.farmId, twinDeployment.publicIps);
} else {
farmIPs.set(node.farmId, farmIPs.get(node.farmId)! + twinDeployment.publicIps);
}
}

for (const farmId of farmIPs.keys()) {
const _farm = await this.tfclient.farms.get({ id: farmId });
const freeIps = _farm.publicIps.filter(res => res.contractId === 0).length;

if (freeIps < farmIPs.get(farmId)!) {
throw Error(
`Farm ${farmId} doesn't have enough public IPs: requested IPs=${farmIPs.get(
farmId,
)}, available IPs=${freeIps}`,
);
}
}
}

async checkNodesCapacity(twinDeployments: TwinDeployment[]) {
for (const twinDeployment of twinDeployments) {
let workloads: Workload[] = [];
Expand Down Expand Up @@ -439,6 +476,8 @@ class TwinDeploymentHandler {
twinDeployments = await this.merge(twinDeployments);
await this.validate(twinDeployments);
await this.checkNodesCapacity(twinDeployments);
await this.checkFarmIps(twinDeployments);

const contracts = { created: [], updated: [], deleted: [] };
const resultContracts = { created: [], updated: [], deleted: [] };
let nodeExtrinsics: ExtrinsicResult<Contract>[] = [];
Expand Down Expand Up @@ -476,6 +515,7 @@ class TwinDeploymentHandler {
if (twinDeployment.deployment.challenge_hash() === contract.contractType.nodeContract.deploymentHash) {
twinDeployment.deployment.contract_id = contract.contractId;
if (
twinDeployment.returnNetworkContracts ||
!(
twinDeployment.deployment.workloads.length === 1 &&
twinDeployment.deployment.workloads[0].type === WorkloadTypes.network
Expand All @@ -500,6 +540,7 @@ class TwinDeploymentHandler {
if (twinDeployment.deployment.challenge_hash() === contract.contractType.nodeContract.deploymentHash) {
twinDeployment.nodeId = contract.contractType.nodeContract.nodeId;
if (
twinDeployment.returnNetworkContracts ||
!(
twinDeployment.deployment.workloads.length === 1 &&
twinDeployment.deployment.workloads[0].type === WorkloadTypes.network
Expand Down
17 changes: 17 additions & 0 deletions packages/grid_client/src/modules/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ class FarmFilterOptions {
@Expose() @IsOptional() @IsInt() @Min(1) nodeRentedBy?: number;
@Expose() @IsOptional() @IsInt() page?: number;
@Expose() @IsOptional() @IsInt() size?: number;
@Expose() @IsOptional() @IsInt() farmId?: number;
}

class CalculatorModel {
Expand Down Expand Up @@ -639,6 +640,20 @@ class pingFarmModel {
@Expose() @IsInt() @IsNotEmpty() @Min(1) farmId: number;
}

class NetworkAddNodeModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) name: string;
@Expose() @IsString() @IsNotEmpty() ipRange: string;
@Expose() @IsInt() @IsNotEmpty() @Min(1) nodeId: number;
@Expose() @IsInt() @IsOptional() solutionProviderId?: number;
@Expose() @IsString() @IsOptional() description?: string;
}

class NetworkHasNodeModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) name: string;
@Expose() @IsString() @IsNotEmpty() ipRange: string;
@Expose() @IsInt() @IsNotEmpty() @Min(1) nodeId: number;
}

class NetworkGetModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) name: string;
}
Expand Down Expand Up @@ -768,6 +783,8 @@ export {
SetServiceContractFeesModel,
SetServiceContractMetadataModel,
GetServiceContractModel,
NetworkAddNodeModel,
NetworkHasNodeModel,
NetworkGetModel,
NodeGetModel,
SetDedicatedNodeExtraFeesModel,
Expand Down
28 changes: 26 additions & 2 deletions packages/grid_client/src/modules/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,49 @@ import * as PATH from "path";
import { GridClientConfig } from "../config";
import { expose } from "../helpers/expose";
import { validateInput } from "../helpers/validator";
import { NetworkHL } from "../high_level/network";
import { BaseModule } from "./base";
import { NetworkGetModel } from "./models";
import { NetworkAddNodeModel, NetworkGetModel, NetworkHasNodeModel } from "./models";
import { checkBalance } from "./utils";

class NetworkModule extends BaseModule {
moduleName = "networks";
network: NetworkHL;

constructor(public config: GridClientConfig) {
super(config);
this.network = new NetworkHL(config);
}

@expose
@validateInput
@checkBalance
async addNode(options: NetworkAddNodeModel) {
const twinDeployments = await this.network.addNode(
options.name,
options.ipRange,
options.nodeId,
options.solutionProviderId!,
options.description,
);
return { contracts: await this.twinDeploymentHandler.handle(twinDeployments) };
}

@expose
async list(): Promise<string[]> {
return await this._list();
}

@expose
@validateInput
async hasNode(options: NetworkHasNodeModel): Promise<boolean> {
return await this.network.hasNode(options.name, options.ipRange, options.nodeId);
}

@expose
@validateInput
async getWireGuardConfigs(options: NetworkGetModel) {
const path = PATH.join(this.getDeploymentPath(options.name), "info.json");
const path = PATH.join(this.config.storePath, this.moduleName, options.name, "info.json");
const networkInfo = await this.backendStorage.load(path);
return networkInfo["wireguardConfigs"];
}
Expand Down
5 changes: 3 additions & 2 deletions packages/grid_client/src/primitives/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface FarmInfo {
interface PublicIps {
id: string;
ip: string;
contractId: number;
contract_id: number; // Added to match the one in the farm interface || TODO: Should we replace the whole http requests to be done with the gridProxy.
gateway: string;
}

Expand Down Expand Up @@ -176,7 +176,7 @@ class Nodes {
farms = await this.getAllFarms(url);
}
return farms
.filter(farm => farm.publicIps.filter(ip => ip.contractId === 0).length > 0)
.filter(farm => farm.publicIps.filter(ip => ip.contract_id === 0).length > 0)
.map(farm => farm.farmId)
.includes(farmId);
}
Expand Down Expand Up @@ -382,6 +382,7 @@ class Nodes {
node_has_gpu: options.nodeHasGPU,
node_rented_by: options.nodeRentedBy,
node_certified: options.nodeCertified,
farm_id: options.farmId,
};
return Object.entries(params)
.map(param => param.join("="))
Expand Down

0 comments on commit 03b4a91

Please sign in to comment.