All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.ipokerface.aps.PushClient Maven / Gradle / Ivy

The newest version!
package cn.ipokerface.aps;

import cn.ipokerface.aps.auth.ApnsSignKey;
import cn.ipokerface.aps.channel.ChannelFactory;
import cn.ipokerface.aps.channel.ChannelPool;
import cn.ipokerface.aps.notification.Notification;
import cn.ipokerface.aps.notification.NotificationFuture;
import cn.ipokerface.aps.response.NotificationResponse;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.codec.http2.Http2FrameLogger;
import io.netty.handler.ssl.SslContext;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by       PokerFace
 * Create Date      2020-08-23.
 * Email:           [email protected]
 * Version          1.0.0
 * 

* Description: */ public class PushClient { private Logger logger = LoggerFactory.getLogger(PushClient.class); private final AtomicBoolean closed = new AtomicBoolean(false); private EventLoopGroup eventLoopGroup; private ChannelPool channelPool; private PushClientMetricsListener listener; /** * constructor... * * @param env * @param topic * @param sslContext * @param signKey * @param connectionTimeout * @param idleInterval * @param listener * @param frameLogger */ protected PushClient(Environment env, String topic, SslContext sslContext, ApnsSignKey signKey, Duration tokenExpiration, Duration connectionTimeout, Duration idleInterval, PushClientMetricsListener listener, Http2FrameLogger frameLogger, int poolCapacity ) { if (env == null) throw new IllegalArgumentException("Envrionment is not set."); if (StringUtils.isEmpty(topic)) throw new IllegalArgumentException("Default topic is not set..."); this.eventLoopGroup = new NioEventLoopGroup(1); this.listener = listener != null ? listener : new PushClientMetricsListener.ClientMetricsListenerAdapter(); ChannelFactory channelFactory = new ChannelFactory(InetSocketAddress.createUnresolved(env.getHost(), env.getPort()), this.eventLoopGroup, sslContext,signKey,tokenExpiration, connectionTimeout,idleInterval,frameLogger, topic); this.channelPool = new ChannelPool(this, channelFactory, poolCapacity, this.eventLoopGroup.next(), this.listener); } /** *

Sends a push notification to the APNs gateway.

* *

This method returns a {@code Future} that indicates whether the notification was accepted or rejected by the * gateway. If the notification was accepted, it may be delivered to its destination device at some time in the * future, but final delivery is not guaranteed. Rejections should be considered permanent failures, and callers * should not attempt to re-send the notification.

* *

The returned {@code Future} may fail with an exception if the notification could not be sent. Failures to * send a notification to the gateway—i.e. those that fail with exceptions—should generally be considered * non-permanent, and callers should attempt to re-send the notification when the underlying problem has been * resolved.

* * @param notification the notification to send to the APNs gateway * * @param the type of notification to be sent * * @return a {@code Future} that will complete when the notification has been either accepted or rejected by the * APNs gateway * * @since 0.8 */ public NotificationFuture> sendNotification(final T notification) { final NotificationFuture> responseFuture = new NotificationFuture<>(notification); if (!this.closed.get()) { this.channelPool.acquire().addListener((GenericFutureListener>) acquireFuture -> { if (acquireFuture.isSuccess()) { final Channel channel = acquireFuture.getNow(); channel.writeAndFlush(responseFuture).addListener((GenericFutureListener) future -> { if (future.isSuccess()) { listener.handleNotificationSend(PushClient.this, notification.getApnsId()); } }); channelPool.release(channel); } else { responseFuture.completeExceptionally(acquireFuture.cause()); } }); responseFuture.whenComplete((response, cause) -> { if (response != null) { if (response.isSuccess()) { listener.handleNotificationAccepted(PushClient.this, notification.getApnsId()); } else { listener.handleNotificationRejected(PushClient.this, notification.getApnsId()); } } else { listener.handleWriteFailure(PushClient.this, notification.getApnsId()); } }); } else { responseFuture.completeExceptionally(new IllegalStateException("Client has been closed and can no longer send push notifications.")); } return responseFuture; } /** *

Gracefully shuts down the client, closing all connections and releasing all persistent resources. The * disconnection process will wait until notifications that have been sent to the APNs server have been either * accepted or rejected. Note that some notifications passed to * {@link PushClient#sendNotification(Notification)} may still be enqueued and not yet sent by the time the * shutdown process begins; the {@code Futures} associated with those notifications will fail.

* *

The returned {@code Future} will be marked as complete when all connections in this client's pool have closed * completely and (if no {@code EventLoopGroup} was provided at construction time) the client's event loop group has * shut down. If the client has already shut down, the returned {@code Future} will be marked as complete * immediately.

* *

Clients may not be reused once they have been closed.

* * @return a {@code Future} that will be marked as complete when the client has finished shutting down * * @since 0.11 */ public CompletableFuture close() { logger.info("Shutting down."); final CompletableFuture closeFuture; if (this.closed.compareAndSet(false, true)) { closeFuture = new CompletableFuture<>(); this.channelPool.close().addListener((GenericFutureListener>) closePoolFuture -> { eventLoopGroup.shutdownGracefully().addListener(future -> closeFuture.complete(null)); }); } else { closeFuture = CompletableFuture.completedFuture(null); } return closeFuture; } /** * 环境 */ public enum Environment { Sandbox ("api.sandbox.push.apple.com", 443, true), Production ("api.push.apple.com", 443, true) ; private String host; private int port; private boolean ssl; private Environment(String url, int port,boolean ssl) { this.host = url; this.port = port; this.ssl = ssl; } public String getHost() { return host; } public int getPort() { return port; } public boolean isSsl() { return ssl; }} }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy