Quickstart

Requestor in browser Quickstart

Introduction

In most of our examples, we demonstrate how to run a requestor script in Node.js. However, you can also run your scripts in a browser context. This example will explain how to do it.

Before getting started, you need to install and launch the Yagna service in version 0.15.2 or later. It can be installed using instructions for manual Yagna installation available here.

warning

Follow the Yagna installation instructions including the set up the app-key step.

Then, start the Yagna with a --api-allow-origin that allows you to handle REST API requests with a CORS policy:

yagna service run --api-allow-origin='http://localhost:8080'

The --api-allow-origin value should be set to the URL where your web application will be served.

In this example, we will use http-server with a default port 8080.

Setting up the project

mkdir web_golem
cd web_golem
npm install --global http-server

This will install the http-server utility to host our web page, where we will run our Golem app.

HTML page with embeded requestor script

Next, we'll create the main index.html file with the following content:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Requestor in browser</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
      integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <div class="container">
      <h1 class="pb-4">Hello Golem</h1>
      <div class="row pb-4">
        <h3>Options</h3>
        <div id="options" class="row">
          <div class="col-4 form-group">
            <label for="YAGNA_APPKEY">Yagna AppKey: </label>
            <input id="YAGNA_APPKEY" class="form-control" type="text" value="" />
          </div>
          <div class="col-4 form-group">
            <label for="YAGNA_API_BASEPATH">Yagna Api Url: </label>
            <input id="YAGNA_API_BASEPATH" class="form-control" type="text" value="http://127.0.0.1:7465" />
          </div>
        </div>
        <div class="row pb-4">
          <div class="col-4 form-group">
            <label for="IMAGE_TAG">Image Tag: </label>
            <input id="IMAGE_TAG" type="text" class="form-control" value="golem/alpine:latest" />
          </div>
          <div class="col-4 form-group">
            <label for="SUBNET_TAG">Subnet Tag: </label>
            <input id="SUBNET_TAG" type="text" class="form-control" value="public" />
          </div>
          <div class="col-4 form-group">
            <label for="PAYMENT_NETWORK">Payment Network: </label>
            <input id="PAYMENT_NETWORK" type="text" class="form-control" value="holesky" />
          </div>
        </div>
      </div>
      <div class="row pb-4">
        <h3>Actions</h3>
        <div>
          <button id="echo" class="btn btn-primary" onclick="run()">Echo Hello World</button>
        </div>
      </div>
      <div class="row">
        <div class="alert alert-info" role="alert">
          <h4 class="alert-heading">Debugging</h4>
          <p>You can see <code>@golem-sdk/golem-js</code> logs in your browser&apos;s <code>console</code> :)</p>
        </div>
        <h3>Results</h3>
        <div class="col">
          <ul id="results"></ul>
        </div>
      </div>
    </div>

    <script type="module">
      import { GolemNetwork } from "https://unpkg.com/@golem-sdk/golem-js";

      export function appendResults(result) {
        const resultsEl = document.getElementById("results");
        const li = document.createElement("li");
        li.appendChild(document.createTextNode(result));
        resultsEl.appendChild(li);
      }

      async function run() {
        // This line allows you to watch golem-js internal logs in the browser console!
        localStorage.debug = "golem-js:*";

        const key = document.getElementById("YAGNA_APPKEY").value;

        if (!key) {
          alert("You didn't provide your Yagna AppKey");
          return;
        }

        const url = document.getElementById("YAGNA_API_BASEPATH").value;
        const subnetTag = document.getElementById("SUBNET_TAG").value;
        const imageTag = document.getElementById("IMAGE_TAG").value;
        const network = document.getElementById("PAYMENT_NETWORK").value;

        // Define the order that we're going to place on the market
        const order = {
          demand: {
            workload: {
              imageTag,
            },
            subnetTag,
          },
          market: {
            rentHours: 0.5,
            pricing: {
              model: "linear",
              maxStartPrice: 0.5,
              maxCpuPerHourPrice: 1.0,
              maxEnvPerHourPrice: 0.5,
            },
          },
          payment: { network },
        };

        const glm = new GolemNetwork({
          api: { key, url },
        });

        glm.payment.events.on("invoiceAccepted", ({ invoice }) => appendResults(`Total cost: ${invoice.amount} GLM`));

        try {
          appendResults("Establishing a connection to the Golem Network");
          await glm.connect();
          appendResults("Request for renting a provider machine");
          const rental = await glm.oneOf({ order });
          appendResults("Rented resources from", rental.agreement.provider.name);
          await rental
            .getExeUnit()
            .then(async (exe) =>
              appendResults("Reply: " + (await exe.run(`echo 'Hello Golem! 👋 from ${exe.provider.name}!'`)).stdout),
            );
          appendResults("Finished all work with the resources");
          await rental.stopAndFinalize();
          appendResults("Finalized renting process");
        } catch (err) {
          console.error("Failed to run the example", err);
        } finally {
          await glm.disconnect();
        }
      }

      window.run = run;
    </script>
  </body>
</html>

In this layout, there are three elements:

  • An Options form, where you can define input params,
  • An Actions section with "Echo Hello World" button, which executes such a command on the remote Golem node,
  • A Results container, which displays the results

The js script defines:

  • the run() function that creates the body of the requestor script
  • a helper functions that will let us present the results in the browser window.

Now, ensure you:

  • have your Yagna APP key set to try_golem (as shown in the yagna installation instruction) and
  • have a running Yagna service started with the --api-allow-origin properly set to http://localhost:8080

Launch http-server in the project folder.

http-server
info

If, instead of using the try_golem app key defined by using the YAGNA_AUTOCONF_APPKEY variable, you have created a unique app key, make sure you update appkey value in the respective Option field.

We should see our app available in the browser:

Open localhost

If you click the Echo Hello World button, after a while, in the result container, you should get the result of the script:

  • the result of executing the script in the Results container
  • debug logs in the console window

Output logs