mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-09-09 10:19:41 +02:00
Rework WebSocket code
Related to SMACK-835.
This commit is contained in:
parent
0c013e4f29
commit
c5a546554b
38 changed files with 953 additions and 498 deletions
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2009 Jive Software, 2018-2020 Florian Schmaus.
|
||||
* Copyright 2009 Jive Software, 2018-2021 Florian Schmaus.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -2201,18 +2201,29 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
return SMACK_REACTOR.schedule(runnable, delay, unit, ScheduledAction.Kind.NonBlocking);
|
||||
}
|
||||
|
||||
protected void onStreamOpen(XmlPullParser parser) {
|
||||
// We found an opening stream.
|
||||
if ("jabber:client".equals(parser.getNamespace(null))) {
|
||||
streamId = parser.getAttributeValue("", "id");
|
||||
incomingStreamXmlEnvironment = XmlEnvironment.from(parser);
|
||||
/**
|
||||
* Must be called when a XMPP stream open tag is encountered. Sets values like the stream ID and the incoming stream
|
||||
* XML environment.
|
||||
* <p>
|
||||
* This method also returns a matching stream close tag. For example if the stream open is {@code <stream …>}, then
|
||||
* {@code </stream>} is returned. But if it is {@code <stream:stream>}, then {@code </stream:stream>} is returned.
|
||||
* Or if it is {@code <foo:stream>}, then {@code </foo:stream>} is returned.
|
||||
* </p>
|
||||
*
|
||||
* @param parser an XML parser that is positioned at the start of the stream open.
|
||||
* @return a String representing the corresponding stream end tag.
|
||||
*/
|
||||
protected String onStreamOpen(XmlPullParser parser) {
|
||||
assert StreamOpen.ETHERX_JABBER_STREAMS_NAMESPACE.equals(parser.getNamespace());
|
||||
assert StreamOpen.UNPREFIXED_ELEMENT.equals(parser.getName());
|
||||
|
||||
String reportedServerDomainString = parser.getAttributeValue("", "from");
|
||||
if (reportedServerDomainString == null) {
|
||||
// RFC 6120 § 4.7.1. makes no explicit statement whether or not 'from' in the stream open from the server
|
||||
// in c2s connections is required or not.
|
||||
return;
|
||||
}
|
||||
streamId = parser.getAttributeValue("id");
|
||||
incomingStreamXmlEnvironment = XmlEnvironment.from(parser);
|
||||
|
||||
String reportedServerDomainString = parser.getAttributeValue("from");
|
||||
// RFC 6120 § 4.7.1. makes no explicit statement whether or not 'from' in the stream open from the server
|
||||
// in c2s connections is required or not.
|
||||
if (reportedServerDomainString != null) {
|
||||
DomainBareJid reportedServerDomain;
|
||||
try {
|
||||
reportedServerDomain = JidCreate.domainBareFrom(reportedServerDomainString);
|
||||
|
@ -2226,6 +2237,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
+ "' as reported by server could not be transformed to a valid JID", e);
|
||||
}
|
||||
}
|
||||
|
||||
String prefix = parser.getPrefix();
|
||||
if (StringUtils.isNotEmpty(prefix)) {
|
||||
return "</" + prefix + ":stream>";
|
||||
}
|
||||
return "</stream>";
|
||||
}
|
||||
|
||||
protected final void sendStreamOpen() throws NotConnectedException, InterruptedException {
|
||||
|
@ -2233,7 +2250,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
// possible. The 'to' attribute is *always* available. The 'from' attribute if set by the user and no external
|
||||
// mechanism is used to determine the local entity (user). And the 'id' attribute is available after the first
|
||||
// response from the server (see e.g. RFC 6120 § 9.1.1 Step 2.)
|
||||
CharSequence to = getXMPPServiceDomain();
|
||||
DomainBareJid to = getXMPPServiceDomain();
|
||||
CharSequence from = null;
|
||||
CharSequence localpart = config.getUsername();
|
||||
if (localpart != null) {
|
||||
|
@ -2247,7 +2264,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
updateOutgoingStreamXmlEnvironmentOnStreamOpen(streamOpen);
|
||||
}
|
||||
|
||||
protected AbstractStreamOpen getStreamOpen(CharSequence to, CharSequence from, String id, String lang) {
|
||||
protected AbstractStreamOpen getStreamOpen(DomainBareJid to, CharSequence from, String id, String lang) {
|
||||
return new StreamOpen(to, from, id, lang);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017-2020 Florian Schmaus
|
||||
* Copyright 2017-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -75,6 +75,10 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
|
||||
@Override
|
||||
public final synchronized boolean isDone() {
|
||||
return result != null || exception != null || cancelled;
|
||||
}
|
||||
|
||||
public final synchronized boolean wasSuccessful() {
|
||||
return result != null;
|
||||
}
|
||||
|
||||
|
@ -162,6 +166,10 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
return result;
|
||||
}
|
||||
|
||||
public E getExceptionIfAvailable() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
protected final synchronized void maybeInvokeCallbacks() {
|
||||
if (cancelled) {
|
||||
return;
|
||||
|
@ -326,6 +334,11 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
return future;
|
||||
}
|
||||
|
||||
public static boolean await(Collection<? extends SmackFuture<?, ?>> futures, long timeout)
|
||||
throws InterruptedException {
|
||||
return await(futures, timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public static boolean await(Collection<? extends SmackFuture<?, ?>> futures, long timeout, TimeUnit unit) throws InterruptedException {
|
||||
CountDownLatch latch = new CountDownLatch(futures.size());
|
||||
for (SmackFuture<?, ?> future : futures) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -139,13 +139,8 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentConnectionExceptionAndNotify(Exception exception) {
|
||||
ModularXmppClientToServerConnection.this.setCurrentConnectionExceptionAndNotify(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamOpen(XmlPullParser parser) {
|
||||
ModularXmppClientToServerConnection.this.onStreamOpen(parser);
|
||||
public String onStreamOpen(XmlPullParser parser) {
|
||||
return ModularXmppClientToServerConnection.this.onStreamOpen(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -571,7 +566,7 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
|
|||
}
|
||||
|
||||
@Override
|
||||
protected AbstractStreamOpen getStreamOpen(CharSequence to, CharSequence from, String id, String lang) {
|
||||
protected AbstractStreamOpen getStreamOpen(DomainBareJid to, CharSequence from, String id, String lang) {
|
||||
StreamOpenAndCloseFactory streamOpenAndCloseFactory = activeTransport.getStreamOpenAndCloseFactory();
|
||||
return streamOpenAndCloseFactory.createStreamOpen(to, from, id, lang);
|
||||
}
|
||||
|
@ -720,6 +715,11 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
|
|||
throw SmackException.NoEndpointsDiscoveredException.from(lookupFailures);
|
||||
}
|
||||
|
||||
if (!lookupFailures.isEmpty()) {
|
||||
// TODO: Put those non-fatal lookup failures into a sink of the connection so that the user is able to
|
||||
// be aware of them.
|
||||
}
|
||||
|
||||
// Even though the outgoing elements queue is unrelated to the lookup remote connection endpoints state, we
|
||||
// do start the queue at this point. The transports will need it available, and we use the state's reset()
|
||||
// function to close the queue again on failure.
|
||||
|
@ -1110,7 +1110,12 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
|
|||
XmppClientToServerTransport.Stats stats = entry.getValue();
|
||||
|
||||
StringUtils.appendHeading(appendable, transportClass.getName());
|
||||
appendable.append(stats.toString()).append('\n');
|
||||
if (stats != null) {
|
||||
appendable.append(stats.toString());
|
||||
} else {
|
||||
appendable.append("No stats available.");
|
||||
}
|
||||
appendable.append('\n');
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Object> entry : filtersStats.entrySet()) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 Florian Schmaus
|
||||
* Copyright 2019-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -62,6 +62,10 @@ public final class ModularXmppClientToServerConnectionConfiguration extends Conn
|
|||
// configuration, e.g. there is no edge from disconnected to connected.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
for (ModularXmppClientToServerConnectionModuleDescriptor moduleDescriptor : moduleDescriptors) {
|
||||
moduleDescriptor.validateConfiguration(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void printStateGraphInDotFormat(PrintWriter pw, boolean breakStateName) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 Florian Schmaus
|
||||
* Copyright 2019-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,6 +28,9 @@ public abstract class ModularXmppClientToServerConnectionModuleDescriptor {
|
|||
protected abstract ModularXmppClientToServerConnectionModule<? extends ModularXmppClientToServerConnectionModuleDescriptor> constructXmppConnectionModule(
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal);
|
||||
|
||||
protected void validateConfiguration(ModularXmppClientToServerConnectionConfiguration configuration) {
|
||||
}
|
||||
|
||||
public abstract static class Builder {
|
||||
private final ModularXmppClientToServerConnectionConfiguration.Builder connectionConfigurationBuilder;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 Aditya Borikar.
|
||||
* Copyright 2020 Aditya Borikar, 2021 Florian Schmaus.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,8 +19,12 @@ package org.jivesoftware.smack.c2s;
|
|||
import org.jivesoftware.smack.packet.AbstractStreamClose;
|
||||
import org.jivesoftware.smack.packet.AbstractStreamOpen;
|
||||
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||
|
||||
public interface StreamOpenAndCloseFactory {
|
||||
AbstractStreamOpen createStreamOpen(CharSequence to, CharSequence from, String id, String lang);
|
||||
|
||||
AbstractStreamOpen createStreamOpen(DomainBareJid to, CharSequence from, String id, String lang);
|
||||
|
||||
AbstractStreamClose createStreamClose();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 Florian Schmaus
|
||||
* Copyright 2019-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -37,6 +37,8 @@ public abstract class XmppClientToServerTransport {
|
|||
|
||||
protected abstract void loadConnectionEndpoints(LookupConnectionEndpointsSuccess lookupConnectionEndpointsSuccess);
|
||||
|
||||
public abstract boolean hasUseableConnectionEndpoints();
|
||||
|
||||
/**
|
||||
* Notify the transport that new outgoing data is available. Usually this method does not need to be called
|
||||
* explicitly, only if the filters are modified so that they potentially produced new data.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 Florian Schmaus
|
||||
* Copyright 2020-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.jivesoftware.smack.c2s.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
|
@ -39,8 +40,10 @@ import org.jivesoftware.smack.packet.Nonza;
|
|||
import org.jivesoftware.smack.packet.TopLevelStreamElement;
|
||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
import org.jivesoftware.smack.util.Supplier;
|
||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||
|
||||
public abstract class ModularXmppClientToServerConnectionInternal {
|
||||
|
||||
|
@ -85,9 +88,19 @@ public abstract class ModularXmppClientToServerConnectionInternal {
|
|||
|
||||
public abstract void notifyConnectionError(Exception e);
|
||||
|
||||
public abstract void setCurrentConnectionExceptionAndNotify(Exception exception);
|
||||
public final String onStreamOpen(String streamOpen) {
|
||||
XmlPullParser streamOpenParser;
|
||||
try {
|
||||
streamOpenParser = PacketParserUtils.getParserFor(streamOpen);
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
// Should never happen.
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
String streamClose = onStreamOpen(streamOpenParser);
|
||||
return streamClose;
|
||||
}
|
||||
|
||||
public abstract void onStreamOpen(XmlPullParser parser);
|
||||
public abstract String onStreamOpen(XmlPullParser parser);
|
||||
|
||||
public abstract void onStreamClosed();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
|||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.c2s.XmppClientToServerTransport;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
|
||||
|
@ -75,4 +76,24 @@ public abstract class State {
|
|||
}
|
||||
}
|
||||
|
||||
public abstract static class AbstractTransport extends State {
|
||||
|
||||
private final XmppClientToServerTransport transport;
|
||||
|
||||
protected AbstractTransport(XmppClientToServerTransport transport, StateDescriptor stateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(stateDescriptor, connectionInternal);
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.TransitionImpossible isTransitionToPossible(WalkStateGraphContext walkStateGraphContext)
|
||||
throws SmackException {
|
||||
if (!transport.hasUseableConnectionEndpoints()) {
|
||||
return new StateTransitionResult.TransitionImpossibleBecauseNoEndpointsDiscovered(transport);
|
||||
}
|
||||
|
||||
return super.isTransitionToPossible(walkStateGraphContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.jivesoftware.smack.fsm;
|
||||
|
||||
import org.jivesoftware.smack.c2s.XmppClientToServerTransport;
|
||||
|
||||
public abstract class StateTransitionResult {
|
||||
|
||||
private final String message;
|
||||
|
@ -92,4 +94,10 @@ public abstract class StateTransitionResult {
|
|||
super(stateDescriptor.getFullStateName(false) + " is not implemented (yet)");
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransitionImpossibleBecauseNoEndpointsDiscovered extends TransitionImpossibleReason {
|
||||
public TransitionImpossibleBecauseNoEndpointsDiscovered(XmppClientToServerTransport transport) {
|
||||
super("The transport " + transport + " did not discover any endpoints");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 Florian Schmaus, Aditya Borikar
|
||||
* Copyright 2020-2021 Florian Schmaus, 2020 Aditya Borikar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,6 +28,7 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
|||
* be achieved through {@link XMPPConnection#sendNonza(Nonza)}.
|
||||
*/
|
||||
public abstract class AbstractStreamOpen implements Nonza {
|
||||
public static final String ETHERX_JABBER_STREAMS_NAMESPACE = "http://etherx.jabber.org/streams";
|
||||
public static final String CLIENT_NAMESPACE = "jabber:client";
|
||||
public static final String SERVER_NAMESPACE = "jabber:server";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Florian Schmaus
|
||||
* Copyright 2018-2021 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,6 +20,8 @@ public final class StreamClose extends AbstractStreamClose {
|
|||
|
||||
public static final StreamClose INSTANCE = new StreamClose();
|
||||
|
||||
public static final String STRING = "</" + StreamOpen.ELEMENT + ">";
|
||||
|
||||
private StreamClose() {
|
||||
}
|
||||
|
||||
|
@ -39,4 +41,8 @@ public final class StreamClose extends AbstractStreamClose {
|
|||
return StreamOpen.ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return STRING;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
|||
* The stream open <b>tag</b>.
|
||||
*/
|
||||
public final class StreamOpen extends AbstractStreamOpen {
|
||||
public static final String ELEMENT = "stream:stream";
|
||||
public static final String UNPREFIXED_ELEMENT = "stream";
|
||||
|
||||
public static final String ELEMENT = "stream:" + UNPREFIXED_ELEMENT;
|
||||
|
||||
public StreamOpen(CharSequence to) {
|
||||
this(to, null, null, null, StreamContentNamespace.client);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue