blob: 6d5d02090795cd4d66af82719696599f36daf374 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License") + you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openmeetings.db.entity.basic;
import static java.util.UUID.randomUUID;
import static org.apache.openmeetings.util.OmFileHelper.SIP_USER_ID;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.apache.openmeetings.db.dao.user.UserDao;
import org.apache.openmeetings.db.entity.IDataProviderEntity;
import org.apache.openmeetings.db.entity.room.Room;
import org.apache.openmeetings.db.entity.room.Room.Right;
import org.apache.openmeetings.db.entity.user.User;
import org.apache.wicket.util.string.Strings;
import com.github.openjson.JSONArray;
import com.github.openjson.JSONObject;
/**
* @author solomax
*
*/
public class Client implements IDataProviderEntity, IWsClient {
private static final long serialVersionUID = 1L;
public enum Activity {
AUDIO //sends Audio to the room
, VIDEO //sends Video to the room
, AUDIO_VIDEO //sends Audio+Video to the room
, SCREEN //screen is shared
, RECORD //record in non-interview room
}
public enum StreamType {
WEBCAM //sends Audio/Video to the room
, SCREEN //send screen sharing
}
private final String sessionId;
private final int pageId;
private User user;
private Room room;
private final String uid;
private final String sid;
private String remoteAddress;
private final Set<Right> rights = ConcurrentHashMap.newKeySet();
private final Set<Activity> activities = ConcurrentHashMap.newKeySet();
private final Map<String, StreamDesc> streams = new ConcurrentHashMap<>();
private final Date connectedSince;
private int cam = -1;
private int mic = -1;
private int width = 0;
private int height = 0;
private String serverId = null;
private final String pictureUri;
public Client(String sessionId, int pageId, User u, String pictureUri) {
this.sessionId = sessionId;
this.pageId = pageId;
this.user = u;
this.connectedSince = new Date();
this.pictureUri = pictureUri;
uid = randomUUID().toString();
sid = randomUUID().toString();
}
@Override
public String getSessionId() {
return sessionId;
}
@Override
public int getPageId() {
return pageId;
}
public User getUser() {
return user;
}
public Client updateUser(UserDao dao) {
user = dao.get(user.getId());
return this;
}
public Long getUserId() {
return user == null ? null : user.getId();
}
public boolean sameUserId(Long userId) {
return getUserId() != null && getUserId().equals(userId);
}
public String getPictureUri() {
return pictureUri;
}
@Override
public String getUid() {
return uid;
}
public String getSid() {
return sid;
}
public boolean isSip() {
return SIP_USER_ID.equals(getUserId());
}
public void clear() {
activities.clear();
rights.clear();
streams.clear();
}
public boolean hasRight(Right right) {
if (Right.SUPER_MODERATOR == right) {
return rights.contains(right);
}
return rights.contains(Right.SUPER_MODERATOR) || rights.contains(Right.MODERATOR) || rights.contains(right);
}
public Client allow(Right... inRights) {
allow(List.of(inRights));
return this;
}
public void allow(Iterable<Right> inRights) {
for (Right right : inRights) {
if (!hasRight(right)) {
rights.add(right);
}
}
}
public void deny(Right... inRights) {
for (Right right : inRights) {
rights.remove(right);
}
}
public void clearActivities() {
activities.clear();
}
public boolean hasAnyActivity(Activity... aa) {
boolean res = false;
if (aa != null) {
for (Activity a : aa) {
res |= activities.contains(a);
}
}
return res;
}
public boolean hasActivity(Activity a) {
return activities.contains(a);
}
public Client toggle(Activity a) {
if (hasActivity(a)) {
remove(a);
} else {
set(a);
}
return this;
}
public Client set(Activity a) {
activities.add(a);
switch (a) {
case VIDEO, AUDIO:
if (hasActivity(Activity.AUDIO) && hasActivity(Activity.VIDEO)) {
activities.add(Activity.AUDIO_VIDEO);
}
break;
case AUDIO_VIDEO:
activities.add(Activity.AUDIO);
activities.add(Activity.VIDEO);
break;
default:
}
return this;
}
public Client remove(Activity a) {
activities.remove(a);
switch (a) {
case VIDEO, AUDIO:
activities.remove(Activity.AUDIO_VIDEO);
break;
case AUDIO_VIDEO:
activities.remove(Activity.AUDIO);
activities.remove(Activity.VIDEO);
break;
default:
}
return this;
}
public StreamDesc addStream(StreamType stype, Activity...inActivities) {
StreamDesc sd = new StreamDesc(stype, inActivities);
streams.put(sd.getUid(), sd);
return sd;
}
public StreamDesc removeStream(String inUid) {
return streams.remove(inUid);
}
public List<StreamDesc> getStreams() {
return new ArrayList<>(streams.values());
}
public StreamDesc getStream(String inUid) {
return streams.get(inUid);
}
public Optional<StreamDesc> getScreenStream() {
return streams.values().stream()
.filter(sd -> StreamType.SCREEN == sd.getType())
.findFirst();
}
public Stream<StreamDesc> getCamStreams() {
return streams.values().stream()
.filter(sd -> StreamType.WEBCAM == sd.getType());
}
public Client restoreActivities(StreamDesc sd) {
synchronized (activities) {
Set<Activity> aa = new HashSet<>(sd.sactivities);
activities.clear();
activities.addAll(aa);
}
return this;
}
public Date getConnectedSince() {
return connectedSince;
}
@Override
public Long getId() {
return null;
}
@Override
public void setId(Long id) {
//no-op
}
public Room getRoom() {
return room;
}
public Client setRoom(Room room) {
this.room = room;
return this;
}
public boolean isCamEnabled() {
return cam > -1;
}
public int getCam() {
return cam;
}
public Client setCam(int cam) {
this.cam = cam;
return this;
}
public boolean isMicEnabled() {
return mic > -1;
}
public int getMic() {
return mic;
}
public Client setMic(int mic) {
this.mic = mic;
return this;
}
public int getWidth() {
return width;
}
public Client setWidth(int width) {
this.width = width;
return this;
}
public int getHeight() {
return height;
}
public Client setHeight(int height) {
this.height = height;
return this;
}
public String getRemoteAddress() {
return remoteAddress;
}
public Client setRemoteAddress(String remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
public String getServerId() {
return serverId;
}
public void setServerId(String serverId) {
this.serverId = serverId;
}
public Long getRoomId() {
return room == null ? null : room.getId();
}
private JSONObject addUserJson(JSONObject o) {
JSONObject u = new JSONObject();
if (user != null) {
JSONObject a = new JSONObject();
u.put("id", user.getId())
.put("firstName", user.getFirstname())
.put("lastName", user.getLastname())
.put("displayName", user.getDisplayName())
.put("address", a)
.put("pictureUri", pictureUri);
if (user.getAddress() != null) {
if (Strings.isEmpty(user.getFirstname()) && Strings.isEmpty(user.getLastname())) {
a.put("email", user.getAddress().getEmail());
}
a.put("country", user.getAddress().getCountry());
}
}
return o.put("user", u)
.put("level", hasRight(Right.MODERATOR) ? 5 : (hasRight(Right.WHITEBOARD) ? 3 : 1));
}
public JSONObject toJson(boolean self) {
JSONArray streamArr = new JSONArray();
for (Entry<String, StreamDesc> e : streams.entrySet()) {
streamArr.put(e.getValue().toJson());
}
JSONObject json = new JSONObject()
.put("cuid", uid)
.put("uid", uid)
.put("rights", new JSONArray(rights))
.put("activities", new JSONArray(activities))
.put("streams", streamArr)
.put("width", width)
.put("height", height)
.put("self", self);
if (self) {
json.put("cam", cam).put("mic", mic);
}
return addUserJson(json);
}
public void merge(Client c) {
user = c.user;
room = c.room;
synchronized (rights) {
Set<Right> rr = new HashSet<>(c.rights);
rights.clear();
rights.addAll(rr);
}
synchronized (activities) {
Set<Activity> aa = new HashSet<>(c.activities);
activities.clear();
activities.addAll(aa);
}
synchronized (streams) {
Map<String, StreamDesc> ss = new HashMap<>(c.streams);
streams.clear();
for (Entry<String, StreamDesc> e : ss.entrySet()) {
streams.put(e.getKey(), new StreamDesc(e.getValue()));
}
}
cam = c.cam;
mic = c.mic;
width = c.width;
height = c.height;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((uid == null) ? 0 : uid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Client)) {
return false;
}
Client other = (Client) obj;
if (uid == null) {
if (other.uid != null) {
return false;
}
} else if (!uid.equals(other.uid)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Client [uid=" + uid + ", sessionId=" + sessionId + ", pageId=" + pageId + ", userId=" + getUserId() + ", room=" + getRoomId()
+ ", rights=" + rights + ", sactivities=" + activities + ", connectedSince=" + connectedSince + "]";
}
public class StreamDesc implements Serializable {
private static final long serialVersionUID = 1L;
private final Set<Activity> sactivities = ConcurrentHashMap.newKeySet();
private final String uuid;
private final StreamType type;
private int swidth;
private int sheight;
public StreamDesc(StreamDesc sd) {
this.uuid = sd.uuid;
this.type = sd.type;
this.swidth = sd.swidth;
this.sheight = sd.sheight;
sactivities.addAll(sd.sactivities);
}
public StreamDesc(StreamType type, Activity...activities) {
this.uuid = randomUUID().toString();
this.type = type;
if (activities == null || activities.length == 0) {
setActivities();
} else {
sactivities.addAll(List.of(activities));
}
if (StreamType.SCREEN == type) {
this.swidth = 800;
this.sheight = 600;
} else if (StreamType.WEBCAM == type) {
boolean interview = room != null && Room.Type.INTERVIEW == room.getType();
this.swidth = interview ? 320 : width;
this.sheight = interview ? 260 : height;
}
}
public String getSid() {
return sid;
}
public String getUid() {
return uuid;
}
public StreamType getType() {
return type;
}
public int getWidth() {
return swidth;
}
public StreamDesc setWidth(int width) {
this.swidth = width;
return this;
}
public int getHeight() {
return sheight;
}
public StreamDesc setHeight(int height) {
this.sheight = height;
return this;
}
public StreamDesc setActivities() {
sactivities.clear();
if (StreamType.WEBCAM == type) {
if (Client.this.hasActivity(Activity.AUDIO)) {
sactivities.add(Activity.AUDIO);
}
if (Client.this.hasActivity(Activity.VIDEO)) {
sactivities.add(Activity.VIDEO);
}
}
if (StreamType.SCREEN == type) {
sactivities.add(Activity.SCREEN);
}
return this;
}
public boolean hasActivity(Activity a) {
return sactivities.contains(a);
}
public void addActivity(Activity a) {
sactivities.add(a);
}
public StreamDesc removeActivity(Activity a) {
sactivities.remove(a);
return this;
}
public Client getClient() {
return Client.this;
}
public List<Activity> getActivities() {
return List.copyOf(sactivities);
}
public JSONObject toJson() {
return toJson(false);
}
public JSONObject toJson(boolean self) {
JSONObject o = new JSONObject()
.put("uid", uuid)
.put("type", type.name())
.put("width", swidth)
.put("height", sheight)
.put("activities", new JSONArray(sactivities))
.put("cuid", uid);
if (self) {
o.put("cam", cam).put("mic", mic);
}
return addUserJson(o);
}
@Override
public String toString() {
return String.format("Stream[uid=%s,type=%s,activities=%s]", uid, type, sactivities);
}
}
}