skip to Main Content

I’m working on a web-based game where a player chooses a type of action, and then a space on which to take that action. Rather than write the web infrastructure first (I’m planning on using express.js) I’m writing the actions first, to see if I can create a nice clean interface.

So for instance, a player chooses ‘Trees’ via request, and the code for what happens when a player selects Trees is

  async play(): Promise<void> {
    const hex = await game.ask<Hex>(new SelectHex());
    game.placeToken(hex, "greenery");
  }

I understand how backwards this might be, because game.ask is now (eventually) responsible for writing the HTTP response, while also owning the Promise. I’m avoiding trying to write something a little less elegant, like

  async play() {
    return new SelectHex((hex) => game.placeToken(hex, "greenery"));
  }

which doesn’t look so inelegant here, but can be more complicated.

Ideally, the express endpoint that receives the hex will need access to the Promise, so as to call its resolve method.

Is this pattern feasible? I realize there’s probably more information necessary, but I’m not sure what else to write.

2

Answers


  1. If I understood this right:

    The pattern you’re considering—using async/await in server-side code to handle user interactions that span multiple HTTP requests—is not feasible in the context of a stateless web architecture like Express.js. The server cannot maintain the execution context (like a pending Promise) across multiple requests, they are completely independent.

    When you write:

    async play(): Promise<void> {
      const hex = await game.ask<Hex>(new SelectHex());
      game.placeToken(hex, "greenery");
    }
    

    You’re effectively trying to pause the server-side function play() until the user selects a hex, which involves a new HTTP request from the client. However, the server cannot keep the function execution pending across multiple HTTP requests because the execution context is lost once the initial request is completed.

    So, in order for you to do what you intend to, you will need to create a state on the server: be it a state machine, session, whatever.

    Login or Signup to reply.
  2. You could translate your requests into a JSON API and then provide all of the necessary information along with a UUID to track its progress.

    Simply set a series of commands in an array of JSON objects, each one having a transaction ID and individual UUIDs, then make a function that calls each command one by one and when there are no more active UUIDs for a specific transactionID then send the API (JSON object) which will be stored by transactionID. You can store functions as strings then eval them or as functions and then execute them any time.

    API message example:

    { 
       type: "play"
       hex: "28928491"
       onSend: function() { game.placeToken(hex, "greenery"); }
       sendAfter: [{ property: "hex", uuid: "28928491", f: function() { game.ask<Hex>(new SelectHex()) } } ]
    }
    
    
    while (message.sendAfter.length > 0) { 
      // take first object and then execute some command with object.f();
      // potentially creating additional APIs etc 
      // this is essentially a promise just customized to work with your code
      //  (as far as I can tell anyways since theres a lot missing)
    }
    message.onSend();
    sendMessage(message);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search