Skip to content

Commit 1cd472c

Browse files
committed
improved channel handling and features (wip)
1 parent d0ab15c commit 1cd472c

File tree

3 files changed

+195
-99
lines changed

3 files changed

+195
-99
lines changed

src/main/java/net/b07z/sepia/websockets/common/SocketChannel.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import java.util.Set;
66
import java.util.concurrent.ConcurrentSkipListSet;
77

8+
import org.json.simple.JSONArray;
9+
import org.json.simple.JSONObject;
10+
811
import net.b07z.sepia.server.core.server.ConfigDefaults;
12+
import net.b07z.sepia.server.core.tools.JSON;
913

1014
/**
1115
* This class represents a default private channel on the webSocketServer for registered users.
@@ -15,22 +19,58 @@
1519
*/
1620
public class SocketChannel {
1721

22+
//Some fixed channel IDs (don't allow users to create them!)
23+
public static final String OPEN_WORLD = "openWorld";
24+
public static final String INFO = "info";
25+
public static final String UNKNOWN = "unknown";
26+
public static final List<String> systemChannels = new ArrayList<>();
27+
static {
28+
systemChannels.add(OPEN_WORLD);
29+
systemChannels.add(INFO);
30+
systemChannels.add(UNKNOWN);
31+
}
32+
1833
private String channelId; //name of the channel
1934
private String channelKey; //password to access channel
2035

2136
private String owner; //admin of the channel
2237
private boolean isOpen = false;
2338
private Set<String> members; //users allowed to be in this channel
2439

40+
/**
41+
* Create new channel
42+
* @param id - unique channel ID
43+
* @param key - security key
44+
* @param owner - channel owner (user ID)
45+
*/
2546
public SocketChannel(String id, String key, String owner){
2647
this.channelId = id;
2748
this.channelKey = key;
49+
this.owner = owner;
2850
this.members = new ConcurrentSkipListSet<String>();
2951
if (key.equals("open")){
3052
this.isOpen = true;
3153
this.members.add(ConfigDefaults.defaultAssistantUserId);
3254
}
3355
}
56+
/**
57+
* Import channel data from JSON object previously generated with {@link #getJson()}.
58+
*/
59+
public SocketChannel(JSONObject channelJson){
60+
this.channelId = JSON.getString(channelJson, "channel_id");
61+
this.channelKey = JSON.getString(channelJson, "channel_key");
62+
this.isOpen = JSON.getBoolean(channelJson, "public");
63+
this.owner = JSON.getString(channelJson, "owner");
64+
this.members = new ConcurrentSkipListSet<String>();
65+
JSONArray membersArray = JSON.getJArray(channelJson, "members");
66+
for (Object o : membersArray){
67+
this.members.add(o.toString());
68+
}
69+
if (this.isOpen){
70+
//might already be in members but just to make sure ...
71+
this.members.add(ConfigDefaults.defaultAssistantUserId);
72+
}
73+
}
3474

3575
@Override
3676
public String toString(){
@@ -121,4 +161,22 @@ public boolean isUserMemberOfChannel(SocketUser user){
121161
return members.contains(user.getUserId());
122162
//return getAllMembers().contains(user);
123163
}
164+
165+
/**
166+
* Get channel data as JSON object.
167+
*/
168+
public JSONObject getJson(){
169+
JSONObject channel = new JSONObject();
170+
JSON.put(channel, "channel_id", channelId);
171+
JSON.put(channel, "channel_key", channelKey);
172+
JSON.put(channel, "owner", owner);
173+
JSON.put(channel, "public", isOpen);
174+
JSON.put(channel, "members", members.toArray());
175+
/*
176+
JSON.put(channel, "channel_name", ""); //not yet implemented
177+
JSON.put(channel, "assistants", new JSONArray()); //not yet implemented
178+
JSON.put(channel, "info", new JSONObject()); //not yet implemented
179+
*/
180+
return channel;
181+
}
124182
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package net.b07z.sepia.websockets.endpoints;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.json.simple.JSONArray;
7+
import org.json.simple.JSONObject;
8+
9+
import net.b07z.sepia.server.core.data.Role;
10+
import net.b07z.sepia.server.core.server.RequestParameters;
11+
import net.b07z.sepia.server.core.server.RequestPostParameters;
12+
import net.b07z.sepia.server.core.server.SparkJavaFw;
13+
import net.b07z.sepia.server.core.tools.JSON;
14+
import net.b07z.sepia.server.core.users.Account;
15+
import net.b07z.sepia.websockets.common.SocketChannel;
16+
import net.b07z.sepia.websockets.common.SocketChannelPool;
17+
import spark.Request;
18+
import spark.Response;
19+
20+
/**
21+
* Create, join and remove channels.
22+
*
23+
* @author Florian Quirin
24+
*/
25+
public class ChannelManager {
26+
27+
/**
28+
* Create a new channel.
29+
*/
30+
public static String createChannel(Request request, Response response){
31+
//get parameters (or throw error)
32+
RequestParameters params = new RequestPostParameters(request);
33+
34+
//authenticate
35+
Account userAccount = new Account();
36+
if (userAccount.authenticate(params)){
37+
//log.info("Authenticated: " + userAccount.getUserID() + ", roles: " + userAccount.getUserRoles()); //debug
38+
if (userAccount.hasRole(Role.developer.name())){
39+
//get parameters
40+
String channelId = params.getString("channelId");
41+
JSONArray initialMembers = params.getJsonArray("members");
42+
String owner = userAccount.getUserID();
43+
boolean isPublic = params.getBoolOrDefault("isPublic", false);
44+
boolean addAssistant = params.getBoolOrDefault("addAssistant", true);
45+
46+
if (channelId == null || channelId.isEmpty()){
47+
JSONObject msgJSON = JSON.make("result", "fail", "error", "missing channelId");
48+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
49+
}else{
50+
//filter system channels (user can't create them)
51+
if (SocketChannel.systemChannels.contains(channelId)){
52+
JSONObject msgJSON = JSON.make("result", "fail", "error", "invalid channelId");
53+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
54+
}
55+
//filter valid channel names
56+
String cleanChannelId = channelId.replaceAll("[^\\w\\s]","").replaceAll("\\s+", " ");
57+
if (!cleanChannelId.equals(channelId)){
58+
JSONObject msgJSON = JSON.make("result", "fail", "error", "invalid channelId, please use only letters, numbers and '_'.");
59+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
60+
}
61+
}
62+
try{
63+
//create channel
64+
String channelKey = SocketChannelPool.createChannel(channelId, owner, isPublic);
65+
if (channelKey != null){
66+
List<String> members = new ArrayList<>();
67+
members.add(owner);
68+
if (initialMembers != null && !initialMembers.isEmpty()){
69+
for (Object o : initialMembers){
70+
members.add((String) o);
71+
}
72+
}
73+
SocketChannel sc = SocketChannelPool.getChannel(channelId);
74+
for (String s : members){
75+
sc.addUser(s, channelKey);
76+
//System.out.println("Member: " + s); //DEBUG
77+
}
78+
if (addAssistant){
79+
sc.addSystemDefaultAssistant(); //Add SEPIA too
80+
//System.out.println("Member: " + SocketConfig.systemAssistantId); //DEBUG
81+
}
82+
JSONObject msgJSON = JSON.make("result", "success", "key", channelKey, "channelId", channelId);
83+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
84+
85+
}else{
86+
//error
87+
JSONObject msgJSON = JSON.make("result", "fail", "error", "creation failed! Maybe already exists?");
88+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
89+
}
90+
}catch (Exception e){
91+
//error
92+
JSONObject msgJSON = JSON.make("result", "fail", "error", e.getMessage());
93+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
94+
}
95+
}else{
96+
//refuse
97+
JSONObject msgJSON = JSON.make("result", "fail", "error", "not authorized, missing required role");
98+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 404);
99+
}
100+
}else{
101+
//refuse
102+
JSONObject msgJSON = JSON.make("result", "fail", "error", "not authorized");
103+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 404);
104+
}
105+
}
106+
107+
/**
108+
* Join a channel.
109+
*/
110+
public static String joinChannel(Request request, Response response){
111+
//TODO:
112+
// - authenticate
113+
// - get parameters (channelId, key, user)
114+
// - return success
115+
// ...
116+
117+
//get parameters (or throw error)
118+
RequestParameters params = new RequestPostParameters(request);
119+
120+
//authenticate
121+
Account userAccount = new Account();
122+
if (userAccount.authenticate(params)){
123+
124+
JSONObject msgJSON = JSON.make("result", "fail", "error", "not yet implemented");
125+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
126+
127+
}else{
128+
//refuse
129+
JSONObject msgJSON = JSON.make("result", "fail", "error", "not authorized");
130+
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 404);
131+
}
132+
}
133+
}

