mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-09-27 18:19:33 +02:00
130 lines
6.1 KiB
Java
130 lines
6.1 KiB
Java
/**
|
|
*
|
|
* Copyright 2018-2020 Florian Schmaus
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package org.jivesoftware.smack.compression;
|
|
|
|
import org.jivesoftware.smack.ConnectionConfiguration;
|
|
import org.jivesoftware.smack.SmackException;
|
|
import org.jivesoftware.smack.XMPPException;
|
|
import org.jivesoftware.smack.XmppInputOutputFilter;
|
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.AuthenticatedButUnboundStateDescriptor;
|
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.ResourceBindingStateDescriptor;
|
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModule;
|
|
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
|
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
|
import org.jivesoftware.smack.compress.packet.Compress;
|
|
import org.jivesoftware.smack.compress.packet.Compressed;
|
|
import org.jivesoftware.smack.compress.packet.Failure;
|
|
import org.jivesoftware.smack.fsm.State;
|
|
import org.jivesoftware.smack.fsm.StateDescriptor;
|
|
import org.jivesoftware.smack.fsm.StateTransitionResult;
|
|
|
|
public class CompressionModule extends ModularXmppClientToServerConnectionModule<CompressionModuleDescriptor> {
|
|
|
|
protected CompressionModule(CompressionModuleDescriptor moduleDescriptor,
|
|
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
|
super(moduleDescriptor, connectionInternal);
|
|
}
|
|
|
|
public static final class CompressionStateDescriptor extends StateDescriptor {
|
|
private CompressionStateDescriptor() {
|
|
super(CompressionModule.CompressionState.class, 138);
|
|
addPredeccessor(AuthenticatedButUnboundStateDescriptor.class);
|
|
addSuccessor(AuthenticatedButUnboundStateDescriptor.class);
|
|
declarePrecedenceOver(ResourceBindingStateDescriptor.class);
|
|
}
|
|
|
|
@Override
|
|
protected CompressionModule.CompressionState constructState(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
|
CompressionModule compressionModule = connectionInternal.connection.getConnectionModuleFor(CompressionModuleDescriptor.class);
|
|
return compressionModule.constructCompressionState(this, connectionInternal);
|
|
}
|
|
}
|
|
|
|
private static final class CompressionState extends State {
|
|
private XmppCompressionFactory selectedCompressionFactory;
|
|
private XmppInputOutputFilter usedXmppInputOutputCompressionFitler;
|
|
|
|
private CompressionState(StateDescriptor stateDescriptor, ModularXmppClientToServerConnectionInternal connectionInternal) {
|
|
super(stateDescriptor, connectionInternal);
|
|
}
|
|
|
|
@Override
|
|
public StateTransitionResult.TransitionImpossible isTransitionToPossible(
|
|
WalkStateGraphContext walkStateGraphContext) {
|
|
final ConnectionConfiguration config = connectionInternal.connection.getConfiguration();
|
|
if (!config.isCompressionEnabled()) {
|
|
return new StateTransitionResult.TransitionImpossibleReason("Stream compression disabled by connection configuration");
|
|
}
|
|
|
|
Compress.Feature compressFeature = connectionInternal.connection.getFeature(Compress.Feature.class);
|
|
if (compressFeature == null) {
|
|
return new StateTransitionResult.TransitionImpossibleReason("Stream compression not supported or enabled by service");
|
|
}
|
|
|
|
selectedCompressionFactory = XmppCompressionManager.getBestFactory(compressFeature);
|
|
if (selectedCompressionFactory == null) {
|
|
return new StateTransitionResult.TransitionImpossibleReason(
|
|
"No matching compression factory for " + compressFeature.getMethods());
|
|
}
|
|
|
|
usedXmppInputOutputCompressionFitler = selectedCompressionFactory.fabricate(config);
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public StateTransitionResult.AttemptResult transitionInto(WalkStateGraphContext walkStateGraphContext)
|
|
throws InterruptedException, SmackException, XMPPException {
|
|
final String compressionMethod = selectedCompressionFactory.getCompressionMethod();
|
|
connectionInternal.sendAndWaitForResponse(new Compress(compressionMethod), Compressed.class, Failure.class);
|
|
|
|
connectionInternal.addXmppInputOutputFilter(usedXmppInputOutputCompressionFitler);
|
|
|
|
connectionInternal.newStreamOpenWaitForFeaturesSequence("server stream features after compression enabled");
|
|
|
|
connectionInternal.setCompressionEnabled(true);
|
|
|
|
return new CompressionTransitionSuccessResult(compressionMethod);
|
|
}
|
|
|
|
@Override
|
|
public void resetState() {
|
|
selectedCompressionFactory = null;
|
|
usedXmppInputOutputCompressionFitler = null;
|
|
connectionInternal.setCompressionEnabled(false);
|
|
}
|
|
}
|
|
|
|
public static final class CompressionTransitionSuccessResult extends StateTransitionResult.Success {
|
|
private final String compressionMethod;
|
|
|
|
private CompressionTransitionSuccessResult(String compressionMethod) {
|
|
super(compressionMethod + " compression enabled");
|
|
this.compressionMethod = compressionMethod;
|
|
}
|
|
|
|
public String getCompressionMethod() {
|
|
return compressionMethod;
|
|
}
|
|
}
|
|
|
|
public CompressionState constructCompressionState(CompressionStateDescriptor compressionStateDescriptor,
|
|
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
|
return new CompressionState(compressionStateDescriptor, connectionInternal);
|
|
}
|
|
}
|