mysql 5.7 – Can’t use G in a handler?

I have a slightly annoying problem. This is on AWS Aurora Serverless – I have found a stored procedure somewhere for checking foreign keys, and modified it a little, adding a handler for 1146:

DELIMITER $$

DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS$$

CREATE
    PROCEDURE `ANALYZE_INVALID_FOREIGN_KEYS`(
        checked_database_name VARCHAR(64), 
        checked_table_name VARCHAR(64), 
        temporary_result_table ENUM('Y', 'N'))

    LANGUAGE SQL
    NOT DETERMINISTIC
    READS SQL DATA

    BEGIN
        DECLARE TABLE_SCHEMA_VAR VARCHAR(64);
        DECLARE TABLE_NAME_VAR VARCHAR(64);
        DECLARE COLUMN_NAME_VAR VARCHAR(64); 
        DECLARE CONSTRAINT_NAME_VAR VARCHAR(64);
        DECLARE REFERENCED_TABLE_SCHEMA_VAR VARCHAR(64);
        DECLARE REFERENCED_TABLE_NAME_VAR VARCHAR(64);
        DECLARE REFERENCED_COLUMN_NAME_VAR VARCHAR(64);
        DECLARE KEYS_SQL_VAR VARCHAR(1024);

        DECLARE done INT DEFAULT 0;

        DECLARE foreign_key_cursor CURSOR FOR
            SELECT
                `TABLE_SCHEMA`,
                `TABLE_NAME`,
                `COLUMN_NAME`,
                `CONSTRAINT_NAME`,
                `REFERENCED_TABLE_SCHEMA`,
                `REFERENCED_TABLE_NAME`,
                `REFERENCED_COLUMN_NAME`
            FROM 
                information_schema.KEY_COLUMN_USAGE 
            WHERE 
                `CONSTRAINT_SCHEMA` LIKE checked_database_name AND
                `TABLE_NAME` LIKE checked_table_name AND
                `REFERENCED_TABLE_SCHEMA` IS NOT NULL;

        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
        declare continue handler for 1243 begin end;
        declare continue handler for 1146
        begin
          select
            TABLE_SCHEMA_VAR,
            TABLE_NAME_VAR,
            COLUMN_NAME_VAR,
            CONSTRAINT_NAME_VAR,
            REFERENCED_TABLE_SCHEMA_VAR,
            REFERENCED_TABLE_NAME_VAR,
            REFERENCED_COLUMN_NAME_VARG
        end;

        IF temporary_result_table = 'N' THEN
            DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS;
            DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS;

            CREATE TABLE INVALID_FOREIGN_KEYS(
                `TABLE_SCHEMA` VARCHAR(64), 
                `TABLE_NAME` VARCHAR(64), 
                `COLUMN_NAME` VARCHAR(64), 
                `CONSTRAINT_NAME` VARCHAR(64),
                `REFERENCED_TABLE_SCHEMA` VARCHAR(64),
                `REFERENCED_TABLE_NAME` VARCHAR(64),
                `REFERENCED_COLUMN_NAME` VARCHAR(64),
                `INVALID_KEY_COUNT` INT,
                `INVALID_KEY_SQL` VARCHAR(1024)
            );
        ELSEIF temporary_result_table = 'Y' THEN
            DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS;
            DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS;

            CREATE TEMPORARY TABLE INVALID_FOREIGN_KEYS(
                `TABLE_SCHEMA` VARCHAR(64),
                `TABLE_NAME` VARCHAR(64),
                `COLUMN_NAME` VARCHAR(64),
                `CONSTRAINT_NAME` VARCHAR(64),
                `REFERENCED_TABLE_SCHEMA` VARCHAR(64),
                `REFERENCED_TABLE_NAME` VARCHAR(64),
                `REFERENCED_COLUMN_NAME` VARCHAR(64),
                `INVALID_KEY_COUNT` INT,
                `INVALID_KEY_SQL` VARCHAR(1024)
            );
        END IF;


        OPEN foreign_key_cursor;
        foreign_key_cursor_loop: LOOP
            FETCH foreign_key_cursor INTO
            TABLE_SCHEMA_VAR,
            TABLE_NAME_VAR,
            COLUMN_NAME_VAR,
            CONSTRAINT_NAME_VAR,
            REFERENCED_TABLE_SCHEMA_VAR,
            REFERENCED_TABLE_NAME_VAR,
            REFERENCED_COLUMN_NAME_VAR;
            IF done THEN
                LEAVE foreign_key_cursor_loop;
            END IF;

            SET @from_part = CONCAT('FROM ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', ' AS REFERRING ',
                 'LEFT JOIN `', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', ' AS REFERRED ',
                 'ON (REFERRING', '.`', COLUMN_NAME_VAR, '`', ' = ', 'REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ') ',
                 'WHERE REFERRING', '.`', COLUMN_NAME_VAR, '`', ' IS NOT NULL ',
                 'AND REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ' IS NULL');
            SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' INTO @invalid_key_count;');
            PREPARE stmt FROM @full_query;

            EXECUTE stmt;
            IF @invalid_key_count > 0 THEN
                INSERT INTO
                    INVALID_FOREIGN_KEYS
                SET
                    `TABLE_SCHEMA` = TABLE_SCHEMA_VAR,
                    `TABLE_NAME` = TABLE_NAME_VAR,
                    `COLUMN_NAME` = COLUMN_NAME_VAR,
                    `CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR,
                    `REFERENCED_TABLE_SCHEMA` = REFERENCED_TABLE_SCHEMA_VAR,
                    `REFERENCED_TABLE_NAME` = REFERENCED_TABLE_NAME_VAR,
                    `REFERENCED_COLUMN_NAME` = REFERENCED_COLUMN_NAME_VAR,
                    `INVALID_KEY_COUNT` = @invalid_key_count,
                    `INVALID_KEY_SQL` = CONCAT('SELECT ',
                        'REFERRING.', '`', COLUMN_NAME_VAR, '` ', 'AS "Invalid: ', COLUMN_NAME_VAR, '", ',
                        'REFERRING.* ',
                        @from_part, ';');
            END IF;
            DEALLOCATE PREPARE stmt;

        END LOOP foreign_key_cursor_loop;
    END$$

DELIMITER ;

When I copy this into the mysql client (or source the file), it complains about an error because of the G in this bit:

        declare continue handler for 1146
        begin
          select
            TABLE_SCHEMA_VAR,
            TABLE_NAME_VAR,
            COLUMN_NAME_VAR,
            CONSTRAINT_NAME_VAR,
            REFERENCED_TABLE_SCHEMA_VAR,
            REFERENCED_TABLE_NAME_VAR,
            REFERENCED_COLUMN_NAME_VARG
        end;

It is fine when I replace G with ;, but the output doesn’t look as good. And if I use a plain mysql 5.6, I get no error. Is there a way to fix this?

8 – Set cookie inside webform handler

Following up with my previous question, I need to set and retrieve a cookie in two difference places:

  • set – inside postSave() in a Webform handler
  • get – inside an event subscriber.

In looking around, it seems that there are a few different options for tools, such as SymfonyComponentHttpFoundationResponse and SymfonyComponentHttpFoundationCookie, or GuzzleHttpCookieSetCookie and GuzzleHttpCookieCookieJar.

For setting the cookie, if I try this in my webform handler:

$values = $webform_submission->getData();

$response = new Response();
$cookie = new Cookie('Dixon customer info form', $values('destination_url'), 0, '/' , NULL, FALSE);
$response->headers->setCookie($cookie);
$response->send();

I get redirected to a blank page. If I try this:

$values = $webform_submission->getData();

$cookie_jar = new CookieJar();
  // Get the current host.
  $host = Drupal::request()->getSchemeAndHttpHost();

  // Set a cookie for the specific form.
  $cookie = new SetCookie((
    'Name' => 'formEnterCookie',
    'Value' => $values('destination_url'),
    'Domain' => $host,
    'Secure' => FALSE,
  ));
  $cookie_jar->setCookie($cookie);

no cookie gets set. Using either option, how do I set my cookie within my webform handler?

javascript – iframe :Failed to launch because the scheme does not have a registered handler

Estou codando um projeto em html e linkei um google form ao botao de vagas, mais quando clico para abrir o form em um dispositivo android ele nao abre, procurei na internet o erro mas nao aparece nenhuma sloução em JS. segue foto do erro:
inserir a descrição da imagem aqui
Erro

inserir a descrição da imagem aqui
Situação do site apos o click

erro:

Failed to launch ‘intent://forms.gle/APWr5k57KL5ipnH56#Intent;package=com.google.android.gms;action=com.google.firebase.dynamiclinks.VIEW_DYNAMIC_LINK;scheme=https;S.browser_fallback_url=https://docs.google.com/forms/d/e/1FAIpQLSe0PP_iqXIVohaGxyQ8McbnxjJEHcYrev2BrGVMeeknSTyGRQ/viewform%3Fusp%3Dsend_form;end;’ because the scheme does not have a registered handler.

os kernel – Is a signal handler invocation an upcall?

I am struggling with the definition of an upcall. Presumably, an upcall is a mechanism that allows the kernel to execute a function in userspace. By this definition, an invocation of a signal handler is an upcall because the handler runs in userspace and it is executed by the kernel. However, I noticed that upcalls are sometimes counterposed to signal handlers, without any reasonable explanations. So, is signal handler invocation an upcall, and if not, why?

Simple Message Handler in Java with generics

I can easily put together a message handling set of generic apis in C# with the following quick and dirty code:

void Main()
{
    var messageClient = new MessageClient(new TestMessageHandler(), new AnotherTestMessageHandler());

    messageClient.Send(new TestMessage { Information = "Hello TestMessageHandler" });
    messageClient.Send(new AnotherTestMessage { Information = "Hello AnotherTestMessageHandler" });
}


public interface IMessageHandler<TMessage>
{
    void Handle(TMessage message);
}

public class TestMessage
{
    public string Information { get; set; }
}

public class TestMessageHandler : IMessageHandler<TestMessage>
{
    public void Handle(TestMessage message) => 
        Console.WriteLine($"I have handled {message.GetType()} and message is '{message.Information}'");
}

public class AnotherTestMessage
{
    public string Information { get; set; }
}

public class AnotherTestMessageHandler : IMessageHandler<AnotherTestMessage>
{
    public void Handle(AnotherTestMessage message) =>
        Console.WriteLine($"I have handled {message.GetType()} and message is '{message.Information}'");
}

public class MessageClient
{
    private object() receivers;
    
    public MessageClient(params object() receivers)
    {
        this.receivers = receivers;
    }
    
    public void Send<TMessage>(TMessage message)
    {
        var messageReceivers = receivers.OfType<IMessageHandler<TMessage>>();
        
        foreach (var messageReceiver in messageReceivers)
        {
            messageReceiver.Handle(message);
        }
    }
}

The purpose being to decouple the handling from the message and also the handling from the message initiators.

Question

What are the best ways to do this in Java without having to fight against type erasure? I have spent last few days reading around generics in java, and still have a lot to learn.

Thoughts

I have considered the following implementation which is based around a Map, however the compiler throws up a warning:

Warning:(67, 53) Unchecked cast: 'thoughts.dictionarythought.Handles<capture<?>>' to 'thoughts.dictionarythought.Handles<TMessage>'

package thoughts;

import org.junit.Assert;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class dictionarythought {

    @Test
    public void testReceive() {
        var message = new MyMessage();

        var registrations = new MessageHandlerRegistrations();
        var client = new MessageClient(registrations);

        MyMessageHandler handler = new MyMessageHandler();
        registrations.register(MyMessage.class, handler);


        client.send(message);
        client.send(new MyMessage2());

        Assert.assertEquals(message, handler.lastReceived);
    }



    public class MyMessage {

    }

    public class MyMessage2 {

    }

    public interface Handles<TMessage> {
        void handle(TMessage message);
    }

    public class MyMessageHandler implements Handles<MyMessage> {
        public MyMessage lastReceived;

        @Override
        public void handle(MyMessage message) {
            System.out.println("Received");
            lastReceived = message;
        }
    }

    public class MessageClient {

        private final MessageHandlerRegistrations registrations;

        MessageClient(MessageHandlerRegistrations registrations) {
            this.registrations = registrations;
        }

        public <TMessage> void send(TMessage message) {

            List<Handles<?>> registeredHandlers = registrations.getHandlersRegisteredForMessage(message);

            for (Handles<?> handler : registeredHandlers) {
                // compiler warning here
                Handles<TMessage> concreteHandler = (Handles<TMessage>)handler;
                concreteHandler.handle(message);
            }
        }
    }

    public class MessageHandlerRegistrations {
        Map<Class<?>, List<Handles<?>>> handlers;

        MessageHandlerRegistrations() {
            handlers = new HashMap<>();
        }

        public void register(Class<?> messageType, Handles<?> handler) {
            List<Handles<?>> messageHandlers = handlers.getOrDefault(messageType, null);

            if (messageHandlers == null) {
                messageHandlers = new ArrayList<>();
                handlers.put(messageType, messageHandlers);
            }

            messageHandlers.add(handler);
        }

        public <TMessage> List<Handles<?>> getHandlersRegisteredForMessage(TMessage message) {
            List<Handles<?>> registeredHandlers = handlers.get(message.getClass());

            if (registeredHandlers == null) {
                registeredHandlers = new ArrayList<>();
            }

            return registeredHandlers;
        }
    }
}

Custom Webform handler not working on Wizard Webform

I am attempting to write a simple webform handler to add to the end of a multi-step webform, ultimately to generate a barcode with the submitted data. I’ve had success with other handlers on single step forms but it looks like the handler causes the wizard form to freeze and not progress to the next step.

My suspicion is that I’m missing something in my plugin code but I can’t seem to find an answer to the problem in similar issues.

So far there’s no functionality attempted in the handler because the form freezes on the first step.

Ultimately I only need this handler to fire upon final submission of my form.

I’m trying to test for the forms state with $webform_submission->getState() but I can’t seem to get it right

  public function postSave(WebformSubmissionInterface $webform_submission, $update = TRUE) {
   
   $state = $webform_submission->getWebform()->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webform_submission->getState();
    if ($this->configuration('states') && in_array($state, $this->configuration('states'))) {
       //do something
      
    }
  }

Refactoring of two command handler implementations with F# in the context of event sourcing

I’ve written some F# code to handle commands in the context of event sourcing which works along the lines below:

  • Read Events from a specific event store stream
  • Build the current state in the given business / domain context accordingly to the events that has just been read right above
  • Decide new events based on the current state + read events + a given command
  • Write the event that have been newly “decided” to a given stream
  • If there is a version mismatch (leading to a failure when it comes to writing the new events to the given stream), there a resilience policy to retry the whole process a certain number of times with a given number of intervals in between (akin to what you can find in Polly).

There is basically two different implementations, a “standard” one and another one validating if some particular events are considered “not okay” slash errors, which makes the handle function returning a Result<'Ok, 'Error>.

Note: The terminology is a bit off but I’ve found the terms in quite a few places in the “Event Sourcing world”.

The code below works, but it’s super-duper redundant and it does feel overly bloated, bear in mind that what is below has already been refactored a couple of times, but I’m not too sure about how I can take this code to a whole new level of clarity.

Not only the code is a bit hard to wrap my own head around, it actually also pains me to see that some paths leading to nowhere cannot be prevented upfront in a declarative way, things like:

| None, Ok _
| Some _, Error _ -> NotImplementedException() |> raise

So what I’m asking is some help to refactor the code below into something easier to reason about, and if possible how can I avoid to process cases that aren’t supposed to happen by design.


CommandHandlerUtils.fs:

(<RequireQualifiedAccess>)
module My.EventSourcing.CommandHandlerUtils

open System

open FSharpPlus.Data

open My.FSharp.Resilience
open My.Infra.EventStore.Common


let internal getInvalidValueException _ _ = NotImplementedException()

let defaultWrongVersionRetryIntervals = Intervals.Seconds (1; 2; 4)

let createStreamKey aggregateName commandMessage =
    { FriendlyName = aggregateName; FriendlyId = commandMessage.AggregateId.ToString() }

/// Build the "history" states based on data available in the "history" events with the reBuild function
/// Note: "history": means "current" here.
let buildHistoryState reBuild (historyEvents: EventRead<'Data, 'Metadata> list) =
    historyEvents
    |> List.map (fun eventRead -> eventRead.Data)
    |> reBuild

/// Read the available events (ascending versions) from a event store and build the current state on top of them.
/// Both values (ie. events and state) are returned.
let buildHistory reBuild (readEvents: ReadEvents<'Data, 'Metadata>) streamKey =
    async {
        let! historyEvents = readEvents streamKey (All Forward)
        let historyState = buildHistoryState reBuild historyEvents
        return (historyEvents, historyState)
    }

/// Save the given events into an event store stream and return a result containing either:
/// - the events successfully written to the event store stream
/// - the error in case the operation has failed
let saveEvents (tryWriteEvents: TryWriteEvents<_, _, _>) historyEvents events streamKey =
    async {
        let eventsToWrite =
            events
            |> List.map (fun event ->
                { Causation = Root
                  Data = event
                  Metadata = () })
            |> NonEmptyList.ofList

        let writeVersion =
            if List.isEmpty historyEvents
            then Expected 1
            else Expected ((List.last historyEvents).StreamVersion + 1)

        return! tryWriteEvents streamKey writeVersion eventsToWrite
    }


GenericCommandHandler.fs:

(<RequireQualifiedAccess>)
module My.EventSourcing.GenericCommandHandler

open FSharpPlus.Data

open My.FSharp.Resilience
open My.Infra.EventStore.Common


// 1. Build history state from readEvents
// 2. Decide new events based on command message + history state
// 3. If any events:
// - a. Try Save / Write new events to given stream (ie. command message) into the Event Store
// - b. Return events + state if writing events did work, throw exception otherwise
// 4. If no events: Return events + state
// Note: default intervals => 4 attempts (1st attempt + 3 retries)
let handleWith aggregateName decide build reBuild readEvents tryWriteEvents commandMessage wrongVersionRetryIntervals =

    let handleCore =
        async {
            let streamKey = CommandHandlerUtils.createStreamKey aggregateName commandMessage
            let! (historyEventReads, historyState) = CommandHandlerUtils.buildHistory reBuild readEvents streamKey
            let events = decide commandMessage.Command historyState
            if List.isEmpty events then
                return (None, events, historyState)
            else
                let state = build historyState events
                let! eventWritesResult =
                    CommandHandlerUtils.saveEvents tryWriteEvents historyEventReads events streamKey
                return (Some eventWritesResult, events, state)
        }

    let acceptOutcome last _ (eventWritesResult, events, state) =
        match eventWritesResult with
        | None
        | Some (Ok _) -> Return (events, state)
        | Some (Error (UnexpectedStreamVersion _)) when not last -> TryAgain
        | Some (Error e) -> e |> WriteEventsException |> raise

    Retry.onValue acceptOutcome CommandHandlerUtils.getInvalidValueException wrongVersionRetryIntervals handleCore

let handle aggregateName decide build reBuild readEvents tryWriteEvents commandMessage =
    handleWith
        aggregateName
        decide
        build
        reBuild
        readEvents
        tryWriteEvents
        commandMessage
        CommandHandlerUtils.defaultWrongVersionRetryIntervals

ValidatingGenericCommandHandler.fs:

(<RequireQualifiedAccess>)
module My.EventSourcing.ValidatingGenericCommandHandler

open System

open My.FSharp.Resilience
open My.Infra.EventStore.Common


// 1. Build history state from readEvents
// 2. Decide new events based on command message + history state
// 3. If any events:
// - A. Events are wrapped with Ok
//   - a. Try Save / Write new events to given stream (ie. command message) into the Event Store
//   - b. Return events + state if writing events did work, throw exception otherwise
// - B. Return events wrapped with Error
// 4. If no events: Return (no) events + history state wrapped with Ok
// Note: default intervals => 4 attempts (1st attempt + 3 retries)
let handleWith aggregateName decide build reBuild readEvents tryWriteEvents commandMessage wrongVersionRetryIntervals =

    let handleCore =
        async {
            let streamKey = CommandHandlerUtils.createStreamKey aggregateName commandMessage
            let! (historyEventReads, historyState) = CommandHandlerUtils.buildHistory reBuild readEvents streamKey
            let eventsResult = decide commandMessage.Command historyState
            match eventsResult with
            | Error events ->
                return (None, Error events, historyState)
            | Ok events when List.isEmpty events ->
                return (None, Ok events, historyState)
            | Ok events ->
                let state = build historyState events
                let! writeEventsResult =
                    CommandHandlerUtils.saveEvents tryWriteEvents historyEventReads events streamKey
                return (Some writeEventsResult, Ok events, state)
        }

    let acceptOutcome last _ (eventWritesResult, eventsResult, state) =
        match eventWritesResult, eventsResult with
        | None, Error events -> events |> Error |> Return
        | Some (Ok _), Ok events -> (events, state) |> Ok |> Return
        | Some (Error (UnexpectedStreamVersion _)), Ok _ when not last -> TryAgain
        | Some (Error e), Ok _ -> e |> WriteEventsException |> raise
        | None, Ok _
        | Some _, Error _ -> NotImplementedException() |> raise

    Retry.onValue acceptOutcome CommandHandlerUtils.getInvalidValueException wrongVersionRetryIntervals handleCore

let handle aggregateName decide build reBuild readEvents tryWriteEvents message =
    handleWith
        aggregateName
        decide
        build
        reBuild
        readEvents
        tryWriteEvents
        message
        CommandHandlerUtils.defaultWrongVersionRetryIntervals
```

