utils_exports.js

import { displayForm } from "./common";
import { getSettings } from "./settings";

/**
 * Export topology as config.
 *
 * @param {object} e - Event object
 */
const exportTopology = (e) => {
  e.preventDefault();
  e.stopPropagation();
  document.querySelector("#importBtn").classList.remove("hidden");
  const exports = {
    description: "",
    producers: [],
    consumers: [],
    exchanges: [],
    queues: [],
    bindings: []
  };
  const exchanges = globalThis.scene.getObjectsInScene("Exchange");
  exchanges.forEach((val) => {
    let alternate = null;
    if (val.alternate) {
      alternate = val.alternate.name;
    }
    exports.exchanges.push({
      x: val.x,
      y: val.y,
      name: val.name,
      type: val.type,
      alternate
    });
  });
  const queues = globalThis.scene.getObjectsInScene("Queue");
  queues.forEach((val) => {
    const q = {
      x: val.x,
      y: val.y,
      name: val.name,
      type: val.type,
      ttl: val.ttl,
      maxLength: val.maxLength
    };
    if (val.dlx) {
      const exchangeIndex = exchanges.findIndex((e) => e.id === val.dlx.id);
      q.dlx = exchangeIndex;
    }
    exports.queues.push(q);
  });
  const bindings = globalThis.scene.getObjectsInScene("Binding");
  bindings.forEach((val) => {
    const exchangeIndex = exchanges.findIndex((e) => e.id === val.source.id);
    const queueIndex = queues.findIndex((q) => q.id === val.destination.id);
    if (exchangeIndex !== -1 && queueIndex !== -1) {
      exports.bindings.push({
        exchange: exchangeIndex,
        queue: queueIndex,
        routingKey: val.routingKey
      });
    }
  });
  const consumers = globalThis.scene.getObjectsInScene("Consumer");
  consumers.forEach((val) => {
    const consumes = [];
    val.queues.forEach((queue) => {
      const queueIndex = queues.findIndex((q) => q.id === queue.id);
      consumes.push(queueIndex);
    });
    exports.consumers.push({
      x: val.x,
      y: val.y,
      name: val.name,
      consumes,
      mode: val.mode
    });
  });
  const producers = globalThis.scene.getObjectsInScene("Producer");
  producers.forEach((val) => {
    const publishes = {};
    for (const key in val.publishes) {
      publishes[key] = {
        exchange: val.publishes[key].exchange.name,
        routingKey: val.publishes[key].routingKey,
        message: val.publishes[key].message
      };
    }
    exports.producers.push({
      x: val.x,
      y: val.y,
      name: val.name,
      publishes
    });
  });

  document.querySelector("#ImExport").value = JSON.stringify(exports);
  document.querySelector("#imexportPanel").classList.add("panel-wrap-out");
};

/**
 * Export topology as curl statements.
 *
 * @param {object} e - Event object
 */
