Search Results for

    Show / Hide Table of Contents

    Unregister and Reregister

    In this tutorial, you'll learn how to:

    • Reregister clients who are disconnected.
    • Unregister clients who leave a channel so that resources are cleaned up.

    Prerequisites

    This tutorial requires the Hello World! app you have created earlier.

    Reregister a Client

    If a client is unable to register because of external factors, like a network connection failure, we determine whether the client has decided to leave and must be unregistered. If not, we reregister the client according to the reregister backoff period.

    The reregister backoff is an incremental interval time between reregistrations. For example, if the reregister backoff time is 10 seconds, then the first time the application tries to reregister is after 10 seconds. The second reregister attempt happens after 20 seconds. The third reregister attempt happens after 30 seconds and so on until it reaches a set maximum backoff time. If you set the maximum backoff to 1 minute, then once 1 minute has elapsed, the backoff interval doesn't increase.

    To reregister a client:

    1. Set the reregister backoff and maximum backoff period in milliseconds.
    2. Set unregistering to false.
    3. Create an event on the client to handle the state changes. If the client isn't unregistering, register the client with a token into the channel again.

    Update the joinAsync function in the HelloWorldLogic class to the following:

    • CSharp
    • Android
    • iOS
    • TypeScript
    // Registering and reregistering a client 
    private int _ReregisterBackoff = 200;
    private const int _MaxRegisterBackoff = 60000;
    private bool _Unregistering = false;
    
    public async Task JoinAsync()
    {
        Client = new Client(GatewayURL, ApplicationId);
        ChannelClaim[] channelClaims = new[] { new ChannelClaim(ChannelId) };
        string token = Token.GenerateClientRegisterToken(
            ApplicationId,
            Client.UserId,
            Client.DeviceId,
            Client.Id,
            null,
            channelClaims,
            SharedSecret
        );
    
        _Unregistering = false;
        Client.OnStateChange += async (client) =>
        {
            if (client.State == ClientState.Unregistered && !_Unregistering)
            {
                Log.Debug($"Registering with backoff = {_ReregisterBackoff}.");                   
                // Incrementally increase register backoff to prevent runaway process
                System.Threading.Thread.Sleep(_ReregisterBackoff);
                if (_ReregisterBackoff <= _MaxRegisterBackoff)
                {
                    _ReregisterBackoff += _ReregisterBackoff;
                }
                DisplayMessage("Client unregistered unexpectedly, trying to re-register.");
                var reregisterChannels = await Client.Register(token).AsTask();
                _ReregisterBackoff = 200;    // Reset registering backoff
                OnClientRegistered(reregisterChannels);
            }
        };
    
        var channels = await Client.Register(token).AsTask();
        DisplayMessage("Client is registered!");
        OnClientRegistered(channels);
    }
    
    int reRegisterBackoff = 200;
    int maxRegisterBackoff = 60000;
    boolean unregistering = false;
    
    // Make a registration request.
    public Future<Channel[]> joinAsync() {
        // Create a client.
        client = new Client(gatewayUrl, applicationId);
    
        // Create a token (do this on the server to avoid exposing your shared secret).
        String token = Token.generateClientRegisterToken(applicationId, client.getUserId(), client.getDeviceId(), client.getId(), null, new ChannelClaim[]{new ChannelClaim(channelId)}, sharedSecret);
    
        // Allow re-register.
        unregistering = false;
    
        client.addOnStateChange(client -> {
            if (client.getState() == ClientState.Unregistered) {
                Log.debug("Client has been unregistered.");
    
                if (!unregistering) {
                    Log.debug(String.format(Locale.US, "Registering with backoff = %d.", reRegisterBackoff));
    
                    // Incrementally increase register backoff to prevent runaway process.
                    ManagedThread.sleep(reRegisterBackoff);
                    if (reRegisterBackoff < maxRegisterBackoff) {
                        reRegisterBackoff += reRegisterBackoff;
                    }
    
                    client.register(token).then(channels -> {
                        // Reset re-register backoff after successful registration.
                        reRegisterBackoff = 200;
                        onClientRegistered(channels);
                    }, ex -> Log.error("ERROR: Client unable to register with the gateway.", ex));
                }
            }
        });
    
        // Register client with token.
        return client.register(token).then(this::onClientRegistered, ex -> Log.error("ERROR: Client unable to register with the gateway.", ex));
    }
    
    var _unRegistering: Bool = false
    var _reRegisteringBackoff: Int32 = 200
    var _maxReRegisteringBackoff: Int32 = 60000
    
    // Make a registration request
    func joinAsync() -> FMLiveSwitchFuture?  {
        // Instantiate the client
        self._client = FMLiveSwitchClient.init(
            gatewayUrl: _gatewayUrl,
            applicationId: _applicationId)
               
        let claim: FMLiveSwitchChannelClaim = FMLiveSwitchChannelClaim.init()
        claim.setId(_channelId)
        let claims: NSMutableArray = []
        claims.add(claim)
        
        let token: String = generateToken(claims: claims)
    
        // We attempt to reregister..
        _client?.addOnStateChange({[weak self] (obj: Any?) in
            let c = obj as! FMLiveSwitchClient
            
            if (c.state() == FMLiveSwitchClientState.unregistered) {
                FMLiveSwitchLog.error(withMessage: "Client unexpectedly unregistered.")
                
                // Client has failed for some reason.
                if (!self!._unRegistering) {
                    FMLiveSwitchManagedThread.dispatch(with: FMLiveSwitchAction0.init(block: {
                        FMLiveSwitchManagedThread.sleep(withMillisecondsTimeout: self!._reRegisteringBackoff)
                        
                        FMLiveSwitchLog.debug(withMessage: "Reregistering with backoff of \(String(describing: self!._reRegisteringBackoff)).")
                        
                        // Increment reRegistering backoff to prevent runaway process
                        if (self!._reRegisteringBackoff < self!._maxReRegisteringBackoff) {
                            self!._reRegisteringBackoff += self!._reRegisteringBackoff
                        }
                        
                        c.register(withToken: token)?.then(resolveActionBlock: { [weak self] (obj: Any!) -> Void in
                            self?._reRegisteringBackoff = 200 // Reset reregistering back off
                            self!.onClientRegistered(obj: obj)
                        })?.fail(rejectActionBlock: { (e: NSException?) in
                            FMLiveSwitchLog.error(withMessage: "Client failed to reregister.", ex: e)
                        })
                    }))
                }
            }
        })
        
        return self._client?.register(withToken: token)?.then(resolveActionBlock: { [weak self] (obj: Any!) -> Void in
            self!.onClientRegistered(obj: obj)
        })?.fail(rejectActionBlock: { (e: NSException?) in
            FMLiveSwitchLog.error(withMessage: "Client failed to register.", ex: e)
        })
    }
    
    
    private reRegisterBackoff = 200;
    private readonly maxRegisterBackoff = 60000;
    private unregistering = false;
    
    public joinAsync(): fm.liveswitch.Future<Object> {
        const promise = new fm.liveswitch.Promise<Object>();
    
        // Create a client.
        this.client = new fm.liveswitch.Client(this.gatewayUrl, this.applicationId);
    
        // Generate a token (do this on the server to avoid exposing your shared secret).
        const token: string = fm.liveswitch.Token.generateClientRegisterToken(this.applicationId, this.client.getUserId(), this.client.getDeviceId(), this.client.getId(), null, [new fm.liveswitch.ChannelClaim(this.channelId)], this.sharedSecret);
    
        // Allow re-register.
        this.unregistering = false;
    
        this.client.addOnStateChange(() => {
            // Write registration state to log.
            fm.liveswitch.Log.debug(`Client is ${new fm.liveswitch.ClientStateWrapper(this.client.getState())}.`);
    
            if (this.client.getState() === fm.liveswitch.ClientState.Unregistered && !this.unregistering) {
                fm.liveswitch.Log.debug(`Registering with backoff = ${this.reRegisterBackoff}.`);
                this.displayMessage("Client unregistered unexpectedly, trying to re-register.");
    
                // Re-register after a backoff.
                setTimeout(() => {
                    // Incrementally increase register backoff to prevent runaway process.
                    if (this.reRegisterBackoff <= this.maxRegisterBackoff) {
                        this.reRegisterBackoff += this.reRegisterBackoff;
                    }
    
                    // Register client with token.
                    this.client.register(token)
                        .then(channels => {
                            // Reset re-register backoff after successful registration.
                            this.reRegisterBackoff = 200;
                            this.onClientRegistered(channels);
                            promise.resolve(null);
                        })
                        .fail(ex => {
                            fm.liveswitch.Log.error("Failed to register with Gateway.");
                            promise.reject(ex)
                        });
    
                }, this.reRegisterBackoff);
            }
        });
    
        // Register client with token.
        this.client.register(token)
            .then(channels => {
                this.onClientRegistered(channels);
                promise.resolve(null);
            })
            .fail(ex => {
                fm.liveswitch.Log.error("Failed to register with Gateway.");
                promise.reject(ex)
            });
    
        return promise;
    }
    

    Unregister a Client

    Unregistering clients when they leave is optional because the LiveSwitch Gateway automatically unregisters clients that are inactive for a period of time. However, unregistering clients cleans up resources immediately. To learn more about unregistering clients, refer to the Unregister section.

    To unregister a client, invoke the unregister method of the client instance. In this code example, we set unregistering to true. This is only used for reregistering a client.

    Paste the following code into the HelloWorldLogic class:

    • CSharp
    • Android
    • iOS
    • TypeScript
    public void LeaveAsync()
    {
        if (Client != null)
        {
            _Unregistering = true;
            Client.Unregister();
            Log.Info("Client has successfully unregistered.");
            DisplayMessage($"Client {Client.Id} has successfully unregistered from channel {Channel.Id}.");
        }
    }
    
    public Future<Object> leaveAsync() {
        if (this.client != null) {
            // Disable re-register.
            unregistering = true;
            return this.client.unregister().fail(ex -> {
                Log.error("ERROR: Unable to unregister client.", ex);
            });
        }
        return null;
    }
    
    
    func leaveAsync() -> FMLiveSwitchFuture {
        if (self._client != nil) {
            self._unRegistering = true
            return (self._client?.unregister().then(resolveActionBlock: {(obj: Any!)-> Void in
                FMLiveSwitchLog.info(withMessage: "Client successfully unregistered!")
            }).fail(rejectActionBlock: { (e: NSException?) in
                FMLiveSwitchLog.error(withMessage: "Client failed to unregister.", ex: e)
            }))!
        } else {
            let promise = FMLiveSwitchPromise()
            promise?.resolve(withResult: nil)
            return promise!
        }
    }
    
    public leaveAsync(): fm.liveswitch.Future<Object> {
        // Disable re-register.
        this.unregistering = true;
        return this.client.unregister()
            .then(() => this.displayMessage(`Client ${this.client.getId()} has successfully unregistered from channel ${this.channel.getId()}.`))
            .fail(() => fm.liveswitch.Log.error("Unregistration failed."));
    }
    

    Uncomment UI Components

    Go to the files that contain UI components and uncomment code to enable unregistering UI.

    • CSharp
    • Android
    • iOS
    • TypeScript

    In MainWindow.xaml.cs, uncomment the code between the <Unregistered> and </Unregistered> tags.

    In app/src/main/java/com/example/helloworld/StartingFragment.java, uncomment the code between the <Unregistered> and </Unregistered> tags.

    Note

    There are multiple instances of these tags. Uncomment all the code between those instances.

    In ViewModel.swift, uncomment the code between the <Unregister> and </Unregister> tags.

    Note

    There are multiple instances of these tags. Uncomment all the code between those instances.

    In index.ts, uncomment the code between the <Unregister> and </Unregister> tags.

    Run Your App

    1. Run your app in your project IDE.
    2. Click Join.
    3. Disable your device's Internet connection. In your project console, there is an error message describing a failure to connect because of a network issue.
      Note

      For TypeScript, the log is in the browser console.

    4. Enable your device's Internet connection. In your project console, there is a message that the client has successfully joined.
    5. Go to your LiveSwitch Console's homepage, and select the Hello World Application. There is only one client and one channel connected to your Hello World Application.
    6. Go to your LiveSwitch Cloud's Dashboard page, and select the Hello World Application. There is only one client and one channel connected to your Hello World Application.
    7. Click Leave.
    8. Go to your LiveSwitch Console's homepage, and select the Hello World Application. There are no clients or channels connected to your Hello World Application.
    9. Go to your LiveSwitch Cloud's Dashboard page, and select the Hello World Application. There are no clients or channels connected to your Hello World Application.

    Congratulations, you've built your app to handle reregistering and unregistering.

    In This Article
    Back to top Copyright © LiveSwitch Inc. All Rights Reserved.Documentation for LiveSwitch Version 1.6.2