Browse Source

在线用户、自动保存优化

mxd 3 years ago
parent
commit
ac5238375b

+ 9 - 1
magic-api/src/main/java/org/ssssssss/magicapi/config/MessageType.java

@@ -13,6 +13,12 @@ public enum MessageType {
 	EXCEPTION,
 	/* 发送给客户端的sessionId */
 	SESSION_ID,
+	/* 通知客户端,有用户上线 */
+	USER_LOGIN,
+	/* 通知客户端,有用户下线 */
+	USER_LOGOUT,
+	/* 通知客户端,当前机器在线人数 */
+	ONLINE_USERS,
 
 	/* C -> S message */
 	/* 设置断点 */
@@ -20,5 +26,7 @@ public enum MessageType {
 	/* 恢复断点 */
 	RESUME_BREAKPOINT,
 	/* 登录 */
-	LOGIN
+	LOGIN,
+	/* 获取当前在线用户 */
+	GET_ONLINE
 }

+ 7 - 2
magic-api/src/main/java/org/ssssssss/magicapi/config/WebSocketSessionManager.java

@@ -11,6 +11,8 @@ import org.ssssssss.magicapi.utils.JsonUtils;
 import org.ssssssss.script.MagicScriptDebugContext;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
@@ -29,7 +31,10 @@ public class WebSocketSessionManager {
 
 	public static void add(MagicConsoleSession session) {
 		SESSIONS.put(session.getId(), session);
-		sendBySession(session, buildMessage(MessageType.SESSION_ID, session.getId()));
+	}
+
+	public static List<MagicConsoleSession> getSessions(){
+		return new ArrayList<>(SESSIONS.values());
 	}
 
 	public static void remove(MagicConsoleSession session) {
@@ -69,7 +74,7 @@ public class WebSocketSessionManager {
 		}
 	}
 
-	private static String buildMessage(MessageType messageType, Object... values) {
+	public static String buildMessage(MessageType messageType, Object... values) {
 		StringBuilder builder = new StringBuilder(messageType.name().toLowerCase());
 		if (values != null) {
 			for (int i = 0, len = values.length; i < len; i++) {

+ 8 - 1
magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicResourceController.java

@@ -48,7 +48,7 @@ public class MagicResourceController extends MagicController implements MagicExc
 
 	@PostMapping("/resource/file/{folder}/save")
 	@ResponseBody
-	public JsonBean<String> saveFile(@PathVariable("folder") String folder, HttpServletRequest request) throws IOException {
+	public JsonBean<String> saveFile(@PathVariable("folder") String folder, String auto, HttpServletRequest request) throws IOException {
 		byte[] bytes = IoUtils.bytes(request.getInputStream());
 		MagicEntity entity = configuration.getMagicDynamicRegistries().stream()
 				.map(MagicDynamicRegistry::getMagicResourceStorage)
@@ -57,6 +57,13 @@ public class MagicResourceController extends MagicController implements MagicExc
 				.orElseThrow(() -> new InvalidArgumentException(GROUP_NOT_FOUND))
 				.read(bytes);
 		isTrue(allowVisit(request, Authorization.SAVE, entity), PERMISSION_INVALID);
+		// 自动保存的代码,和旧版代码对比,如果一致,则不保存,直接返回。
+		if(entity.getId() != null && "1".equals(auto)){
+			MagicEntity oldInfo = service.file(entity.getId());
+			if(Objects.equals(oldInfo.getScript(), entity.getScript())){
+				return new JsonBean<>(entity.getId());
+			}
+		}
 		if (MagicConfiguration.getMagicResourceService().saveFile(entity)) {
 			return new JsonBean<>(entity.getId());
 		}

+ 10 - 1
magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicWebSocketDispatcher.java

@@ -7,14 +7,17 @@ import org.springframework.web.socket.TextMessage;
 import org.springframework.web.socket.WebSocketSession;
 import org.springframework.web.socket.handler.TextWebSocketHandler;
 import org.ssssssss.magicapi.config.Message;
+import org.ssssssss.magicapi.config.MessageType;
 import org.ssssssss.magicapi.config.WebSocketSessionManager;
 import org.ssssssss.magicapi.event.EventAction;
+import org.ssssssss.magicapi.interceptor.MagicUser;
 import org.ssssssss.magicapi.model.MagicConsoleSession;
 import org.ssssssss.magicapi.model.MagicNotify;
 import org.ssssssss.magicapi.provider.MagicNotifyService;
 import org.ssssssss.magicapi.utils.JsonUtils;
 import org.ssssssss.script.reflection.MethodInvoker;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -44,6 +47,7 @@ public class MagicWebSocketDispatcher extends TextWebSocketHandler {
 		WebSocketSessionManager.setInstanceId(instanceId);
 		websocketMessageHandlers.forEach(websocketMessageHandler ->
 				Stream.of(websocketMessageHandler.getClass().getDeclaredMethods())
+						.filter(it -> it.getAnnotation(Message.class) != null)
 						.forEach(method -> HANDLERS.put(method.getAnnotation(Message.class).value().name().toLowerCase(), new MethodInvoker(method, websocketMessageHandler)))
 		);
 	}
@@ -96,8 +100,13 @@ public class MagicWebSocketDispatcher extends TextWebSocketHandler {
 
 	@Override
 	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
-		WebSocketSessionManager.remove(MagicConsoleSession.from(session));
+		MagicConsoleSession mcsession = MagicConsoleSession.from(session);
+		WebSocketSessionManager.remove(mcsession);
 		MagicConsoleSession.remove(session);
+		MagicUser user = (MagicUser) mcsession.getAttribute("user");
+		if(user != null){
+			WebSocketSessionManager.sendToAll(MessageType.USER_LOGOUT, Arrays.asList(mcsession.getId(), mcsession.getAttribute("ip"), user));
+		}
 	}
 
 	@Override

+ 29 - 1
magic-api/src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchHandler.java

@@ -5,8 +5,15 @@ import org.ssssssss.magicapi.config.MessageType;
 import org.ssssssss.magicapi.config.WebSocketSessionManager;
 import org.ssssssss.magicapi.exception.MagicLoginException;
 import org.ssssssss.magicapi.interceptor.AuthorizationInterceptor;
+import org.ssssssss.magicapi.interceptor.MagicUser;
 import org.ssssssss.magicapi.model.MagicConsoleSession;
 
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
 /**
  * UI上其它操作处理
  *
@@ -16,6 +23,8 @@ public class MagicWorkbenchHandler {
 
 	private final AuthorizationInterceptor authorizationInterceptor;
 
+	private final static MagicUser guest = new MagicUser("guest","游客", "unauthorization");
+
 	public MagicWorkbenchHandler(AuthorizationInterceptor authorizationInterceptor) {
 		this.authorizationInterceptor = authorizationInterceptor;
 	}
@@ -23,11 +32,30 @@ public class MagicWorkbenchHandler {
 	@Message(MessageType.LOGIN)
 	public void onLogin(MagicConsoleSession session, String token) {
 		try {
-			if (!authorizationInterceptor.requireLogin() || authorizationInterceptor.getUserByToken(token) != null) {
+			MagicUser user = guest;
+			if (!authorizationInterceptor.requireLogin() || (user = authorizationInterceptor.getUserByToken(token)) != null) {
+				String ip = Optional.ofNullable(session.getWebSocketSession().getRemoteAddress()).map(it -> it.getAddress().getHostAddress()).orElse("unknown");
+				session.setAttribute("user", user);
+				session.setAttribute("ip", ip);
 				WebSocketSessionManager.add(session);
+				List<Object> messages = Arrays.asList(session.getId(), ip, user);
+				WebSocketSessionManager.sendBySession(session, WebSocketSessionManager.buildMessage(MessageType.SESSION_ID, messages));
+				WebSocketSessionManager.sendToAll(MessageType.USER_LOGIN, messages);
 			}
 		} catch (MagicLoginException ignored) {
 
 		}
 	}
+
+	@Message(MessageType.GET_ONLINE)
+	public boolean getOnline(MagicConsoleSession session) {
+		List<MagicConsoleSession> sessions = WebSocketSessionManager.getSessions();
+		if(sessions.size() > 0){
+			List<List<Object>> messages = sessions.stream()
+					.map(it -> Arrays.asList(it.getId(), it.getAttribute("ip"), it.getAttribute("user")))
+					.collect(Collectors.toList());
+			WebSocketSessionManager.sendBySessionId(session.getId(), WebSocketSessionManager.buildMessage(MessageType.ONLINE_USERS, messages));
+		}
+		return false;
+	}
 }

+ 10 - 0
magic-api/src/main/java/org/ssssssss/magicapi/model/MagicConsoleSession.java

@@ -2,6 +2,7 @@ package org.ssssssss.magicapi.model;
 
 import org.springframework.web.socket.WebSocketSession;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -14,6 +15,8 @@ public class MagicConsoleSession {
 
 	private final WebSocketSession webSocketSession;
 
+	private final Map<String, Object> attributes = new HashMap<>();
+
 	public MagicConsoleSession(WebSocketSession webSocketSession) {
 		this.webSocketSession = webSocketSession;
 	}
@@ -42,4 +45,11 @@ public class MagicConsoleSession {
 	public static void remove(WebSocketSession session) {
 		cached.remove(session.getId());
 	}
+
+	public Object getAttribute(String key){
+		return attributes.get(key);
+	}
+	public void setAttribute(String key, Object value){
+		attributes.put(key, value);
+	}
 }

+ 0 - 4
magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DataSourceMagicDynamicRegistry.java

@@ -27,8 +27,6 @@ public class DataSourceMagicDynamicRegistry extends AbstractMagicDynamicRegistry
 
 	private final MagicDynamicDataSource magicDynamicDataSource;
 
-	private static final Logger logger = LoggerFactory.getLogger(DataSourceMagicDynamicRegistry.class);
-
 	private static final ClassLoader CLASSLOADER = DataSourceMagicDynamicRegistry.class.getClassLoader();
 
 	// copy from DataSourceBuilder
@@ -61,14 +59,12 @@ public class DataSourceMagicDynamicRegistry extends AbstractMagicDynamicRegistry
 		}
 		DataSource datasource = createDataSource(getDataSourceType(info.getType()), properties);
 		magicDynamicDataSource.put(info.getId(), info.getKey(), info.getName(), datasource, info.getMaxRows());
-		logger.debug("注册数据源:{}", info.getKey());
 		return true;
 	}
 
 
 	@Override
 	public boolean unregister(DataSourceInfo info) {
-		logger.debug("取消注册数据源:{}", info.getKey());
 		return magicDynamicDataSource.delete(info.getKey());
 	}
 

+ 9 - 3
magic-api/src/main/java/org/ssssssss/magicapi/service/impl/DefaultMagicResourceService.java

@@ -124,9 +124,9 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
 		});
 	}
 
-	@Override
-	public void refresh() {
+	private void read(){
 		writeLock(() -> {
+			publisher.publishEvent(new MagicEvent("clear", EventAction.CLEAR));
 			this.init();
 			this.root.readAll();
 			storages.forEach((key, registry) -> refreshGroup(root.getDirectory(key), registry));
@@ -138,6 +138,12 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
 		});
 	}
 
+	@Override
+	public void refresh() {
+		publisher.publishEvent(new MagicEvent("clear", EventAction.CLEAR));
+		this.read();
+	}
+
 	@Override
 	public Resource getResource() {
 		return root;
@@ -787,6 +793,6 @@ public class DefaultMagicResourceService implements MagicResourceService, JsonCo
 
 	@Override
 	public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
-		this.refresh();
+		this.read();
 	}
 }