const exportCurl = (e) => {
  e.preventDefault();
  e.stopPropagation();
  displayForm("imexportForm");
  document.querySelector("#importBtn").classList.add("hidden");
  let generatedString = "";
  const brokerSettings = getSettings();
  const { management } = brokerSettings;
  const { username } = brokerSettings;
  const { password } = brokerSettings;
  const { vhost } = brokerSettings;
  const exchanges = globalThis.scene.getObjectsInScene("Exchange");
  exchanges.forEach((val) => {
    const name = encodeURIComponent(val.name);
    const args = {};
    if (val.alternate !== null) {
      args["alternate-exchange"] = val.alternate.name;
    }
    generatedString +=
      `curl -u ${username}:${password} -i -H "content-type:application/json" -XPUT ${management}/exchanges/${vhost}/${name} -d '{"type": "${val.type}", "auto_delete": false, "durable": true, "internal": false, "arguments": ${
        JSON.stringify(
          args
        )
      }}'\n\n`;
  });
  const queues = globalThis.scene.getObjectsInScene("Queue");
  queues.forEach((val) => {
    const name = encodeURIComponent(val.name);
    const args = { "x-queue-type": val.type };
    if (val.dlx) {
      args["x-dead-letter-exchange"] = val.dlx.name;
      args["x-dead-letter-routing-key"] = val.dlxrk;
    }
    if (val.msgTtl) {
      args["x-message-ttl"] = val.msgTtl;
    }
    if (val.maxLength) {
      args["x-max-length"] = val.maxLength;
    }
    generatedString +=
      `curl -u ${username}:${password} -i -H "content-type:application/json" -XPUT ${management}/queues/${vhost}/${name} -d '{"auto_delete": false, "durable": true, "arguments": ${
        JSON.stringify(
          args
        )
      }}'\n\n`;
  });
  const bindings = globalThis.scene.getObjectsInScene("Binding");
  bindings.forEach((val) => {
    const exchangeIndex = exchanges.findIndex((e) => e.id === val.source.id);
    const queueIndex = queues.findIndex((q) => q.id === val.destination.id);
    if (exchangeIndex !== -1 && queueIndex !== -1) {
      const exchange = exchanges[exchangeIndex];
      const queue = queues[queueIndex];
      generatedString +=
        `curl -u ${username}:${password} -i -H "content-type:application/json" -XPOST ${management}/bindings/${vhost}/e/${
          encodeURIComponent(
            exchange.name
          )
        }/q/${
          encodeURIComponent(queue.name)
        } -d '{"routing_key": ${val.routingKey}, "arguments": {}}'\n\n`;
    }
  });
  document.querySelector("#ImExport").value = generatedString;
  document.querySelector("#imexportPanel").classList.add("panel-wrap-out");
};

/**
 * Export topology as rabbitmqadmin statements.
 *
 * @param {object} e - Event object
 */
const exportRabbitmqadmin = (e) => {
  e.preventDefault();
  e.stopPropagation();
  displayForm("imexportForm");
  document.querySelector("#importBtn").classList.add("hidden");
  let generatedString = "";
  const brokerSettings = getSettings();
  const { management } = brokerSettings;
  const { username } = brokerSettings;
  const { password } = brokerSettings;
  const url = new URL(management);
  let { vhost } = brokerSettings;
  if (vhost === "%2f") {
    vhost = "/";
  }
  const exchanges = globalThis.scene.getObjectsInScene("Exchange");
  exchanges.forEach((val) => {
    generatedString +=
      `rabbitmqadmin -H ${url.hostname} -u ${username} -p ${password} -V ${vhost} declare exchange `;
    generatedString += `name="${val.name}" type="${val.type}" durable=true`;
    if (val.alternate !== null) {
      generatedString += ` arguments='${
        JSON.stringify({ "alternate-exchange": val.alternate.name })
      }'`;
    }
    generatedString += `\n\n`;
  });
  const queues = globalThis.scene.getObjectsInScene("Queue");
  queues.forEach((val) => {
    const args = { "x-queue-type": val.type };
    if (val.dlx) {
      args["x-dead-letter-exchange"] = val.dlx.name;
      args["x-dead-letter-routing-key"] = val.dlxrk;
    }
    if (val.msgTtl) {
      args["x-message-ttl"] = val.msgTtl;
    }
    if (val.maxLength) {
      args["x-max-length"] = val.maxLength;
    }
    generatedString +=
      `rabbitmqadmin -H ${url.hostname} -u ${username} -p ${password} -V ${vhost} declare queue name="${val.name}" durable=true`;
    if (Object.keys(args).length !== 0) {
      generatedString += ` arguments='${JSON.stringify(args)}'`;
    }
    generatedString += "\n\n";
  });
  const bindings = globalThis.scene.getObjectsInScene("Binding");
  bindings.forEach((val) => {
    const exchangeIndex = exchanges.findIndex((e) => e.id === val.source.id);
    const queueIndex = queues.findIndex((q) => q.id === val.destination.id);
    if (exchangeIndex !== -1 && queueIndex !== -1) {
      const exchange = exchanges[exchangeIndex];
      const queue = queues[queueIndex];
      generatedString +=
        `rabbitmqadmin -H ${url.hostname} -u ${username} -p ${password} -V ${vhost} declare binding source="${exchange.name}" destination_type="queue" destination="${queue.name}" routing_key="${val.routingKey}"\n\n`;
    }
  });
  document.querySelector("#ImExport").value = generatedString;
  document.querySelector("#imexportPanel").classList.add("panel-wrap-out");
};

