Mattermost-server: [Help Wanted] [PLT-7983] Any activity on the computer should maintain online status for Desktop App

Created on 25 Oct 2017  路  32Comments  路  Source: mattermost/mattermost-server

If you're interested please comment here and come join our "Contributors" community channel on our daily build server, where you can discuss questions with community members and the Mattermost core team. For technical advice or questions, please join our "Developers" community channel.

New contributors please see our Developer's Guide, specifically for machine setup and for developer workflow.


Notes: Jira ticket

This ticket is to improve the detection for the online status on the desktop app.

Desktop Repo: https://github.com/mattermost/desktop


Current Behavior:
5 minutes of inactivity in Mattermost will cause the users status to change to "Away", even if the person is at their computer using other applications.

Expected Behavior:
Any activity on the computer will maintain the "Online" status. 5 minutes of no activity on the computer changes the user status to "Away".

Library to help detect when a user has been idle on their computer: https://github.com/paulcbetts/node-system-idle-time

Medium TecReactJS

Most helpful comment

Now that there is Electron 4.0 in master, I will take a look again

All 32 comments

I will work on this.

Awesome, thanks @h2oloopan!

Hi,

I have done some research but I think I may need some help clarifying whether my understanding is correct.

  1. When we are communicating with the server from the webapp, we are doing RESTful API calls but when going backward (from server to the webapp) we are doing websocket messaging.
  2. We don't have any specific action that updates the user's status on the server. We only call the method to mark user online in some of the api endpoints manually.