src/main/java/net/b07z/sepia/websockets/server/StartWebSocketServer.java

Lines changed: 4 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
package net.b07z.sepia.websockets.server;
22
import static spark.Spark.*;
33

4-
import java.util.ArrayList;
5-
import java.util.List;
6-
7-
import org.json.simple.JSONArray;
84
import org.json.simple.JSONObject;
95
import org.slf4j.Logger;
106
import org.slf4j.LoggerFactory;
117

12-
import net.b07z.sepia.server.core.data.Role;
138
import net.b07z.sepia.server.core.endpoints.CoreEndpoints;
149
import net.b07z.sepia.server.core.server.ConfigDefaults;
15-
import net.b07z.sepia.server.core.server.RequestParameters;
16-
import net.b07z.sepia.server.core.server.RequestPostParameters;
1710
import net.b07z.sepia.server.core.server.SparkJavaFw;
1811
import net.b07z.sepia.server.core.tools.DateTime;
1912
import net.b07z.sepia.server.core.tools.Debugger;
2013
import net.b07z.sepia.server.core.tools.JSON;
2114
import net.b07z.sepia.server.core.tools.Timer;
22-
import net.b07z.sepia.server.core.users.Account;
2315
import net.b07z.sepia.websockets.common.SocketChannel;
2416
import net.b07z.sepia.websockets.common.SocketChannelPool;
2517
import net.b07z.sepia.websockets.common.SocketConfig;
26-
import spark.Request;
27-
import spark.Response;
18+
import net.b07z.sepia.websockets.endpoints.ChannelManager;
2819

