cometd源码阅读-WebSocketTransport普通消息处理过程(八)
<1>
入口处从开始看
https://www.cnblogs.com/LQBlog/p/16594835.html#autoid-2-3-0
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#processMessage
private void processMessage(ServerMessage.Mutable[] messages, Context context, ServerMessageImpl message, Promise<Boolean> promise) { if (_logger.isDebugEnabled()) { _logger.debug("Processing {} on {}", message, this); } //为message设置当前transport信息 message.setServerTransport(_transport); //为message_bayeuxContext message.setBayeuxContext(_bayeuxContext); //为session设置transport ServerSessionImpl session = context.session; if (session != null) { session.setServerTransport(_transport); } //获得message channel String channel = message.getChannel(); //是否是握手请求 if (Channel.META_HANDSHAKE.equals(channel)) { if (messages.length > 1) { promise.fail(new IOException("protocol violation")); } else { if (session != null) { //设置为null 握手之前不需要发送消息 session.setScheduler(null); } //处理握手请求 processMetaHandshake(context, message, promise); } } else { //握手之前主动推送消息 if (session != null && session.updateServerEndPoint(this)) { session.setScheduler(new WebSocketScheduler(context, message, 0)); } //是否是续约消息 if (Channel.META_CONNECT.equals(channel)) { processMetaConnect(context, message, Promise.from(proceed -> { if (proceed) { resume(context, message, Promise.from(y -> promise.succeed(true), promise::fail)); } else { promise.succeed(false); } }, promise::fail)); } else { //<2>普通消息 processMessage(context, message, promise); } } }
<2>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#processMessage
private void processMessage(Context context, ServerMessageImpl message, Promise<Boolean> promise) { ServerSessionImpl session = context.session; //<3>内部调用extends的incoming方法 _transport.getBayeux().handle(session, message, Promise.from(y -> _transport.processReply(session, message.getAssociated(), Promise.from(reply -> { if (reply != null) { context.replies.add(reply); } if (!isMetaConnectDeliveryOnly(session)) { context.sendQueue = true; } // Leave scheduleExpiration unchanged. promise.succeed(true); }, promise::fail)), promise::fail)); }
<3>
org.cometd.server.BayeuxServerImpl#handle
private void handle1(ServerSessionImpl session, ServerMessage.Mutable message, Promise<ServerMessage.Mutable> promise) { if (_logger.isDebugEnabled()) { _logger.debug("> {} {}", message, session); } ServerMessage.Mutable reply = message.getAssociated(); //session的有效性进行校验 session断开连接,或者 messageid与clientId对不上同时又不是握手请求 if (session == null || session.isDisconnected() || (!session.getId().equals(message.getClientId()) && !Channel.META_HANDSHAKE.equals(message.getChannel()))) { //消息追加错误 unknownSession(reply); promise.succeed(reply); } else { String channelName = message.getChannel(); //针对meta_connect session 执行续约 session.cancelExpiration(Channel.META_CONNECT.equals(channelName)); if (channelName == null) { error(reply, "400::channel_missing"); promise.succeed(reply); } else { //从服务器获得channel ServerChannelImpl channel = getServerChannel(channelName); if (channel == null) { //channel没有找到则先走创建channel流程 isCreationAuthorized(session, message, channelName, Promise.from(result -> { if (result instanceof Authorizer.Result.Denied) { String denyReason = ((Authorizer.Result.Denied)result).getReason(); error(reply, "403:" + denyReason + ":channel_create_denied"); promise.succeed(reply); } else { //<4>处理消息 handle2(session, message, (ServerChannelImpl)createChannelIfAbsent(channelName).getReference(), promise); } }, promise::fail)); } else { //<4>处理消息 handle2(session, message, channel, promise); } } } }
<4>
org.cometd.server.BayeuxServerImpl#handle2
private void handle2(ServerSessionImpl session, ServerMessage.Mutable message, ServerChannelImpl channel, Promise<ServerMessage.Mutable> promise) { ServerMessage.Mutable reply = message.getAssociated(); //是否是/meta 内置协议开头的channel if (channel.isMeta()) { //消息处理 publish(session, channel, message, true, Promise.from(published -> promise.succeed(reply), promise::fail)); } else { //校验是否有权限推送 isPublishAuthorized(channel, session, message, Promise.from(result -> { if (result instanceof Authorizer.Result.Denied) { String denyReason = ((Authorizer.Result.Denied)result).getReason(); error(reply, "403:" + denyReason + ":publish_denied"); promise.succeed(reply); } else { reply.setSuccessful(true); //<5>消息处理 publish(session, channel, message, true, Promise.from(published -> promise.succeed(reply), promise::fail)); } }, promise::fail)); } }
<5>
org.cometd.server.BayeuxServerImpl#publish
protected void publish(ServerSessionImpl session, ServerChannelImpl channel, ServerMessage.Mutable message, boolean receiving, Promise<Boolean> promise) { if (_logger.isDebugEnabled()) { _logger.debug("< {} {}", message, session); } //channel非/meta和非/service if (channel.isBroadcast()) { // Do not leak the clientId to other subscribers // as we are now "sending" this message. message.setClientId(null); // Reset the messageId to avoid clashes with message-based transports such // as websocket whose clients may rely on the messageId to match request/responses. message.setId(null); } //触发Listener通知 notifyListeners(session, channel, message, Promise.from(proceed -> { if (proceed) { //<6>处理消息 publish1(session, channel, message, receiving, promise); } else { ServerMessageImpl reply = (ServerMessageImpl)message.getAssociated(); if (reply != null && !reply.isHandled()) { error(reply, "404::message_deleted"); } promise.succeed(false); } }, promise::fail)); }
<6>
org.cometd.server.BayeuxServerImpl#publish1
private void publish1(ServerSessionImpl session, ServerChannelImpl channel, ServerMessage.Mutable message, boolean receiving, Promise<Boolean> promise) { //非/meta和/service/开头的渠道 if (channel.isBroadcast() || !receiving) { extendOutgoing(session, null, message, Promise.from(result -> { if (result) { // Exactly at this point, we convert the message to JSON and therefore // any further modification will be lost. // This is an optimization so that if the message is sent to a million // subscribers, we generate the JSON only once. // From now on, user code is passed a ServerMessage reference (and not // ServerMessage.Mutable), and we attempt to return immutable data // structures, even if it is not possible to guard against all cases. // For example, it is impossible to prevent things like // ((CustomObject)serverMessage.getData()).change() or // ((Map)serverMessage.getExt().get("map")).put(). //重新格式化消息的json freeze(message); //<7>处理消息 publish2(session, channel, message, promise); } else { ServerMessage.Mutable reply = message.getAssociated(); error(reply, "404::message_deleted"); promise.succeed(false); } }, promise::fail)); } else { //<7>处理消息 publish2(session, channel, message, promise); } }
<7>
org.cometd.server.BayeuxServerImpl#publish2
private void publish2(ServerSessionImpl session, ServerChannelImpl channel, ServerMessage.Mutable message, Promise<Boolean> promise) { //是否是/meta内部协议渠道 if (channel.isMeta()) { notifyMetaHandlers(session, channel, message, promise); } else if (channel.isBroadcast()) {//非/meta和/server的渠道 //<8> notifySubscribers(session, channel, message, promise); } else { promise.succeed(true); } }
<8>
org.cometd.server.BayeuxServerImpl#notifySubscribers
private void notifySubscribers(ServerSessionImpl session, ServerChannelImpl channel, Mutable message, Promise<Boolean> promise) { Set<String> wildSubscribers = new HashSet<>();
//先通知模糊匹配的 比如/chat/demo 有的客户端订阅了/chat/* AsyncFoldLeft.run(channel.getChannelId().getWilds(), true, (result, wildName, wildLoop) -> { //获得channel ServerChannelImpl wildChannel = _channels.get(wildName); if (wildChannel == null) { wildLoop.proceed(result); } else { //获得channel的订阅者 Set<ServerSession> subscribers = wildChannel.subscribers(); if (_logger.isDebugEnabled()) { _logger.debug("Notifying {} subscribers on {}", subscribers.size(), wildChannel); } //遍历调用订阅者的获取消息方法 AsyncFoldLeft.run(subscribers, true, (r, subscriber, loop) -> { if (wildSubscribers.add(subscriber.getId())) { //是否允许自己给自己发送消息 当前渠道 if (subscriber == session && !channel.isBroadcastToPublisher()) { loop.proceed(true); } else { //<9>放入消息队列 ((ServerSessionImpl)subscriber).deliver1(session, message, Promise.from(b -> loop.proceed(true), loop::fail)); } } else { loop.proceed(r); } }, Promise.from(y -> wildLoop.proceed(true), wildLoop::fail)); } }, Promise.from(b -> {
//再推送给直接订阅 如:/chat/demo Set<ServerSession> subscribers = channel.subscribers(); if (_logger.isDebugEnabled()) { _logger.debug("Notifying {} subscribers on {}", subscribers.size(), channel); } AsyncFoldLeft.run(subscribers, true, (result, subscriber, loop) -> { if (!wildSubscribers.contains(subscriber.getId())) { if (subscriber == session && !channel.isBroadcastToPublisher()) { loop.proceed(true); } else { //<9>放入消息队列 ((ServerSessionImpl)subscriber).deliver1(session, message, Promise.from(y -> loop.proceed(true), loop::fail)); } } else { loop.proceed(true); } }, promise); }, promise::fail) ); }
<9>
org.cometd.server.ServerSessionImpl#deliver1
protected void deliver1(ServerSession sender, ServerMessage.Mutable mutable, Promise<Boolean> promise) { if (sender == this && !isBroadcastToPublisher() && ChannelId.isBroadcast(mutable.getChannel())) { promise.succeed(false); } else { //触发session的获取消息前的生命周期 extendOutgoing(sender, mutable, Promise.from(message -> { if (message == null) { promise.succeed(false); } else { _bayeux.freeze(message); //获得session listener AsyncFoldLeft.run(_listeners, true, (result, listener, loop) -> { if (listener instanceof MessageListener) { //触发消息监听器 notifyOnMessage((MessageListener)listener, sender, message, _bayeux.resolveLoop(loop)); } else { loop.proceed(result); } }, Promise.from(b -> { if (b) { //<11>监听器触发成功加入消息到队列 deliver2(sender, message, promise); } else { promise.succeed(false); } }, promise::fail)); } }, promise::fail)); } }
<11>
org.cometd.server.ServerSessionImpl#deliver2
private void deliver2(ServerSession sender, ServerMessage.Mutable message, Promise<Boolean> promise) { //<12>将消息加入队列 Boolean wakeup = enqueueMessage(sender, message); if (wakeup == null) { promise.succeed(false); } else { if (wakeup) { //消息是否是延迟消息 开启延迟任务推送 if (message.isLazy()) { flushLazy(message); } else { //<13>直接推送 flush(); } } promise.succeed(true); } }
<12>
org.cometd.server.ServerSessionImpl#enqueueMessage
private Boolean enqueueMessage(ServerSession sender, ServerMessage.Mutable message) { synchronized (getLock()) { for (ServerSessionListener listener : _listeners) { if (listener instanceof QueueMaxedListener) { int maxQueueSize = _maxQueue; //当消息达到达到queueSize 通知消息回调 可以持久化到redis或者mysql if (maxQueueSize > 0 && _queue.size() >= maxQueueSize) { if (!notifyQueueMaxed((QueueMaxedListener)listener, this, _queue, sender, message)) { return null; } } } } //将消息加入queue 最终消费者回调消费则成功方法会触发从queue里面获取推送 addMessage(message); //触发已加入消息监听器 for (ServerSessionListener listener : _listeners) { if (listener instanceof QueueListener) { notifyQueued((QueueListener)listener, sender, message); } } return _batch == 0; } }
<13>
org.cometd.server.ServerSessionImpl#flush
public void flush() { Scheduler scheduler; synchronized (getLock()) { _lazyTask.cancel(); scheduler = _scheduler; } if (_localSession == null) { // <14>消息推送的地方org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler scheduler.schedule(); } else { // Local delivery. if (hasNonLazyMessages()) { for (ServerMessage msg : takeQueue(Collections.emptyList())) { _localSession.receive(new HashMapMessage(msg), Promise.noop()); } } } }
<14>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler#schedule
@Override public void schedule() { ServerSessionImpl session = context.session; boolean metaConnectDelivery = isMetaConnectDeliveryOnly(session); // When delivering only via /meta/connect, we want to behave similarly to HTTP. // Otherwise, the scheduler is not "disabled" by cancelling the // timeout, and it will continue to deliver messages to the client. if (metaConnectDelivery || session.isTerminated()) { //当前session未超时 表示在线 if (cancelTimeout(false)) { if (_logger.isDebugEnabled()) { _logger.debug("Resuming suspended {} for {} on {}", message, session, AbstractWebSocketEndPoint.this); } //触发ServerSession.HeartBeatListener session.notifyResumed(message, false); //<15>发送消息 注意这个this resume(context, message, this); } } else { // Avoid sending messages if this scheduler has been disabled, so that the // messages remain in the session queue until the next scheduler is set. if (taskRef.isMarked()) { Context ctx = new Context(session); ctx.sendQueue = true; ctx.metaConnectCycle = context.metaConnectCycle; flush(ctx); } } }
<15>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#resume
private void resume(Context context, ServerMessage.Mutable message, Promise<Void> promise) { ServerMessage.Mutable reply = message.getAssociated(); ServerSessionImpl session = context.session; if (session != null) { Map<String, Object> advice = session.takeAdvice(_transport); if (advice != null) { reply.put(Message.ADVICE_FIELD, advice); } if (session.isDisconnected()) { reply.getAdvice(true).put(Message.RECONNECT_FIELD, Message.RECONNECT_NONE_VALUE); } } _transport.processReply(session, reply, Promise.from(r -> { if (r != null) { context.replies.add(r); } context.sendQueue = true; context.scheduleExpiration = true; //<16>这里的回调是this 最终会调用 org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler.succeed方法 promise.succeed(null); }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle, promise, x))); }
<16>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler#succeed
public void succeed(Void result) { //<17> executeFlush(context, Promise.from(y -> {}, this::fail)); }
<17>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler#executeFlush
private void executeFlush(Context context, Promise<Void> promise) { //<18>线程池异步触发当前ssesion拉取消息 _transport.getBayeux().execute(() -> AbstractWebSocketEndPoint.this.flush(context, promise)); }
<18>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#flush
protected void flush(Context context, Promise<Void> promise) { List<ServerMessage> msgs = Collections.emptyList(); ServerSessionImpl session = context.session; if (context.sendQueue && session != null) { //拉取消息 msgs = session.takeQueue(context.replies); } if (_logger.isDebugEnabled()) { _logger.debug("Flushing {}, replies={}, messages={} on {}", session, context.replies, msgs, this); } List<ServerMessage> messages = msgs; //将消息封装成entry加入推送队列 boolean queued = flusher.queue(new Entry(context, messages, Promise.from(y -> { promise.succeed(null); writeComplete(context, messages); }, promise::fail))); if (queued) { //<19>触发消息消费 flusher.iterate(); } }
<19>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.Flusher#process
@Override protected Action process() { while (true) { //类型 switch (_state) { case IDLE: { synchronized (this) { _entry = _entries.poll(); } if (_logger.isDebugEnabled()) { _logger.debug("Processing {} on {}", _entry, AbstractWebSocketEndPoint.this); } if (_entry == null) { return Action.IDLE; } _state = State.HANDSHAKE; _buffer = new StringBuilder(256); break; } case HANDSHAKE: { _state = State.MESSAGES; List<ServerMessage.Mutable> replies = _entry._context.replies; if (!replies.isEmpty()) { ServerMessage.Mutable reply = replies.get(0); if (Channel.META_HANDSHAKE.equals(reply.getChannel())) { if (_logger.isDebugEnabled()) { _logger.debug("Processing handshake reply {}", reply); } List<ServerMessage> queue = _entry._queue; if (_transport.allowMessageDeliveryDuringHandshake(_session) && !queue.isEmpty()) { reply.put("x-messages", queue.size()); } _transport.getBayeux().freeze(reply); _buffer.setLength(0); _buffer.append("["); _buffer.append(toJSON(reply)); _buffer.append("]"); ++_replyIndex; AbstractWebSocketEndPoint.this.send(_session, _buffer.toString(), this); return Action.SCHEDULED; } } break; } case MESSAGES: { List<ServerMessage> messages = _entry._queue; int size = messages.size(); if (_messageIndex < size) { int batchSize = _transport.getMessagesPerFrame(); batchSize = batchSize > 0 ? Math.min(batchSize, size) : size; if (_logger.isDebugEnabled()) { _logger.debug("Processing messages, batch size {}: {}", batchSize, messages); } _buffer.setLength(0); _buffer.append("["); boolean comma = false; int endIndex = Math.min(size, _messageIndex + batchSize); while (_messageIndex < endIndex) { ServerMessage message = messages.get(_messageIndex); if (comma) { _buffer.append(","); } comma = true; _buffer.append(toJSON(message)); ++_messageIndex; } _buffer.append("]"); //<20>发送消息 AbstractWebSocketEndPoint.this.send(_session, _buffer.toString(), this); return Action.SCHEDULED; } // Start the interval timeout after writing the // messages since they may take time to be written. _entry.scheduleExpiration(); _state = State.REPLIES; break; } case REPLIES: { List<ServerMessage.Mutable> replies = _entry._context.replies; int size = replies.size(); if (_replyIndex < size) { if (_logger.isDebugEnabled()) { _logger.debug("Processing replies {}", replies); } _buffer.setLength(0); _buffer.append("["); boolean comma = false; while (_replyIndex < size) { ServerMessage.Mutable reply = replies.get(_replyIndex); _transport.getBayeux().freeze(reply); if (comma) { _buffer.append(","); } comma = true; _buffer.append(toJSON(reply)); ++_replyIndex; } _buffer.append("]"); AbstractWebSocketEndPoint.this.send(_session, _buffer.toString(), this); return Action.SCHEDULED; } _state = State.COMPLETE; break; } case COMPLETE: { Entry entry = _entry; _state = State.IDLE; // Do not keep the buffer around while we are idle. _buffer = null; _entry = null; _messageIndex = 0; _replyIndex = 0; entry._promise.succeed(null); break; } default: { throw new IllegalStateException("Invalid state " + _state); } } } }
<20>
org.cometd.server.websocket.javax.WebSocketEndPoint.Delegate#send
@Override protected void send(ServerSession session, String data, Callback callback) { if (_logger.isDebugEnabled()) { _logger.debug("Sending {} on {}", data, this); } // Async write. 这个session是websocket的session 触发推送 _wsSession.getAsyncRemote().sendText(data, result -> { Throwable failure = result.getException(); if (failure == null) { callback.succeeded(); } else { callback.failed(failure); } }); }