If the above is true, to implement this feature, I think I may need to add a new API endpoint in the server (if so where shall I put it to?) and is dedicated to call the method to set user status to online, also I may need to create an action in the redux repo and bind it to an api call (by the way, what's the difference between client.js and client4.js?)

Therefore, I can add the detection logic to the desktop app and use socket to update user status in the webapp. Then in the action handling logic I can check whether the last update was done 2/3 minutes ago and only call the server endpoint if so (do I store the last updated time in the redux state?)

Thoughts? @jwilander

Thanks!

Hi @h2oloopan,

Number 1 is correct, the server determines online status based on RESTful API calls the web app makes and the server alerts all of a user's clients to status changes using the WebSocket.

For number 2 we actually do have an endpoint dedicated to updating the user's status but it acts as the user "manually" setting their status (meaning it stays the same until they manually change it again or set it back to online). For the desktop app we don't want it to have that behavior since it's not actually the user changing the status, the app is doing it automatically.

So for that we have two options:

  1. Update the PUT /users/{user_id}/status to take in another body parameter manual that defaults to true (to keep backwards compat) but when set to false will set the status not manually
  2. In the desktop app, check if the status is manually to away, offline or dnd and only set the status to online if they're not manually set

I'm leaning towards 1 because it's less complex and less prone to races. What do you think?

Sounds good, I will start working on it now (option 1).

Hi @h2oloopan, hope all is going well, any questions or concerns on this ticket we can help with?

Any updates on this one? This would really be a useful feature! I have developed something in java but this needs to be in the mattermost client!

The solution uses - the jna library - and the windows provided functions from the user32.dll

public static int getIdleTimeMillisWin32() { User32.LASTINPUTINFO lastInputInfo = new User32.LASTINPUTINFO(); User32.INSTANCE.GetLastInputInfo(lastInputInfo); return Kernel32.INSTANCE.GetTickCount() - lastInputInfo.dwTime; }

userupdate:

public boolean updateUserStatus(String status) {
        try {
            HttpResponse<JsonNode> jsonResponse = Unirest.put(mattermostUrl + "/api/v4/users/{user_id}/status")
                    .header("Authorization", "Bearer " + tocken).routeParam("user_id", this.userId)
                    .body("{\"status\": \"" + status + "\"}").asJson();
            if (jsonResponse.getStatus() != 200) {
                logger.log(Level.WARNING, "status update error: "+jsonResponse.getStatus()+": "+jsonResponse.getStatusText());
                return false;
            } else {
                logger.info("update status: "+status );
            } 
            return true;
        } catch (Exception e) {
            logger.log(Level.WARNING, "status update exeption: {0}", e.getMessage());
            return false;
        }
}

userstatus:

public boolean checkUser(String username) {
        try {
            HttpResponse<JsonNode> jsonResponse = Unirest.post(mattermostUrl + "/api/v4/users/usernames")
                    .header("Authorization", "Bearer " + tocken).body("[\"" + username + "\"]").asJson();

            if (jsonResponse.getStatus() != 200) {
                logger.info("Failed verify user in mattermost: " + jsonResponse.getStatusText());
                return false;
            }
            if (jsonResponse.getBody().getArray() != null
                    && jsonResponse.getBody().getArray().getJSONObject(0) != null) {
                userEmail = jsonResponse.getBody().getArray().getJSONObject(0).getString("email");
                userId = jsonResponse.getBody().getArray().getJSONObject(0).getString("id");
                logger.info("userId: " + userId);
                logger.fine("user-data: "+jsonResponse.getBody().getArray().getJSONObject(0).toString());
            }
            return true;
        } catch (Exception e) {
            logger.log(Level.WARNING, "check user exeption: {0}", e.getMessage());
            return false;
        }
    }

Any update on this feature? we are looking for this feature! It would be really helpful if you can implement this in the next release

Thanks @mbuchner and @saikaushik-itsmyworld, this ticket is still up for grabs so if either of you are interested in contributing it we'd be happy to provide some guidance.

We need this feature as well for an enterprise deployment. We've plans to migrate from jabber to mattermost, but a meaningful online status is one of the minimum requirement.

We need this feature as well. My developers are not using the app because they think that everyone is offline or away when in-fact they aren't. @esethna if you could point me in the right direction I can look at making the changes. I am new to the code base so any help would be appreciated.

Sweet! Thanks @rbiggers.

Adding @hmhealey as he dove into this a bit on our end and might be able to provide some guidance. Feel free to also join our pre-release server where most contributors and developers communicate. We can set up a channel for all dicussion related to this feature

Adding another request for this feature. Is anybody working on this or has worked on this previously? I may consider taking a look at this at some point as it is very important to our team, but I have no experience with Mattermost development or Node for that matter.

Same for me - this feature is important to our team.
We've been using Jabber previously. We could see that someone isn't on his/her working place if the user was away - but with Mattermost, we can't rely on this information anymore.

@MathieuTougas wondering if your work at https://github.com/MathieuTougas/electron-node-desktop-idle would be helpful for this issue?

@rbiggers just circling back on this to check if you were still working on this issue? If so, feel free to reach out if you have any questions :)