2920
public class StartWebSocketServer {
3021

@@ -116,7 +107,7 @@ public static void loadSettings(String[] args) {
116107
//SETUP DEFAULT CHANNELS
117108
public static void createDefaultChannels(){
118109
try {
119-
SocketChannelPool.createChannel("openWorld", SocketConfig.SERVERNAME, true); //Open world
110+
SocketChannelPool.createChannel(SocketChannel.OPEN_WORLD, SocketConfig.SERVERNAME, true); //Open world
120111

121112
} catch (Exception e) {
122113
log.error("One or more default channels could not be created!");
@@ -143,8 +134,8 @@ public static void main(String[] args) {
143134
get("/ping", (request, response) -> CoreEndpoints.ping(request, response, SocketConfig.SERVERNAME));
144135
get("/validate", (request, response) -> CoreEndpoints.validateServer(request, response, SocketConfig.SERVERNAME,
145136
SocketConfig.apiVersion, SocketConfig.localName, SocketConfig.localSecret));
146-
post("/createChannel", (request, response) -> createChannel(request, response));
147-
post("/joinChannel", (request, response) -> joinChannel(request, response));
137+
post("/createChannel", (request, response) -> ChannelManager.createChannel(request, response));
138+
post("/joinChannel", (request, response) -> ChannelManager.joinChannel(request, response));
148139
//TODO:
149140
//getChannel, getAllChannels, getChannelData, deleteChannel
150141

@@ -163,90 +154,4 @@ public static void main(String[] args) {
163154

164155
Debugger.println("Initialization complete, lets go!", 3);
165156
}
166-
167-
/**
168-
* Create a new channel.
169-
*/
170-
public static String createChannel(Request request, Response response){
171-
//get parameters (or throw error)
172-
RequestParameters params = new RequestPostParameters(request);
173-
174-
//authenticate
175-
Account userAccount = new Account();
176-
if (userAccount.authenticate(params)){
177-
//log.info("Authenticated: " + userAccount.getUserID() + ", roles: " + userAccount.getUserRoles()); //debug
178-
if (userAccount.hasRole(Role.developer.name())){
179-
//get parameters
180-
String channelId = params.getString("channelId");
181-
JSONArray initialMembers = params.getJsonArray("members");
182-
String owner = userAccount.getUserID();
183-
boolean isPublic = params.getBoolOrDefault("isPublic", false);
184-
boolean addAssistant = params.getBoolOrDefault("addAssistant", true);
185-
186-
if (channelId == null || channelId.isEmpty()){
187-
JSONObject msgJSON = JSON.make("result", "fail", "error", "missing channelId");
188-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
189-
}else{
190-
//TODO: filter valid channel names
191-
}
192-
try{
193-
//create channel
194-
String channelKey = SocketChannelPool.createChannel(channelId, owner, isPublic);
195-
if (channelKey != null){
196-
List<String> members = new ArrayList<>();
197-
members.add(owner);
198-
if (initialMembers != null && !initialMembers.isEmpty()){
199-
for (Object o : initialMembers){
200-
members.add((String) o);
201-
}
202-
}
203-
SocketChannel sc = SocketChannelPool.getChannel(channelId);
204-
for (String s : members){
205-
sc.addUser(s, channelKey);
206-
//System.out.println("Member: " + s); //DEBUG
207-
}
208-
if (addAssistant){
209-
sc.addSystemDefaultAssistant(); //Add SEPIA too
210-
//System.out.println("Member: " + SocketConfig.systemAssistantId); //DEBUG
211-
}
212-
JSONObject msgJSON = JSON.make("result", "success", "key", channelKey, "channelId", channelId);
213-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
214-
215-
}else{
216-
//error
217-
JSONObject msgJSON = JSON.make("result", "fail", "error", "creation failed! Maybe already exists?");
218-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
219-
}
220-
}catch (Exception e){
221-
//error
222-
JSONObject msgJSON = JSON.make("result", "fail", "error", e.getMessage());
223-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
224-
}
225-
}else{
226-
//refuse
227-
JSONObject msgJSON = JSON.make("result", "fail", "error", "not authorized, missing required role");
228-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 404);
229-
}
230-
}else{
231-
//refuse
232-
JSONObject msgJSON = JSON.make("result", "fail", "error", "not authorized");
233-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 404);
234-
}
235-
}
236-
/**
237-
* Join a channel.
238-
*/
239-
public static String joinChannel(Request request, Response response){
240-
//TODO:
241-
// - authenticate
242-
// - get parameters (channelId, key, user)
243-
// - return success
244-
// ...
245-
//get parameters (or throw error)
246-
//RequestParameters params = new RequestPostParameters(request);
247-
248-
JSONObject msgJSON = JSON.make("result", "fail", "error", "not yet implemented");
249-
return SparkJavaFw.returnResult(request, response, msgJSON.toJSONString(), 200);
250-
}
251-
252157
}

0 commit comments

Comments
 (0)