Running on main thread issues when using _channel.Bind() in Pusher SDK

That`s my code which we changed a lot because of an error!

This is “LoadingRoom.cs”:

private string baseUrl = "https://example.com/";

void Start()
{
        try
        {
            StartCoroutine(InitialisePusher());
        }

        catch (Exception e)
        {
            Debug.Log(e.Message);
        }
}

Then we initialize the pusher & sign in the user, then subscribe it to a channel and bind for an event in the code:

private IEnumerator InitialisePusher()
{
        if (_pusher == null && (APP_KEY != "APP_KEY") && (APP_CLUSTER != "APP_CLUSTER"))

        {
             _pusher = new Pusher(APP_KEY, new PusherOptions()

            {
                Cluster = APP_CLUSTER,

                Encrypted = true,
                Authorizer = new HttpAuthorizer(baseUrl + "api/auth/authorizer")
                {
                    AuthenticationHeader = AuthenticationHeaderValue.Parse("Bearer " + PlayerPrefs.GetString("token"))
                },
            });
            _pusher.Error += OnPusherOnError;
            _pusher.ConnectionStateChanged += PusherOnConnectionStateChanged;
            _pusher.Connected += PusherOnConnected;
            yield return new WaitUntil(() =>

            {
                _channel = _pusher.SubscribeAsync("private-" + PlayerPrefs.GetString("Channel")).Result;

                if (_channel != null)
                {
                    return true;
                }

                return false;
            });
            _pusher.Subscribed += OnChannelOnSubscribed;
            _pusher.ConnectAsync();
        }

        else
        {
             Debug.Log("Error in credentials");
        }
}

private void PusherOnConnected(object sender)
{
        _channel.Bind("connected", (PusherEvent data) =>

        {
            StartCoroutine(GetList()); //⬅️Everything is ok but a bug happens here when we want to run the StartCoroutine() method in here. I found out it`s because it will run on a different thread than the main thread so I cannot use the StartCoroutine() or even any other simple method in here!
        });
}

But I got this error:
Error:
Error invoking the action for the emitted event connected:
IsObjectMonoBehaviour can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don’t use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

Because we want to wait for the “GetList” method which that`s an IEnumerator; to be completed, we cannot run it on the Start or Awake methods.

Here’s how to post code on the forums: Unity Engine - Unity Discussions

1 Like

You could make me happy to take a look at my main challenge!

If I had any idea I would’ve helped. :slight_smile:

Yes if you had so.

Is GetList() awaitable? If so, await it.

Otherwise make a call to a method on the main thread and start the coroutine there.

UnityMainThreadDispatcher is one way to do so.

But I would scrutinize the whole setup. Particularly the WaitUntil part makes me think (also: cringe) there must be a better way than to try to subscribe every frame (!) to an async event. Is the Pusher API generally awaitable to begin with, for instance? Then you wouldn’t need that first coroutine.

1 Like

I’m here moderating the forum. I was here to tell you about code-tags and removing your cross-post on General Discussion.

1 Like

This is a very short summary of larger code & the InitialisePusher() should run inside a Coroutine, so do not waste your time on code optimizations, the challenge is in threads and other things are working properly.

Thanks, now let us focus on the main challenge please. You posted more than me and problem solvers on this thread.

That’s fine but please edit your post to use code-tags.

Thanks.

Store the Unity SynchronizationContext in a field during Awake or Start
_contextField = System.Threading.SynchronizationContext.Current

Then use it to invoke your code on the “main” thread
_contextField.Post(x => { StartCoroutine(GetList()); }, null);

1 Like

You mean this:

using System.Threading;
private bool lists_checked = true;
private SynchronizationContext syncer;
void Awake()
{
    syncer = SynchronizationContext.Current;
}

_channel.Bind("connected", (PusherEvent data) =>
{
    try
    {
        Debug.Log("Called");
        lists_checked = false;
        syncer.Post(x => { StartCoroutine(GetList()); }, null);
    }
    catch (Exception e)
    {
        Debug.Log(e.Message);
    }
});

IEnumerator GetList()
{
    if (!lists_checked)
    {
        lists_checked = true;
        Debug.Log("Calling...");[/INDENT]
    }
}

But now printing a bunch of “Calling…” in the console!
How should I stop it after one time of running?! inside of the “GetList” I`m sending a web request to my server to update the list of current players are joined to this room.
9810186--1408944--Web 1920 – 1.png

As long as you obdurately refuse to format your code, most people such as myself are not even going to look at it.

If you post a code snippet, ALWAYS USE CODE TAGS:

How to use code tags: https://discussions.unity.com/t/481379

  • Do not TALK about code without posting it.
  • Do NOT post unformatted code.
  • Do NOT retype code. Use copy/paste properly using code tags.
  • Do NOT post screenshots of code.
  • Do NOT post photographs of code.
  • Do NOT attach entire scripts to your post.
  • ONLY post the relevant code, and then refer to it in your discussion.

We see this every day, people like you who think the forum rules don’t apply to them. Well sure, they don’t. But we also don’t have to look at your code.

Good luck!!

Ok grandma! I fixed it, now check it up and stop hating me.

Good lord your imagination is running completely wild here. I don’t hate anyone. I looked over every single word of the post I made above and I have no idea where you get “hate” from. Maybe it’s a language barrier thing??

Perhaps by setting and checking a boolean??

Either way… it sounds like it is time to start debugging!

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log() to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Friends pusher has some serious problems with unity, I couldn’t find any solution for this because of a lack of docs & experience using Pusher!
use ABly instead of pusher, it`s more update and useful.