Hi, @torlenor and me would love to have this feature and we would be willing to take a look at it. We have a few questions first:
1) first things first, is someone now actively working on it? (@rbiggers, @h2oloopan)
2) It would only be implemented in mattermost-desktop. This would mean the behavior is different between web, desktop and mobile, is this ok with your guidelines?
3) On the server we would extend the API call with something like a "manual" field.
If there should be different logic between manual=true (default) and manual=false, please specify.
What we can think of is, that in case of a desktop client with "local idle detection" the automatic idle detection has to be disabled.
Maybe this could be detected because the desktop client would make an api call setting the status online with manual=false in the beginning, or
maybe something like setClientFeature(LocalIdleDetection=True)
4) The harder part (maybe) is the implementation in the Desktop app. We would try to find a suitable way to determine if the user is idle or not
(maybe with https://github.com/MathieuTougas/electron-node-desktop-idle) and implement the changes to mattermost-desktop
and PUT /users/{user_id}/status accordingly.

@scuq

  1. As far as I'm aware, they're no longer working on it. At the very least, I don't think we've heard from them in some time
  2. That's correct. The web and mobile apps can't detect activity outside of the browser due to sandboxing, and there's no way around that
  3. @jwilander Can you answer this?
  4. I agree that that's probably the hardest part. I spent some time a few months ago trying to add this feature, and I got stuck coming up with a cross-platform way to actually detect that. I don't think I tried that library, but that definitely sounds like it should work here.

3 - I'm not sure the automatic idle detection needs to be disabled necessarily. You could just have the API call to set the status reset the timer for the idle detection, as long as the API call occurs often enough. If that doesn't work then you should be able to detect the desktop app on the server and disable the automatic idle detection but I think that might get complicated if you the user has multiple devices connected

I agree that simply sending an "active signal" periodically from the desktop app would make the most sense.

So basically we would not have to change the API at all for the moment and can use the existing call as it is.

@scuq and me played a bit with the idle detection and it seems without a native module it is not possible, yet, but the module provided in the git repo above would work in general (at least in our small test project with a little bit of fiddling).

Another option seems to be available with Electron 3.0: It got an API call (https://electronjs.org/docs/api/power-monitor#powermonitorquerysystemidlestateidlethreshold-callback), but so far we couldn't get this to work (and of course it would mean we would have to wait until desktop is updated to Electron 3.0).

We will keep evaluating the options and see if we can implement something in mattermost-desktop to test.

@torlenor Using something built into Electron like that would actually be ideal since we wouldn't need to bother with a native module at all. We're going to upgrade to Electron 3 at some point, but if that makes this feature much easier to implement, we could prioritize upgrading Electron higher

Did something similar but with angular6 and electron3x - powermonitor seems to work pretty good:

import { ipcRenderer, webFrame, remote } from 'electron';
...

@Injectable()
export class ElectronService implements OnInit, OnDestroy {
...
  private _idleTime = new Subject<number>();
  idleTime$ = this._idleTime.asObservable();
...
constructor(settingsService: SettingsService) {
      const electron = require('electron');
      this.remote = electron.remote;
      this.menu = electron.Menu || this.remote.Menu;
      this.powerMonitor = electron.powerMonitor || remote.powerMonitor;
      ...
      this.createIdleTimeObervable(2);
  }
...
  createIdleTimeObervable(checkIntervalInSec: number) {
    timer(0, checkIntervalInSec * 1000).subscribe(x => {
      this.powerMonitor.querySystemIdleTime((idleTime) => {
        this._idleTime.next(idleTime);
      })
    })
  }

and then call the mattermost update status

    getUser(settings: Settings) {
        return this.http.post<MattermostUser[]>(settings.mattermostUrl + '/api/v4/users/usernames', '["'+settings.username+'"]', {
            headers: new HttpHeaders({ 
                'Access-Control-Allow-Origin': '*',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer '+settings.mattermostToken
            })}
        ).pipe(
            catchError(this.handleError)
          );
    }

    updateStatus(settings: Settings, status: string) {
        return this.http.put<MattermostUserStatusUpdate>(settings.mattermostUrl + '/api/v4/users/'+settings.userId+'/status', 
        '{"status": "' + status + '"}', {
            headers: new HttpHeaders({ 
                'Access-Control-Allow-Origin': '*',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer '+settings.mattermostToken
            })
        }).pipe(
            catchError(this.handleError)
          );
    }

Unfortunately I am not into react but probably this helps somebody ...

Hey, @amyblais.
Do you know something about this problem? It's a real problem when lots of people receiving huge counts of emails when they were online. Just because status was wrong.

Now that there is Electron 4.0 in master, I will take a look again

@torlenor Hows this going? Anything we can help with? Let us know if you'd like to continue on it or if we should open this up to the community again.

Readding the up for grabs label for now, @torlenor let us know if you're still working on this issue :)

Hello,

Any update on this matter as this is an issue for us. All my contact are marked away when they are at their computer. It's been an issue that has been escalated in our company.

Thank you

+1 for this. Even a possibility to disable the auto-status as it is now would be better. We use Mattermost in our company but 9 times out of 10 people are marked as away even while sitting behind their PC.

Closing as the core team works on this. See https://github.com/mattermost/desktop/pull/945 for the progress.

Was this page helpful?
0 / 5 - 0 ratings