Browse Source
feat: 支持beforePublishHook, afterPublishHook回调. feat: publishWithReply提供CompletableFuture支持.pull/42/head
11 changed files with 475 additions and 7 deletions
@ -0,0 +1,79 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.common; |
||||||
|
|
||||||
|
import com.dji.sdk.mqtt.Chan; |
||||||
|
import com.dji.sdk.mqtt.CommonTopicRequest; |
||||||
|
import com.dji.sdk.mqtt.CommonTopicResponse; |
||||||
|
|
||||||
|
import java.util.Objects; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
public class JDKLockBarrierImpl implements PublishBarrier{ |
||||||
|
|
||||||
|
/** |
||||||
|
* 在我的实现中是采用一个定期清理的TimedCache储存请求 |
||||||
|
*/ |
||||||
|
private final ConcurrentHashMap<String, JDKHolder> container = new ConcurrentHashMap<>(); |
||||||
|
|
||||||
|
@Override |
||||||
|
public void put(String identity, CommonTopicResponse receiveData) { |
||||||
|
if(hasIdentity(identity)){ |
||||||
|
container.get(identity).setData(receiveData); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void registerRequest(String identity, CommonTopicRequest requestData) { |
||||||
|
container.put(identity,new JDKHolder()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public PublishBarrierResult await(String identity, long timeout) { |
||||||
|
JDKHolder jdkHolder = container.get(identity); |
||||||
|
if(Objects.isNull(jdkHolder)){ |
||||||
|
throw new RuntimeException("等待指令返回前未注册指令到栅栏"); |
||||||
|
} |
||||||
|
jdkHolder.await(timeout); |
||||||
|
|
||||||
|
return jdkHolder.getResult(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasIdentity(String identity) { |
||||||
|
return container.containsKey(identity); |
||||||
|
} |
||||||
|
|
||||||
|
public static class JDKHolder{ |
||||||
|
volatile Object locker = new Object(); |
||||||
|
CommonTopicResponse response = null; |
||||||
|
|
||||||
|
public void await(long timeout) { |
||||||
|
synchronized (locker){ |
||||||
|
try { |
||||||
|
locker.wait(timeout); |
||||||
|
}catch (InterruptedException e){} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void setData(CommonTopicResponse receiveData) { |
||||||
|
this.response = receiveData; |
||||||
|
synchronized (locker){ |
||||||
|
locker.notify(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public PublishBarrierResult getResult() { |
||||||
|
if(Objects.nonNull(response)){ |
||||||
|
return PublishBarrierResult.ok(response); |
||||||
|
}else{ |
||||||
|
return PublishBarrierResult.EMPTY; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.common; |
||||||
|
|
||||||
|
import com.dji.sdk.mqtt.CommonTopicRequest; |
||||||
|
import com.dji.sdk.mqtt.CommonTopicResponse; |
||||||
|
|
||||||
|
public interface PublishBarrier { |
||||||
|
|
||||||
|
void put(String identity, CommonTopicResponse receiveData); |
||||||
|
|
||||||
|
void registerRequest(String identity, CommonTopicRequest requestData); |
||||||
|
|
||||||
|
PublishBarrierResult await(String identity,long timeout); |
||||||
|
|
||||||
|
boolean hasIdentity(String identity); |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.common; |
||||||
|
|
||||||
|
import com.dji.sdk.mqtt.CommonTopicResponse; |
||||||
|
|
||||||
|
public class PublishBarrierResult { |
||||||
|
|
||||||
|
public static PublishBarrierResult EMPTY = new PublishBarrierResult(); |
||||||
|
|
||||||
|
public static PublishBarrierResult ok(CommonTopicResponse data){ |
||||||
|
return new PublishBarrierResult().setData(data); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
boolean timeout = true; |
||||||
|
|
||||||
|
CommonTopicResponse data; |
||||||
|
|
||||||
|
private PublishBarrierResult() { |
||||||
|
} |
||||||
|
|
||||||
|
private PublishBarrierResult setData(CommonTopicResponse data) { |
||||||
|
this.data = data; |
||||||
|
this.timeout = false; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isTimeout(){ |
||||||
|
return timeout; |
||||||
|
} |
||||||
|
|
||||||
|
public <T> CommonTopicResponse<T> getData(){ |
||||||
|
return data; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.common; |
||||||
|
|
||||||
|
import com.dji.sdk.mqtt.CommonTopicRequest; |
||||||
|
|
||||||
|
import java.util.Objects; |
||||||
|
import java.util.function.BiConsumer; |
||||||
|
import java.util.function.Consumer; |
||||||
|
|
||||||
|
public class PublishConfiguration { |
||||||
|
|
||||||
|
String bid; |
||||||
|
String tid; |
||||||
|
|
||||||
|
//默认超时
|
||||||
|
int timeout = 3; |
||||||
|
//请求发送前调用
|
||||||
|
Consumer<CommonTopicRequest> beforePublishHook = (e)->{}; |
||||||
|
//收到请求回信后调用
|
||||||
|
BiConsumer<CommonTopicRequest, PublishBarrierResult> afterPublishHook = (req,rsp) ->{}; |
||||||
|
|
||||||
|
|
||||||
|
public String getBid() { |
||||||
|
return bid; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTid() { |
||||||
|
return tid; |
||||||
|
} |
||||||
|
|
||||||
|
public long getTimeout() { |
||||||
|
return timeout * 1000; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBizId(String bid) { |
||||||
|
this.bid = bid; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTransactionId(String tid) { |
||||||
|
this.tid = tid; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTimeout(int timeout) { |
||||||
|
this.timeout = timeout; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBeforePublishHook(Consumer<CommonTopicRequest> callback) { |
||||||
|
beforePublishHook = callback; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAfterPublishReplyHook(BiConsumer<CommonTopicRequest, PublishBarrierResult> callback) { |
||||||
|
afterPublishHook = callback; |
||||||
|
} |
||||||
|
|
||||||
|
public void invokeBeforePublishHook(CommonTopicRequest req){ |
||||||
|
if(Objects.nonNull(beforePublishHook)){ |
||||||
|
try { |
||||||
|
beforePublishHook.accept(req); |
||||||
|
}catch (Throwable ex){ |
||||||
|
//do nothing
|
||||||
|
//业务层的异常不理会
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void invokeAfterPublishReplyHook(CommonTopicRequest req, PublishBarrierResult result){ |
||||||
|
if(Objects.nonNull(afterPublishHook)){ |
||||||
|
try{ |
||||||
|
afterPublishHook.accept(req,result); |
||||||
|
}catch (Throwable ex){ |
||||||
|
//do nothing
|
||||||
|
//业务层的异常不理会
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.common; |
||||||
|
|
||||||
|
import com.dji.sdk.mqtt.CommonTopicRequest; |
||||||
|
import com.dji.sdk.mqtt.CommonTopicResponse; |
||||||
|
import com.google.common.base.Strings; |
||||||
|
|
||||||
|
import java.util.Objects; |
||||||
|
import java.util.function.BiConsumer; |
||||||
|
import java.util.function.Consumer; |
||||||
|
|
||||||
|
public class PublishOption { |
||||||
|
|
||||||
|
public static Consumer<PublishOption> DEFAULT = (cfg)->{}; |
||||||
|
|
||||||
|
final PublishConfiguration configuration; |
||||||
|
|
||||||
|
public PublishOption(PublishConfiguration configuration) { |
||||||
|
this.configuration = configuration; |
||||||
|
} |
||||||
|
|
||||||
|
public PublishOption withBizId(String bid){ |
||||||
|
if(!Strings.isNullOrEmpty(bid)){ |
||||||
|
configuration.setBizId(bid); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public PublishOption withTransactionId(String tid){ |
||||||
|
if(!Strings.isNullOrEmpty(tid)){ |
||||||
|
configuration.setTransactionId(tid); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public PublishOption timeout(int second){ |
||||||
|
configuration.setTimeout(second); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public PublishOption beforePublish(Consumer<CommonTopicRequest> callback){ |
||||||
|
if(Objects.nonNull(callback)){ |
||||||
|
configuration.setBeforePublishHook(callback); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
public PublishOption afterPublishReply(BiConsumer<CommonTopicRequest, PublishBarrierResult> callback){ |
||||||
|
if(Objects.nonNull(callback)){ |
||||||
|
configuration.setAfterPublishReplyHook(callback); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.config; |
||||||
|
|
||||||
|
import com.dji.sdk.common.JDKLockBarrierImpl; |
||||||
|
import com.dji.sdk.common.PublishBarrier; |
||||||
|
import com.dji.sdk.mqtt.ChanBarrierAdapter; |
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
@Configuration |
||||||
|
public class DefaultBeanConfiguration { |
||||||
|
|
||||||
|
/** |
||||||
|
* 使用者可以自定义PublishBarrier的实现,默认采用Chan实现 |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
@ConditionalOnMissingBean(PublishBarrier.class) |
||||||
|
public PublishBarrier chanBarrier(){ |
||||||
|
/** 原Chan实现 */ |
||||||
|
return new ChanBarrierAdapter(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* PublishBarrier 另一个实现, 采用同步锁 |
||||||
|
*/ |
||||||
|
// @Bean
|
||||||
|
// @ConditionalOnMissingBean(PublishBarrier.class)
|
||||||
|
// public PublishBarrier jdkBarrier(){
|
||||||
|
// return new JDKLockBarrierImpl();
|
||||||
|
// }
|
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
/************************************************* |
||||||
|
* @copyright 2017 Flision Corporation Inc. |
||||||
|
* @author: Vincent Chan @ Canton |
||||||
|
* @date: 2023年09月22日 |
||||||
|
* @version: 1.0.0 |
||||||
|
* @description: |
||||||
|
**************************************************/ |
||||||
|
package com.dji.sdk.mqtt; |
||||||
|
|
||||||
|
import com.dji.sdk.common.PublishBarrier; |
||||||
|
import com.dji.sdk.common.PublishBarrierResult; |
||||||
|
|
||||||
|
import java.util.Objects; |
||||||
|
|
||||||
|
public class ChanBarrierAdapter implements PublishBarrier { |
||||||
|
@Override |
||||||
|
public void put(String identity, CommonTopicResponse receiveData) { |
||||||
|
Chan instance = Chan.getInstance(identity, false); |
||||||
|
if(Objects.nonNull(instance)){ |
||||||
|
instance.put(receiveData); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void registerRequest(String identity, CommonTopicRequest requestData) { |
||||||
|
Chan.getInstance(identity, true); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public PublishBarrierResult await(String identity,long timeout) { |
||||||
|
Chan instance = Chan.getInstance(identity, false); |
||||||
|
|
||||||
|
CommonTopicResponse response = instance.get(identity, timeout); |
||||||
|
|
||||||
|
return Objects.nonNull(response) ? PublishBarrierResult.ok(response) : PublishBarrierResult.EMPTY; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasIdentity(String identity) { |
||||||
|
Chan instance = Chan.getInstance(identity, false); |
||||||
|
return Objects.nonNull(instance); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue