SHA256
Промежуточная версия
в которой надо дорабоать 1. Исправить ошибки и сделать что бы работала вторая слева вкладка. ТОесть АПИ для сервера я сделал (пока они возвращают весь список сообщений целиком - всем большим списком сообщений в канал - для мвп это устраивает,и по этому только три АПИ функции добавилось) Там какието ошибки на клиенте ( я только сгенерил код - но гдето вылетает) по UI можешь исправлять переделывать - моешь оставить калечное как есть - мне пока не важно. Важно увидить что каналы и сообщения и публичная переписка в каналах блокчейна работает 2. потестировать и сделать корректное завершение сессии (там есть глюки при завершении сесии)
This commit is contained in:
+100
@@ -0,0 +1,100 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ClientErrorLog_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ClientErrorLog_Response;
|
||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* ClientErrorLog — технический endpoint для фронтенд-ошибок.
|
||||
* Не требует авторизации: клиент должен иметь возможность отправить ошибку
|
||||
* даже если логин/сессия ещё не установлены.
|
||||
*/
|
||||
public class Net_ClientErrorLog_Handler implements JsonMessageHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Net_ClientErrorLog_Handler.class);
|
||||
|
||||
@Override
|
||||
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
|
||||
Net_ClientErrorLog_Request req = (Net_ClientErrorLog_Request) baseRequest;
|
||||
|
||||
if (req.getMessage() == null || req.getMessage().isBlank()) {
|
||||
return NetExceptionResponseFactory.error(
|
||||
req,
|
||||
WireCodes.Status.BAD_REQUEST,
|
||||
"BAD_FIELDS",
|
||||
"Поле message обязательно для ClientErrorLog"
|
||||
);
|
||||
}
|
||||
|
||||
long serverTs = System.currentTimeMillis();
|
||||
String login = safe(ctx != null ? ctx.getLogin() : null);
|
||||
String sessionId = safe(ctx != null ? ctx.getSessionId() : null);
|
||||
String remote = safe(remoteAddress(ctx));
|
||||
|
||||
log.error(
|
||||
"CLIENT_FRONTEND_ERROR kind={} clientTs={} serverTs={} login={} sessionId={} remote={} route={} href={} sourceUrl={} line={} column={} requestOp={} requestIdRef={} message={} userAgent={} context={}",
|
||||
clip(req.getKind(), 64),
|
||||
req.getClientTs(),
|
||||
serverTs,
|
||||
clip(login, 64),
|
||||
clip(sessionId, 128),
|
||||
clip(remote, 128),
|
||||
clip(req.getRoute(), 200),
|
||||
clip(req.getHref(), 240),
|
||||
clip(req.getSourceUrl(), 240),
|
||||
req.getLineNumber(),
|
||||
req.getColumnNumber(),
|
||||
clip(req.getRequestOp(), 64),
|
||||
clip(req.getRequestIdRef(), 128),
|
||||
clip(req.getMessage(), 500),
|
||||
clip(req.getUserAgent(), 240),
|
||||
clip(req.getContextJson(), 2000)
|
||||
);
|
||||
|
||||
if (req.getStack() != null && !req.getStack().isBlank()) {
|
||||
log.error("CLIENT_FRONTEND_ERROR_STACK requestId={} stack={}",
|
||||
clip(req.getRequestId(), 128),
|
||||
clip(req.getStack(), 8000));
|
||||
}
|
||||
|
||||
Net_ClientErrorLog_Response resp = new Net_ClientErrorLog_Response();
|
||||
resp.setOp(req.getOp());
|
||||
resp.setRequestId(req.getRequestId());
|
||||
resp.setStatus(WireCodes.Status.OK);
|
||||
resp.setAccepted(true);
|
||||
resp.setServerTs(serverTs);
|
||||
return resp;
|
||||
}
|
||||
|
||||
private static String remoteAddress(ConnectionContext ctx) {
|
||||
if (ctx == null) return "";
|
||||
Session ws = ctx.getWsSession();
|
||||
if (ws == null) return "";
|
||||
SocketAddress remote = ws.getRemoteAddress();
|
||||
return remote != null ? remote.toString() : "";
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private static String clip(String value, int maxLen) {
|
||||
String cleaned = safe(value)
|
||||
.replace('\n', ' ')
|
||||
.replace('\r', ' ');
|
||||
if (cleaned.length() <= maxLen) {
|
||||
return cleaned;
|
||||
}
|
||||
return cleaned.substring(0, Math.max(0, maxLen - 3)) + "...";
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system;
|
||||
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_GetServerInfo_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_GetServerInfo_Response;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
import utils.config.AppConfig;
|
||||
|
||||
/**
|
||||
* GetServerInfo — технический запрос без авторизации.
|
||||
* Возвращает базовую публичную информацию о сервере, чтобы клиент
|
||||
* мог проверить доступность узла и показать его в списке серверов.
|
||||
*/
|
||||
public class Net_GetServerInfo_Handler implements JsonMessageHandler {
|
||||
|
||||
private static final AppConfig CONFIG = AppConfig.getInstance();
|
||||
|
||||
@Override
|
||||
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
|
||||
Net_GetServerInfo_Request req = (Net_GetServerInfo_Request) baseRequest;
|
||||
|
||||
Net_GetServerInfo_Response resp = new Net_GetServerInfo_Response();
|
||||
resp.setOp(req.getOp());
|
||||
resp.setRequestId(req.getRequestId());
|
||||
resp.setStatus(WireCodes.Status.OK);
|
||||
resp.setUrl(CONFIG.getStringOrEmpty("server.info.url"));
|
||||
resp.setVersion(CONFIG.getStringOrEmpty("server.version"));
|
||||
resp.setPhysicalRegion(CONFIG.getStringOrEmpty("server.info.physicalRegion"));
|
||||
resp.setDescription(CONFIG.getStringOrEmpty("server.info.description"));
|
||||
resp.setOrigin(CONFIG.getStringOrEmpty("server.info.origin"));
|
||||
resp.setExtraInfo(CONFIG.getStringOrEmpty("server.info.extraInfo"));
|
||||
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
/**
|
||||
* ClientErrorLog:
|
||||
* {
|
||||
* "op": "ClientErrorLog",
|
||||
* "requestId": "req-1",
|
||||
* "payload": {
|
||||
* "kind": "global_error",
|
||||
* "message": "...",
|
||||
* "stack": "...",
|
||||
* "sourceUrl": "...",
|
||||
* "lineNumber": 10,
|
||||
* "columnNumber": 20,
|
||||
* "route": "#/channel-view/own-0",
|
||||
* "href": "https://example/#/channel-view/own-0",
|
||||
* "userAgent": "...",
|
||||
* "clientTs": 1700000000123,
|
||||
* "requestOp": "GetChannelMessages",
|
||||
* "requestIdRef": "GetChannelMessages-123",
|
||||
* "contextJson": "{...}"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public class Net_ClientErrorLog_Request extends Net_Request {
|
||||
|
||||
private String kind;
|
||||
private String message;
|
||||
private String stack;
|
||||
private String sourceUrl;
|
||||
private Integer lineNumber;
|
||||
private Integer columnNumber;
|
||||
private String route;
|
||||
private String href;
|
||||
private String userAgent;
|
||||
private Long clientTs;
|
||||
private String requestOp;
|
||||
private String requestIdRef;
|
||||
private String contextJson;
|
||||
|
||||
public String getKind() { return kind; }
|
||||
public void setKind(String kind) { this.kind = kind; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public String getStack() { return stack; }
|
||||
public void setStack(String stack) { this.stack = stack; }
|
||||
|
||||
public String getSourceUrl() { return sourceUrl; }
|
||||
public void setSourceUrl(String sourceUrl) { this.sourceUrl = sourceUrl; }
|
||||
|
||||
public Integer getLineNumber() { return lineNumber; }
|
||||
public void setLineNumber(Integer lineNumber) { this.lineNumber = lineNumber; }
|
||||
|
||||
public Integer getColumnNumber() { return columnNumber; }
|
||||
public void setColumnNumber(Integer columnNumber) { this.columnNumber = columnNumber; }
|
||||
|
||||
public String getRoute() { return route; }
|
||||
public void setRoute(String route) { this.route = route; }
|
||||
|
||||
public String getHref() { return href; }
|
||||
public void setHref(String href) { this.href = href; }
|
||||
|
||||
public String getUserAgent() { return userAgent; }
|
||||
public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
|
||||
|
||||
public Long getClientTs() { return clientTs; }
|
||||
public void setClientTs(Long clientTs) { this.clientTs = clientTs; }
|
||||
|
||||
public String getRequestOp() { return requestOp; }
|
||||
public void setRequestOp(String requestOp) { this.requestOp = requestOp; }
|
||||
|
||||
public String getRequestIdRef() { return requestIdRef; }
|
||||
public void setRequestIdRef(String requestIdRef) { this.requestIdRef = requestIdRef; }
|
||||
|
||||
public String getContextJson() { return contextJson; }
|
||||
public void setContextJson(String contextJson) { this.contextJson = contextJson; }
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
public class Net_ClientErrorLog_Response extends Net_Response {
|
||||
|
||||
private long serverTs;
|
||||
private boolean accepted;
|
||||
|
||||
public long getServerTs() { return serverTs; }
|
||||
public void setServerTs(long serverTs) { this.serverTs = serverTs; }
|
||||
|
||||
public boolean isAccepted() { return accepted; }
|
||||
public void setAccepted(boolean accepted) { this.accepted = accepted; }
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
/**
|
||||
* GetServerInfo:
|
||||
* {
|
||||
* "op": "GetServerInfo",
|
||||
* "requestId": "req-1",
|
||||
* "payload": {}
|
||||
* }
|
||||
*/
|
||||
public class Net_GetServerInfo_Request extends Net_Request {
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
/**
|
||||
* Ответ GetServerInfo:
|
||||
* {
|
||||
* "op": "GetServerInfo",
|
||||
* "requestId": "req-1",
|
||||
* "status": 200,
|
||||
* "payload": {
|
||||
* "url": "...",
|
||||
* "version": "...",
|
||||
* "physicalRegion": "...",
|
||||
* "description": "...",
|
||||
* "origin": "...",
|
||||
* "extraInfo": "..."
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public class Net_GetServerInfo_Response extends Net_Response {
|
||||
|
||||
private String url;
|
||||
private String version;
|
||||
private String physicalRegion;
|
||||
private String description;
|
||||
private String origin;
|
||||
private String extraInfo;
|
||||
|
||||
public String getUrl() { return url; }
|
||||
public void setUrl(String url) { this.url = url; }
|
||||
|
||||
public String getVersion() { return version; }
|
||||
public void setVersion(String version) { this.version = version; }
|
||||
|
||||
public String getPhysicalRegion() { return physicalRegion; }
|
||||
public void setPhysicalRegion(String physicalRegion) { this.physicalRegion = physicalRegion; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getOrigin() { return origin; }
|
||||
public void setOrigin(String origin) { this.origin = origin; }
|
||||
|
||||
public String getExtraInfo() { return extraInfo; }
|
||||
public void setExtraInfo(String extraInfo) { this.extraInfo = extraInfo; }
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package server.logic.ws_protocol.JSON.utils;
|
||||
|
||||
import server.logic.ws_protocol.Base64Ws;
|
||||
|
||||
/**
|
||||
* Утилиты для строковых публичных ключей, используемых в auth/session API.
|
||||
*
|
||||
* Поддерживаемые форматы:
|
||||
* - legacy: BASE64(32 bytes)
|
||||
* - explicit: ed25519/BASE64(32 bytes)
|
||||
*/
|
||||
public final class AuthKeyUtils {
|
||||
|
||||
private AuthKeyUtils() {}
|
||||
|
||||
public static String normalize(String key, String fieldName) {
|
||||
if (key == null) throw new IllegalArgumentException(fieldName + " is null");
|
||||
String trimmed = key.trim();
|
||||
if (trimmed.isEmpty()) throw new IllegalArgumentException(fieldName + " is empty");
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public static byte[] parseEd25519PublicKey(String key, String fieldName) {
|
||||
String normalized = normalize(key, fieldName);
|
||||
|
||||
int slash = normalized.indexOf('/');
|
||||
if (slash < 0) {
|
||||
return Base64Ws.decodeLen(normalized, 32, fieldName);
|
||||
}
|
||||
|
||||
String algorithm = normalized.substring(0, slash).trim();
|
||||
String encodedKey = normalized.substring(slash + 1).trim();
|
||||
|
||||
if (algorithm.isEmpty() || encodedKey.isEmpty()) {
|
||||
throw new IllegalArgumentException(fieldName + " has bad algorithm/key format");
|
||||
}
|
||||
|
||||
if (!"ed25519".equalsIgnoreCase(algorithm)) {
|
||||
throw new UnsupportedOperationException(fieldName + " algorithm is not supported: " + algorithm);
|
||||
}
|
||||
|
||||
return Base64Ws.decodeLen(encodedKey, 32, fieldName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user