C# Event handler for WPF MVVM

So I’ve been learning about MVVM and I had a problem. I often had to start a thread to download or do some longer task in background and when it is done change some properties so the UI updates. The problem is that the UI will update only if I changed it from the main thread. So I often had to create DispatchTimers to wait for the thread to finish and then execute some code in main. Well this is my solution to it.

With this class you can simply go to your ViewModel constructor and do something like this:

ViewModelEventHandler.RegisterEventListener("EventName", EventAction);

EventAction being an action that is executed when the event is raised.
You can simply create an async Task that does its work in the background and it raises the event “EventName” and then EventAction() is executed in main thread. You just have to put new ViewModelEventHandler(); inside your main function.

I also use it a lot for communication between view models. You can raise an event in view model A and a completely unrelated view model B can execute code.

Here is my code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Threading;

namespace MVVM {
  public class EventData < T1, T2 > {
    public T1 eventState {
      get;
      set;
    }
    public T2 subs {
      get;
      set;
    }
  }

  class ViewModelEventHandler {
    // holds all events and their subscribed actions, the string is the event name, bool keeps track of if the event is currently raised, and List<Action> holds all the functions that will be executed when the event is raised
    private static Dictionary < string, EventData < bool, List<Action> >> eventList = new Dictionary < string, EventData <bool,List<Action> >> ();