/**
 * Export topology as Terraform.
 *
 * @param {object} e - Event object
 */
const exportTerraform = (e) => {
  e.preventDefault();
  e.stopPropagation();
  displayForm("imexportForm");
  document.querySelector("#importBtn").classList.add("hidden");
  let generatedString = "";
  const brokerSettings = getSettings();
  const { management } = brokerSettings;
  const { username } = brokerSettings;
  const { password } = brokerSettings;
  const url = new URL(management);
  let { vhost } = brokerSettings;
  if (vhost === "%2f") {
    vhost = "/";
  }
  generatedString += `terraform {
  required_providers {
    rabbitmq = {
      source = "cyrilgdn/rabbitmq"
      version = "1.8.0"
    }
  }
}
provider "rabbitmq" {
  endpoint = "${url.origin}"
  username = "${username}"
  password = "${password}"
}
resource "rabbitmq_vhost" "vhost" {
  name = "${vhost}"
}
`;
  const exchanges = globalThis.scene.getObjectsInScene("Exchange");
  exchanges.forEach((val) => {
    const name = val.name.replace(/ /g, "-");
    generatedString += `resource "rabbitmq_exchange" "${name}" {
  name  = "${val.name}"
  vhost = "\${rabbitmq_vhost.vhost.name}"
  settings {
    type        = "${val.type}"
    durable     = true
    auto_delete = false
  }
}
`;
  });
  const queues = globalThis.scene.getObjectsInScene("Queue");
  queues.forEach((val) => {
    const name = val.name.replace(/ /g, "-");
    generatedString += `variable "${name}args" {
  default = <<EOF
  {
`;
    const extra = [`"x-queue-type": "${val.type}"`];
    if (val.dlx) {
      extra.push(`"x-dead-letter-exchange": "${val.dlx.name}"`);
      extra.push(`"x-dead-letter-routing-key": "${val.dlxrk}"`);
    }
    if (val.msgTtl) {
      extra.push(`"x-message-ttl": ${val.msgTtl}`);
    }
    if (val.maxLength) {
      extra.push(`"x-max-length": ${val.maxLength}`);
    }
    generatedString += `    ${extra.join(",\n    ")}`;
    generatedString += `
  }
  EOF
}
`;
    generatedString += `resource "rabbitmq_queue" "${name}" {
  name  = "${val.name}"
  vhost = "\${rabbitmq_vhost.vhost.name}"
    
  settings {
    durable     = true
    auto_delete = false`;
    generatedString += `
    arguments_json = "\${var.${name}args}"`;
    generatedString += `
  }
}
`;
  });

  const bindings = globalThis.scene.getObjectsInScene("Binding");
  bindings.forEach((val) => {
    const srcName = val.source.name.replace(/ /g, "-");
    const destName = val.destination.name.replace(/ /g, "-");
    generatedString += `resource "rabbitmq_binding" "${srcName}${destName}" {
  source           = "\${rabbitmq_exchange.${srcName}.name}"
  vhost            = "\${rabbitmq_vhost.vhost.name}"
  destination      = "\${rabbitmq_queue.${destName}.name}"
  destination_type = "queue"
  routing_key      = "${val.routingKey}"
}
`;
  });

  document.querySelector("#ImExport").value = generatedString;
  document.querySelector("#importBtn").classList.add("hidden");
  document.querySelector("#imexportPanel").classList.add("panel-wrap-out");
};

/**
 * Export topology as AsyncApi.
 *
 * @param {object} e - Event object
 */
