~swisschili/chat

6d8344f4df381fc7efb0140ce87d98931162ed14 — swissChili a month ago 7597d16
Store user statuses server-side, automatically set as offline
M client/src/main/java/sh/swisschili/chat/client/MainWindow.java => client/src/main/java/sh/swisschili/chat/client/MainWindow.java +31 -25
@@ 107,31 107,7 @@ public class MainWindow {
        statusBox.setModel(statusModel);

        statusBox.addActionListener(e -> {
            Presence presence = null;
            String selected = (String) statusBox.getSelectedItem();
            if (selected == null)
                return;

            switch (selected) {
                case "Online":
                    presence = Presence.ONLINE;
                    break;
                case "Away":
                    presence = Presence.AWAY;
                    break;
                case "Do not disturb":
                    presence = Presence.DND;
            }

            UserStatus.Builder builder = UserStatus.newBuilder();
            if (presence == null) {
                builder.setCustom(CustomPresence.newBuilder()
                        .setName(selected).build());
            } else {
                builder.setPresence(presence);
            }

            updateStatus(builder.build());
            updateStatusFromUi();
        });

        groups.setComponentPopupMenu(new GroupsPopUp(e -> new AddGroupDialog(this::groupAdded)


@@ 189,6 165,34 @@ public class MainWindow {
        });
    }

    private void updateStatusFromUi() {
        Presence presence = null;
        String selected = (String) statusBox.getSelectedItem();
        if (selected == null)
            return;

        switch (selected) {
            case "Online":
                presence = Presence.ONLINE;
                break;
            case "Away":
                presence = Presence.AWAY;
                break;
            case "Do not disturb":
                presence = Presence.DND;
        }

        UserStatus.Builder builder = UserStatus.newBuilder();
        if (presence == null) {
            builder.setCustom(CustomPresence.newBuilder()
                    .setName(selected).build());
        } else {
            builder.setPresence(presence);
        }

        updateStatus(builder.build());
    }

    private void updateStatus(UserStatus status) {
        for (int i = 0; i < groupModel.size(); i++) {
            groupModel.get(i).setStatus(status);


@@ 208,6 212,8 @@ public class MainWindow {
                });

        groupModel.addElement(serverGroup);

        updateStatusFromUi();
    }

    private void groupSelected() {

M client/src/main/java/sh/swisschili/chat/client/MessageCell.form => client/src/main/java/sh/swisschili/chat/client/MessageCell.form +4 -1
@@ 45,7 45,10 @@
      </grid>
      <component id="131b0" class="javax.swing.JTextArea" binding="body">
        <constraints border-constraint="Center"/>
        <properties/>
        <properties>
          <lineWrap value="true"/>
          <wrapStyleWord value="true"/>
        </properties>
      </component>
    </children>
  </grid>

M client/src/main/java/sh/swisschili/chat/client/ServerGroup.java => client/src/main/java/sh/swisschili/chat/client/ServerGroup.java +2 -1
@@ 115,7 115,8 @@ public class ServerGroup {
                                });

                        pool.chatStubFor(server)
                                .getGroupUserStatuses(GroupUserStatusRequest.newBuilder().setGroup(group).build(),
                                .getGroupUserStatuses(GroupUserStatusRequest.newBuilder().setGroup(group)
                                                .setFor(user).build(),
                                        new StreamObserver<UserStatus>() {
                                            @Override
                                            public void onNext(UserStatus value) {

M server/src/main/java/sh/swisschili/chat/server/ChatService.java => server/src/main/java/sh/swisschili/chat/server/ChatService.java +16 -3
@@ 110,7 110,7 @@ public class ChatService extends ChatGrpc.ChatImplBase {

            pool.authStubFor(user.getHost())
                    .getUserPublicKey(ChatProtos.PublicKeyRequest.newBuilder()
                            .setUser(user).build(),
                                    .setUser(user).build(),
                            listener);
        }



@@ 152,7 152,8 @@ public class ChatService extends ChatGrpc.ChatImplBase {
                }
            };

            channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {});
            channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {
            });
        } catch (IOException e) {
            LOGGER.error("Could not create RabbitMQ channel in getMessages");
            responseObserver.onError(e);


@@ 272,6 273,8 @@ public class ChatService extends ChatGrpc.ChatImplBase {
            Channel channel = getChannel(exchangeName);
            channel.basicPublish(exchangeName, "", null, request.getStatus().toByteArray());

            db.setUserStatus(request.getStatus(), request.getGroup());

            LOGGER.info(String.format("Set user status %s", request.toString()));

            responseObserver.onNext(ChatProtos.SetUserStatusResponse.newBuilder().build());


@@ 300,9 303,12 @@ public class ChatService extends ChatGrpc.ChatImplBase {
                } catch (Exception e) {
                    LOGGER.info("Client disconnected");
                    channel.basicCancel(consumerTag);

                    setUserOffline(request.getFor(), request.getGroup());
                }
            };
            channel.basicConsume(queueName, true, callback, consumerTag -> {});
            channel.basicConsume(queueName, true, callback, consumerTag -> {
            });
        } catch (IOException e) {
            responseObserver.onError(e);
        }


@@ 319,4 325,11 @@ public class ChatService extends ChatGrpc.ChatImplBase {
    public void setAllowUnsignedMessages(boolean allowUnsignedMessages) {
        this.allowUnsignedMessages = allowUnsignedMessages;
    }

    private void setUserOffline(ChatProtos.User user, ChatProtos.Group group) {
        db.setUserStatus(ChatProtos.UserStatus.newBuilder().setUser(user)
                        .setPresence(ChatProtos.Presence.OFFLINE)
                        .build(),
                group);
    }
}

M util/src/main/proto/chat.proto => util/src/main/proto/chat.proto +2 -0
@@ 90,6 90,7 @@ enum Presence {
  ONLINE = 0;
  AWAY = 1;
  DND = 2; // do not disturb
  OFFLINE = 3;
}

message CustomPresence {


@@ 107,6 108,7 @@ message UserStatus {

message GroupUserStatusRequest {
  Group group = 1;
  User for = 2;
}

message SetUserStatusRequest {