    public ViewModelEventHandler() {
      DispatcherTimer timer = new DispatcherTimer();
      timer.Interval = TimeSpan.FromMilliseconds(1);
      timer.Tick += eventListen_Tick;
      timer.Start();
    }

    public static void RaiseEvent(string eventName) {
      try {
        eventList(eventName).eventState = true;
      }
      catch {}
    }

    public static void RegisterEventListener(string eventName, Action eventMethod) {
      foreach(var regEvent in eventList) {
        if (regEvent.Key == eventName) {
          eventList(eventName).subs.Add(eventMethod);
          return;
        }
      }

      eventList(eventName) = new EventData < bool, List < Action >> ();
      eventList(eventName).eventState = false;
      eventList(eventName).subs = new List < Action > ();
      eventList(eventName).subs.Add(eventMethod);

    }


    public static void RemoveEventListener(string eventName, Action eventMethod) {
      try {
        eventList(eventName).subs.Remove(eventMethod);
      }
      catch {}
    }

    public static void RemoveEvent(string eventName) {
      try {
        eventList.Remove(eventName);
      }
      catch {}
    }

    private void eventListen_Tick(object sender, EventArgs e) {
      foreach(var ev in eventList) {
        if (ev.Value.eventState) {
          ev.Value.eventState = false;
          foreach(Action eventSub in ev.Value.subs) {
            eventSub();
          }
        }
      }
    }

  }
}

javascript – In regards to real time turn based games, where should the turn handler be?

I’m currently developing a pool-like browser game. I’m stuck on where should I handle the turn changing, timer, etc.

Currently, turn timer (i.e. 15 seconds left to do action, then turn will change) is handled by the server. But the changing of turns itself is handled by the client (the browser itself).

Now in my current setup, whenever a player leaves window focus, the game gets out of sync. Should I migrate the turn change handling to the server instead?