const exportAsyncApi = (e) => {
  e.preventDefault();
  e.stopPropagation();
  displayForm("imexportForm");
  document.querySelector("#importBtn").classList.add("hidden");
  let generatedString = "";
  const brokerSettings = getSettings();
  const { host } = brokerSettings;
  const { title, description, version } = brokerSettings.asyncapi;
  let { vhost } = brokerSettings;
  if (vhost === "%2f") {
    vhost = "/";
  }
  const exchanges = globalThis.scene.getObjectsInScene("Exchange");
  const queues = globalThis.scene.getObjectsInScene("Queue");

  generatedString += `asyncapi: 3.0.0
info:
  title: ${title}
  description: ${description}
  version: ${version}
  termsOfService: https://asyncapi.org/terms/
  contact:
    name: API Support
    url: https://www.asyncapi.org/support
    email: support@asyncapi.org
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.htm  
servers:
  production:
    host: ${host}
    protocol: amqps
    protocolVersion: 0.9.1
    description: Production broker.
    tags:
      - name: env:production
        description: This environment is the live environment available for final users
channels:
`;
  exchanges.forEach((val) => {
    if (val.type === "topic") {
      val.bindings.forEach((v) => {
        if (v.routingKey !== "#") {
          let nameAddition = "";
          if (v.routingKey) {
            nameAddition = "_" + v.routingKey;
          }
          generatedString += `  ${
            val.name.replaceAll(" ", "_")
          }${nameAddition}          
    address: '${v.routingKey}'
    messages:
      event:
        $ref: '#/components/messages/Event'
    bindings:
      amqp:
        is: routingKey
        exchange:
          name: ${v.source.name}
          type: 'topic'
          durable: true
          autoDelete: false
          vhost: ${vhost}
`;
        }
      });
    } else {
      generatedString += `  ${val.name.replaceAll(" ", "_")}:
    messages:
      event:
        $ref: '#/components/messages/Event'
    bindings:
      amqp:
        is: routingKey
        exchange:
          name: ${val.name}
          type: '${val.type}'
          durable: true
          autoDelete: false
          vhost: ${vhost}
`;
    }
  });

  queues.forEach((val) => {
    generatedString += `  ${val.name.replaceAll(" ", "_")}:
    messages:
      event:
        $ref: '#/components/messages/Event'
    bindings:
      amqp:
        is: queue
        queue:
          name: ${val.name}
          type: ${val.type}
          durable: true
          exclusive: false
          autoDelete: false
`;
  });

  generatedString += `operations:`;
  exchanges.forEach((val) => {
    val.bindings.forEach((v) => {
      if (v.routingKey !== "#") {
        let nameAddition = "";
        if (v.routingKey) {
          nameAddition = "_" + v.routingKey;
        }
        generatedString += `
  send${val.name}/${v.routingKey}:
    channel:
      $ref: '#/channels/${val.name.replaceAll(" ", "_")}${nameAddition}'
    action: send`;
      }
    });
  });

  queues.forEach((val) => {
    generatedString += `
  receive${val.name.replaceAll(" ", "_")}:
    channel:
      $ref: '#/channels/${val.name.replaceAll(" ", "_")}'
    action: receive`;
  });

  // remove two to start again
  //generatedString = generatedString.slice(0, -2)
  generatedString += `  
components:
  messages:
    Event:
      name: EventName
      title: Event Title
      summary: Summary of the event.
      description: Event description
      contentType: application/json
      tags:
        - name: message
        - name: example
      headers:
        type: object
        properties:
          correlationId:
            description: Correlation ID set by application
            type: string
          applicationInstanceId:
            description: Unique identifier for a given instance of the publishing application
            type: string
      payload:
        type: object
        additionalProperties: false
        properties:
          created:
            type: string
            description: The date and time a message was sent.
            format: datetime
          name:
            type: string
            description: The name of the message was sent.
          value:
            type: string
            description: The value of the message was sent.`;

  document.querySelector("#ImExport").value = generatedString;
  document.querySelector("#imexportPanel").classList.add("panel-wrap-out");
};

export {
  exportAsyncApi,
  exportCurl,
  exportRabbitmqadmin,
  exportTerraform,
  exportTopology
};