OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-cogserver / examples / websockets / script.js

226 lines · javascript ref:
/*
  WebSocket connection Script
  Uses standard W3C WebSocket API, not socket.io API
  Connects to a local websocket server

  created 7 Jan 2021
  modified 17 Jan 2021
  by Tom Igoe

  Revised and adapted for the CogServer, Linas Vepstas August 2022
*/
let server;
let endpoint;
let serverURL;
let errorState = "";

let socket;
// variables for the DOM elements:
let serverText;
let endpointMenu;
let endpointType;
let urlSpan;
let connectionSpan;
let connectButton;
let replySpan;
let outgoingText;

function setup()
{
  // Get all the DOM elements that need listeners.
  serverText = document.getElementById('server-box');
  endpointMenu = document.getElementById('endpoint-menu');
  endpointType = document.getElementById('endpoint');
  urlSpan = document.getElementById('full-url');
  replySpan = document.getElementById('reply');
  outgoingText = document.getElementById('outgoing');
  connectionSpan = document.getElementById('connection');
  connectButton = document.getElementById('connectButton');

  // Set the listeners.
  serverText.addEventListener('change', setServer);
  // For textarea, listen to keydown to catch Enter key (but not Shift+Enter)
  outgoingText.addEventListener('keydown', function(event) {
    if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault(); // Prevent default newline
      sendMessage();
    }
  });
  connectButton.addEventListener('click', changeConnection);

  // Initial server and endpoint - use current hostname.
  server = `ws://${window.location.hostname}:${window.location.port}/`;
  endpoint = 'json';
  serverURL = server + endpoint;

  // DOM elements
  serverText.value = server;
  endpointMenu.value = endpoint;
  urlSpan.innerHTML = serverURL;
  openSocket(serverURL);
}

// Called when user enters a new CogServer base URL
function setServer() {
  server = serverText.value;
  endpoint = endpointMenu.value;
  serverURL = server + endpoint;
  console.log("Enter setServer, new url=" + serverURL);
}

function openSocket(url)
{
  // Open the socket.
  socket = new WebSocket(url);
  socket.addEventListener('open', openConnection);
  socket.addEventListener('close', closeConnection);
  socket.addEventListener('message', readReplyMessage);
  socket.addEventListener('error', reportError);
}


function changeConnection(event)
{
  console.log("button click; socket state=" + socket.readyState + " vs closed=" + WebSocket.CLOSED);
  // Open the connection if it's closed, or close it if open.
  if (socket.readyState === WebSocket.CLOSED) {
    server = serverText.value;
    endpoint = endpointMenu.value;
    serverURL = server + endpoint;
    console.log("Opening socket connection to " + serverURL);
    openSocket(serverURL);
  } else {
    console.log("close socket");
    socket.close();
  }
}

function openConnection()
{
  errorState = "";
  // Display the change of state:
  serverText.value = server;
  urlSpan.innerHTML = serverURL;
  connectionSpan.innerHTML = "true";
  connectionSpan.className = "connected";
  connectButton.value = "Disconnect";

  if (endpoint == 'json')
    endpointType.innerHTML = "JSON";
  else if (endpoint == 'scm')
    endpointType.innerHTML = "Guile Scheme";
  else if (endpoint == 'py')
    endpointType.innerHTML = "Python";
  else if (endpoint == 'sexpr')
    endpointType.innerHTML = "S-Expressions";
}

function closeConnection()
{
  // Display the change of state:
  urlSpan.innerHTML = "none";
  connectionSpan.innerHTML = "false" + errorState;
  connectionSpan.className = "";
  connectButton.value = "Connect";
  endpointType.innerHTML = "none";
  replySpan.innerHTML = "";
}

function reportError(event)
{
  console.log("oh nooo=" + event.data + "<<");
  errorState = "; Unable to connect to \'" + serverURL + "\'";
}

// Display the reply message
function readReplyMessage(event)
{
  console.log("got reply=" + event.data + "<<");
  // Append each message chunk (don't replace) so errors aren't lost
  replySpan.innerHTML += event.data;
}

function sendMessage(keepCommand)
{
  console.log("enter sendmsg; socket state=" + socket.readyState + " vs open=" + WebSocket.OPEN);
  // If the socket's open, send a message:
  if (socket.readyState === WebSocket.OPEN) {
    // Clear previous results before sending new command
    replySpan.innerHTML = "";
    winl = outgoingText.value;
    console.log("going to send this" + winl + "<<");
    socket.send(winl);
    // Clear the textarea after sending (unless keepCommand is true)
    if (!keepCommand) {
      outgoingText.value = '';
    }
  }
}

// Function to run a specific command with the correct endpoint
function runCommand(command, requiredEndpoint)
{
  console.log("Running command: " + command + " with endpoint: " + requiredEndpoint);

  // Always set the command in the textarea first so user can see it
  outgoingText.value = command;

  // Check if we need to switch endpoints
  if (endpoint !== requiredEndpoint) {
    // Update the endpoint
    endpoint = requiredEndpoint;
    endpointMenu.value = requiredEndpoint;

    // If connected, disconnect first to reconnect with new endpoint
    if (socket && socket.readyState === WebSocket.OPEN) {
      console.log("Switching endpoint, disconnecting first");
      socket.close();
      // Wait a bit for close to complete, then reconnect
      setTimeout(function() {
        // Re-set the command since connectAndSend might clear it
        outgoingText.value = command;
        connectAndSend();
      }, 500);
    } else {
      // Not connected, just connect and send
      connectAndSend();
    }
  } else if (socket && socket.readyState === WebSocket.OPEN) {
    // Already connected to the right endpoint, just send
    sendMessage(true); // Keep command in textarea
  } else {
    // Right endpoint but not connected
    connectAndSend();
  }
}

// Helper function to connect and send after connection
function connectAndSend()
{
  server = serverText.value;
  endpoint = endpointMenu.value;
  serverURL = server + endpoint;
  console.log("Connecting to " + serverURL + " to send command");

  // Save the command before connecting since sendMessage will clear it
  var commandToSend = outgoingText.value;

  // Create a one-time listener for the open event
  var tempSocket = new WebSocket(serverURL);
  tempSocket.addEventListener('open', function() {
    socket = tempSocket;
    openConnection();
    // Restore the command and send it after a short delay to ensure connection is ready
    setTimeout(function() {
      outgoingText.value = commandToSend;
      sendMessage(true); // Keep command in textarea
    }, 100);
  });
  tempSocket.addEventListener('close', closeConnection);
  tempSocket.addEventListener('message', readReplyMessage);
  tempSocket.addEventListener('error', reportError);
}

// add a listener for the page to load:
window.addEventListener('load', setup);