33 changed files with 901 additions and 1164 deletions
@ -1,156 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.actors.session; |
|||
|
|||
import akka.actor.ActorContext; |
|||
import akka.event.LoggingAdapter; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.common.msg.core.AttributesSubscribeMsg; |
|||
import org.thingsboard.server.common.msg.core.ResponseMsg; |
|||
import org.thingsboard.server.common.msg.core.RpcSubscribeMsg; |
|||
import org.thingsboard.server.common.msg.core.SessionCloseMsg; |
|||
import org.thingsboard.server.common.msg.core.SessionOpenMsg; |
|||
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|||
import org.thingsboard.server.common.msg.session.SessionType; |
|||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.session.ex.SessionException; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.Optional; |
|||
|
|||
class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
|||
|
|||
private boolean firstMsg = true; |
|||
private Map<Integer, DeviceToDeviceActorMsg> pendingMap = new HashMap<>(); |
|||
private Optional<ServerAddress> currentTargetServer; |
|||
private boolean subscribedToAttributeUpdates; |
|||
private boolean subscribedToRpcCommands; |
|||
|
|||
public ASyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
|||
super(ctx, logger, sessionId); |
|||
} |
|||
|
|||
@Override |
|||
protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { |
|||
updateSessionCtx(msg, SessionType.ASYNC); |
|||
DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg); |
|||
FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload(); |
|||
if (firstMsg) { |
|||
if (fromDeviceMsg.getMsgType() != SessionMsgType.SESSION_OPEN) { |
|||
toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); |
|||
} |
|||
firstMsg = false; |
|||
} |
|||
switch (fromDeviceMsg.getMsgType()) { |
|||
case POST_TELEMETRY_REQUEST: |
|||
case POST_ATTRIBUTES_REQUEST: |
|||
FromDeviceRequestMsg requestMsg = (FromDeviceRequestMsg) fromDeviceMsg; |
|||
if (requestMsg.getRequestId() >= 0) { |
|||
logger.debug("[{}] Pending request {} registered", requestMsg.getRequestId(), requestMsg.getMsgType()); |
|||
//TODO: handle duplicates.
|
|||
pendingMap.put(requestMsg.getRequestId(), pendingMsg); |
|||
} |
|||
break; |
|||
case SUBSCRIBE_ATTRIBUTES_REQUEST: |
|||
subscribedToAttributeUpdates = true; |
|||
break; |
|||
case UNSUBSCRIBE_ATTRIBUTES_REQUEST: |
|||
subscribedToAttributeUpdates = false; |
|||
break; |
|||
case SUBSCRIBE_RPC_COMMANDS_REQUEST: |
|||
subscribedToRpcCommands = true; |
|||
break; |
|||
case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: |
|||
subscribedToRpcCommands = false; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
currentTargetServer = forwardToAppActor(ctx, pendingMsg); |
|||
} |
|||
|
|||
@Override |
|||
public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { |
|||
try { |
|||
if (msg.getSessionMsgType() != SessionMsgType.SESSION_CLOSE) { |
|||
switch (msg.getSessionMsgType()) { |
|||
case STATUS_CODE_RESPONSE: |
|||
case GET_ATTRIBUTES_RESPONSE: |
|||
ResponseMsg responseMsg = (ResponseMsg) msg; |
|||
if (responseMsg.getRequestId() >= 0) { |
|||
logger.debug("[{}] Pending request processed: {}", responseMsg.getRequestId(), responseMsg); |
|||
pendingMap.remove(responseMsg.getRequestId()); |
|||
} |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); |
|||
} else { |
|||
sessionCtx.onMsg(org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg.onCredentialsRevoked(sessionCtx.getSessionId())); |
|||
} |
|||
} catch (SessionException e) { |
|||
logger.warning("Failed to push session response msg", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { |
|||
// TODO Auto-generated method stub
|
|||
} |
|||
|
|||
@Override |
|||
protected void cleanupSession(ActorContext ctx) { |
|||
toDeviceMsg(new SessionCloseMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); |
|||
} |
|||
|
|||
@Override |
|||
public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { |
|||
if (pendingMap.size() > 0 || subscribedToAttributeUpdates || subscribedToRpcCommands) { |
|||
Optional<ServerAddress> newTargetServer = systemContext.getRoutingService().resolveById(getDeviceId()); |
|||
if (!newTargetServer.equals(currentTargetServer)) { |
|||
firstMsg = true; |
|||
currentTargetServer = newTargetServer; |
|||
pendingMap.values().forEach(v -> { |
|||
forwardToAppActor(context, v, currentTargetServer); |
|||
if (currentTargetServer.isPresent()) { |
|||
logger.debug("[{}] Forwarded msg to new server: {}", sessionId, currentTargetServer.get()); |
|||
} else { |
|||
logger.debug("[{}] Forwarded msg to local server.", sessionId); |
|||
} |
|||
}); |
|||
if (subscribedToAttributeUpdates) { |
|||
toDeviceMsg(new AttributesSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); |
|||
logger.debug("[{}] Forwarded attributes subscription.", sessionId); |
|||
} |
|||
if (subscribedToRpcCommands) { |
|||
toDeviceMsg(new RpcSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); |
|||
logger.debug("[{}] Forwarded rpc commands subscription.", sessionId); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,122 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.actors.session; |
|||
|
|||
import akka.actor.ActorContext; |
|||
import akka.actor.ActorRef; |
|||
import akka.event.LoggingAdapter; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
|||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|||
import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.common.msg.device.BasicDeviceToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionContext; |
|||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionType; |
|||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgProcessor { |
|||
|
|||
protected final SessionId sessionId; |
|||
protected SessionContext sessionCtx; |
|||
protected DeviceToDeviceActorMsg deviceToDeviceActorMsgPrototype; |
|||
|
|||
protected AbstractSessionActorMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
|||
super(ctx, logger); |
|||
this.sessionId = sessionId; |
|||
} |
|||
|
|||
protected abstract void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg); |
|||
|
|||
protected abstract void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg); |
|||
|
|||
protected abstract void processToDeviceMsg(ActorContext context, ToDeviceMsg msg); |
|||
|
|||
public abstract void processClusterEvent(ActorContext context, ClusterEventMsg msg); |
|||
|
|||
protected void processSessionCtrlMsg(ActorContext ctx, SessionCtrlMsg msg) { |
|||
if (msg instanceof SessionCloseMsg) { |
|||
cleanupSession(ctx); |
|||
terminateSession(ctx, sessionId); |
|||
} |
|||
} |
|||
|
|||
protected void cleanupSession(ActorContext ctx) { |
|||
} |
|||
|
|||
protected void updateSessionCtx(TransportToDeviceSessionActorMsg msg, SessionType type) { |
|||
sessionCtx = msg.getSessionMsg().getSessionContext(); |
|||
deviceToDeviceActorMsgPrototype = new BasicDeviceToDeviceActorMsg(msg, type); |
|||
} |
|||
|
|||
protected DeviceToDeviceActorMsg toDeviceMsg(TransportToDeviceSessionActorMsg msg) { |
|||
AdaptorToSessionActorMsg adaptorMsg = msg.getSessionMsg(); |
|||
return new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, adaptorMsg.getMsg()); |
|||
} |
|||
|
|||
protected Optional<DeviceToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) { |
|||
if (deviceToDeviceActorMsgPrototype != null) { |
|||
return Optional.of(new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, msg)); |
|||
} else { |
|||
return Optional.empty(); |
|||
} |
|||
} |
|||
|
|||
protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward) { |
|||
Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); |
|||
forwardToAppActor(ctx, toForward, address); |
|||
return address; |
|||
} |
|||
|
|||
protected Optional<ServerAddress> forwardToAppActorIfAddressChanged(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { |
|||
|
|||
Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); |
|||
if (!newAddress.equals(oldAddress)) { |
|||
getAppActor().tell(new SendToClusterMsg(toForward.getDeviceId(), toForward |
|||
.toOtherAddress(systemContext.getRoutingService().getCurrentServer())), ctx.self()); |
|||
} |
|||
return newAddress; |
|||
} |
|||
|
|||
protected void forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> address) { |
|||
if (address.isPresent()) { |
|||
systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(address.get(), |
|||
toForward.toOtherAddress(systemContext.getRoutingService().getCurrentServer()))); |
|||
} else { |
|||
getAppActor().tell(toForward, ctx.self()); |
|||
} |
|||
} |
|||
|
|||
public static void terminateSession(ActorContext ctx, SessionId sessionId) { |
|||
ctx.parent().tell(new SessionTerminationMsg(sessionId), ActorRef.noSender()); |
|||
ctx.stop(ctx.self()); |
|||
} |
|||
|
|||
public DeviceId getDeviceId() { |
|||
return deviceToDeviceActorMsgPrototype.getDeviceId(); |
|||
} |
|||
} |
|||
@ -1,143 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.actors.session; |
|||
|
|||
import akka.actor.OneForOneStrategy; |
|||
import akka.actor.SupervisorStrategy; |
|||
import akka.event.Logging; |
|||
import akka.event.LoggingAdapter; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.service.ContextAwareActor; |
|||
import org.thingsboard.server.actors.service.ContextBasedCreator; |
|||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.msg.TbActorMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|||
import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionType; |
|||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
|||
import scala.concurrent.duration.Duration; |
|||
|
|||
public class SessionActor extends ContextAwareActor { |
|||
|
|||
private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); |
|||
|
|||
private final SessionId sessionId; |
|||
private AbstractSessionActorMsgProcessor processor; |
|||
|
|||
private SessionActor(ActorSystemContext systemContext, SessionId sessionId) { |
|||
super(systemContext); |
|||
this.sessionId = sessionId; |
|||
} |
|||
|
|||
@Override |
|||
public SupervisorStrategy supervisorStrategy() { |
|||
return new OneForOneStrategy(-1, Duration.Inf(), |
|||
throwable -> { |
|||
logger.error(throwable, "Unknown session error"); |
|||
if (throwable instanceof Error) { |
|||
return OneForOneStrategy.escalate(); |
|||
} else { |
|||
return OneForOneStrategy.resume(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
protected boolean process(TbActorMsg msg) { |
|||
switch (msg.getMsgType()) { |
|||
case TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG: |
|||
processTransportToSessionMsg((TransportToDeviceSessionActorMsg) msg); |
|||
break; |
|||
case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG: |
|||
processActorsToSessionMsg((ActorSystemToDeviceSessionActorMsg) msg); |
|||
break; |
|||
case SESSION_TIMEOUT_MSG: |
|||
processTimeoutMsg((SessionTimeoutMsg) msg); |
|||
break; |
|||
case SESSION_CTRL_MSG: |
|||
processSessionCloseMsg((SessionCtrlMsg) msg); |
|||
break; |
|||
case CLUSTER_EVENT_MSG: |
|||
processClusterEvent((ClusterEventMsg) msg); |
|||
break; |
|||
default: return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
private void processClusterEvent(ClusterEventMsg msg) { |
|||
processor.processClusterEvent(context(), msg); |
|||
} |
|||
|
|||
private void processTransportToSessionMsg(TransportToDeviceSessionActorMsg msg) { |
|||
initProcessor(msg); |
|||
processor.processToDeviceActorMsg(context(), msg); |
|||
} |
|||
|
|||
private void processActorsToSessionMsg(ActorSystemToDeviceSessionActorMsg msg) { |
|||
processor.processToDeviceMsg(context(), msg.getMsg()); |
|||
} |
|||
|
|||
private void processTimeoutMsg(SessionTimeoutMsg msg) { |
|||
if (processor != null) { |
|||
processor.processTimeoutMsg(context(), msg); |
|||
} else { |
|||
logger.warning("[{}] Can't process timeout msg: {} without processor", sessionId, msg); |
|||
} |
|||
} |
|||
|
|||
private void processSessionCloseMsg(SessionCtrlMsg msg) { |
|||
if (processor != null) { |
|||
processor.processSessionCtrlMsg(context(), msg); |
|||
} else if (msg instanceof SessionCloseMsg) { |
|||
AbstractSessionActorMsgProcessor.terminateSession(context(), sessionId); |
|||
} else { |
|||
logger.warning("[{}] Can't process session ctrl msg: {} without processor", sessionId, msg); |
|||
} |
|||
} |
|||
|
|||
private void initProcessor(TransportToDeviceSessionActorMsg msg) { |
|||
if (processor == null) { |
|||
SessionMsg sessionMsg = (SessionMsg) msg.getSessionMsg(); |
|||
if (sessionMsg.getSessionContext().getSessionType() == SessionType.SYNC) { |
|||
processor = new SyncMsgProcessor(systemContext, logger, sessionId); |
|||
} else { |
|||
processor = new ASyncMsgProcessor(systemContext, logger, sessionId); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static class ActorCreator extends ContextBasedCreator<SessionActor> { |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private final SessionId sessionId; |
|||
|
|||
public ActorCreator(ActorSystemContext context, SessionId sessionId) { |
|||
super(context); |
|||
this.sessionId = sessionId; |
|||
} |
|||
|
|||
@Override |
|||
public SessionActor create() throws Exception { |
|||
return new SessionActor(context, sessionId); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,180 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.actors.session; |
|||
|
|||
import akka.actor.ActorInitializationException; |
|||
import akka.actor.ActorRef; |
|||
import akka.actor.InvalidActorNameException; |
|||
import akka.actor.LocalActorRef; |
|||
import akka.actor.OneForOneStrategy; |
|||
import akka.actor.Props; |
|||
import akka.actor.SupervisorStrategy; |
|||
import akka.actor.Terminated; |
|||
import akka.event.Logging; |
|||
import akka.event.LoggingAdapter; |
|||
import akka.japi.Function; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.service.ContextAwareActor; |
|||
import org.thingsboard.server.actors.service.ContextBasedCreator; |
|||
import org.thingsboard.server.actors.service.DefaultActorService; |
|||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.msg.TbActorMsg; |
|||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|||
import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.core.SessionCloseMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|||
import scala.concurrent.duration.Duration; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
public class SessionManagerActor extends ContextAwareActor { |
|||
|
|||
private static final int INITIAL_SESSION_MAP_SIZE = 1024; |
|||
|
|||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); |
|||
|
|||
private final Map<String, ActorRef> sessionActors; |
|||
|
|||
SessionManagerActor(ActorSystemContext systemContext) { |
|||
super(systemContext); |
|||
this.sessionActors = new HashMap<>(INITIAL_SESSION_MAP_SIZE); |
|||
} |
|||
|
|||
@Override |
|||
public SupervisorStrategy supervisorStrategy() { |
|||
return strategy; |
|||
} |
|||
|
|||
@Override |
|||
protected boolean process(TbActorMsg msg) { |
|||
//TODO Move everything here, to work with TbActorMsg
|
|||
return false; |
|||
} |
|||
|
|||
@Override |
|||
public void onReceive(Object msg) throws Exception { |
|||
if (msg instanceof SessionCtrlMsg) { |
|||
onSessionCtrlMsg((SessionCtrlMsg) msg); |
|||
} else if (msg instanceof SessionAwareMsg) { |
|||
forwardToSessionActor((SessionAwareMsg) msg); |
|||
} else if (msg instanceof SessionTerminationMsg) { |
|||
onSessionTermination((SessionTerminationMsg) msg); |
|||
} else if (msg instanceof Terminated) { |
|||
onTermination((Terminated) msg); |
|||
} else if (msg instanceof SessionTimeoutMsg) { |
|||
onSessionTimeout((SessionTimeoutMsg) msg); |
|||
} else if (msg instanceof ClusterEventMsg) { |
|||
broadcast(msg); |
|||
} |
|||
} |
|||
|
|||
private void broadcast(Object msg) { |
|||
sessionActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
|||
} |
|||
|
|||
private void onSessionTimeout(SessionTimeoutMsg msg) { |
|||
String sessionIdStr = msg.getSessionId().toUidStr(); |
|||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|||
if (sessionActor != null) { |
|||
sessionActor.tell(msg, ActorRef.noSender()); |
|||
} |
|||
} |
|||
|
|||
private void onSessionCtrlMsg(SessionCtrlMsg msg) { |
|||
String sessionIdStr = msg.getSessionId().toUidStr(); |
|||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|||
if (sessionActor != null) { |
|||
sessionActor.tell(msg, ActorRef.noSender()); |
|||
} |
|||
} |
|||
|
|||
private void onSessionTermination(SessionTerminationMsg msg) { |
|||
String sessionIdStr = msg.getId().toUidStr(); |
|||
ActorRef sessionActor = sessionActors.remove(sessionIdStr); |
|||
if (sessionActor != null) { |
|||
log.debug("[{}] Removed session actor.", sessionIdStr); |
|||
//TODO: onSubscriptionUpdate device actor about session close;
|
|||
} else { |
|||
log.debug("[{}] Session actor was already removed.", sessionIdStr); |
|||
} |
|||
} |
|||
|
|||
private void forwardToSessionActor(SessionAwareMsg msg) { |
|||
if (msg instanceof ActorSystemToDeviceSessionActorMsg || msg instanceof SessionCloseMsg) { |
|||
String sessionIdStr = msg.getSessionId().toUidStr(); |
|||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|||
if (sessionActor != null) { |
|||
sessionActor.tell(msg, ActorRef.noSender()); |
|||
} else { |
|||
log.debug("[{}] Session actor was already removed.", sessionIdStr); |
|||
} |
|||
} else { |
|||
try { |
|||
getOrCreateSessionActor(msg.getSessionId()).tell(msg, self()); |
|||
} catch (InvalidActorNameException e) { |
|||
log.info("Invalid msg : {}", msg); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private ActorRef getOrCreateSessionActor(SessionId sessionId) { |
|||
String sessionIdStr = sessionId.toUidStr(); |
|||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|||
if (sessionActor == null) { |
|||
log.debug("[{}] Creating session actor.", sessionIdStr); |
|||
sessionActor = context().actorOf( |
|||
Props.create(new SessionActor.ActorCreator(systemContext, sessionId)).withDispatcher(DefaultActorService.SESSION_DISPATCHER_NAME), |
|||
sessionIdStr); |
|||
sessionActors.put(sessionIdStr, sessionActor); |
|||
log.debug("[{}] Created session actor.", sessionIdStr); |
|||
} |
|||
return sessionActor; |
|||
} |
|||
|
|||
private void onTermination(Terminated message) { |
|||
ActorRef terminated = message.actor(); |
|||
if (terminated instanceof LocalActorRef) { |
|||
log.info("Removed actor: {}.", terminated); |
|||
//TODO: cleanup session actors map
|
|||
} else { |
|||
throw new IllegalStateException("Remote actors are not supported!"); |
|||
} |
|||
} |
|||
|
|||
public static class ActorCreator extends ContextBasedCreator<SessionManagerActor> { |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
public ActorCreator(ActorSystemContext context) { |
|||
super(context); |
|||
} |
|||
|
|||
@Override |
|||
public SessionManagerActor create() throws Exception { |
|||
return new SessionManagerActor(context); |
|||
} |
|||
} |
|||
|
|||
private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { |
|||
@Override |
|||
public SupervisorStrategy.Directive apply(Throwable t) { |
|||
logger.error(t, "Unknown failure"); |
|||
return SupervisorStrategy.stop(); |
|||
} |
|||
}); |
|||
} |
|||
@ -1,95 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.actors.session; |
|||
|
|||
import akka.actor.ActorContext; |
|||
import akka.event.LoggingAdapter; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionContext; |
|||
import org.thingsboard.server.common.msg.session.SessionType; |
|||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|||
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
|||
import org.thingsboard.server.common.msg.session.ex.SessionException; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
class SyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
|||
private DeviceToDeviceActorMsg pendingMsg; |
|||
private Optional<ServerAddress> currentTargetServer; |
|||
private boolean pendingResponse; |
|||
|
|||
public SyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
|||
super(ctx, logger, sessionId); |
|||
} |
|||
|
|||
@Override |
|||
protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { |
|||
updateSessionCtx(msg, SessionType.SYNC); |
|||
pendingMsg = toDeviceMsg(msg); |
|||
pendingResponse = true; |
|||
currentTargetServer = forwardToAppActor(ctx, pendingMsg); |
|||
scheduleMsgWithDelay(ctx, new SessionTimeoutMsg(sessionId), getTimeout(systemContext, msg.getSessionMsg().getSessionContext()), ctx.parent()); |
|||
} |
|||
|
|||
public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { |
|||
if (pendingResponse) { |
|||
try { |
|||
sessionCtx.onMsg(SessionCloseMsg.onTimeout(sessionId)); |
|||
} catch (SessionException e) { |
|||
logger.warning("Failed to push session close msg", e); |
|||
} |
|||
terminateSession(context, this.sessionId); |
|||
} |
|||
} |
|||
|
|||
public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { |
|||
try { |
|||
sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); |
|||
pendingResponse = false; |
|||
} catch (SessionException e) { |
|||
logger.warning("Failed to push session response msg", e); |
|||
} |
|||
terminateSession(context, this.sessionId); |
|||
} |
|||
|
|||
@Override |
|||
public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { |
|||
if (pendingResponse) { |
|||
Optional<ServerAddress> newTargetServer = forwardToAppActorIfAddressChanged(context, pendingMsg, currentTargetServer); |
|||
if (logger.isDebugEnabled()) { |
|||
if (!newTargetServer.equals(currentTargetServer)) { |
|||
if (newTargetServer.isPresent()) { |
|||
logger.debug("[{}] Forwarded msg to new server: {}", sessionId, newTargetServer.get()); |
|||
} else { |
|||
logger.debug("[{}] Forwarded msg to local server.", sessionId); |
|||
} |
|||
} |
|||
} |
|||
currentTargetServer = newTargetServer; |
|||
} |
|||
} |
|||
|
|||
private long getTimeout(ActorSystemContext ctx, SessionContext sessionCtx) { |
|||
return sessionCtx.getTimeout() > 0 ? sessionCtx.getTimeout() : ctx.getSyncSessionTimeout(); |
|||
} |
|||
} |
|||
@ -0,0 +1,187 @@ |
|||
package org.thingsboard.server.service.transport; |
|||
|
|||
import akka.actor.ActorRef; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.kafka.clients.consumer.ConsumerRecords; |
|||
import org.apache.kafka.clients.producer.Callback; |
|||
import org.apache.kafka.clients.producer.RecordMetadata; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.service.ActorService; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
|||
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; |
|||
import org.thingsboard.server.kafka.TBKafkaProducerTemplate; |
|||
import org.thingsboard.server.kafka.TbKafkaSettings; |
|||
import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
|||
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
|||
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
|||
import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
|||
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.annotation.PreDestroy; |
|||
import java.time.Duration; |
|||
import java.util.Optional; |
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.function.Consumer; |
|||
|
|||
/** |
|||
* Created by ashvayka on 09.10.18. |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
@ConditionalOnProperty(prefix = "transport.remote", value = "enabled", havingValue = "true") |
|||
public class RemoteRuleEngineTransportService implements RuleEngineTransportService { |
|||
|
|||
private static final ObjectMapper mapper = new ObjectMapper(); |
|||
|
|||
@Value("${transport.remote.rule_engine.topic}") |
|||
private String ruleEngineTopic; |
|||
@Value("${transport.remote.notifications.topic}") |
|||
private String notificationsTopic; |
|||
@Value("${transport.remote.rule_engine.poll_interval}") |
|||
private int pollDuration; |
|||
@Value("${transport.remote.rule_engine.auto_commit_interval}") |
|||
private int autoCommitInterval; |
|||
|
|||
@Autowired |
|||
private TbKafkaSettings kafkaSettings; |
|||
|
|||
@Autowired |
|||
private DiscoveryService discoveryService; |
|||
|
|||
@Autowired |
|||
private ActorSystemContext actorContext; |
|||
|
|||
@Autowired |
|||
private ActorService actorService; |
|||
|
|||
//TODO: completely replace this routing with the Kafka routing by partition ids.
|
|||
@Autowired |
|||
private ClusterRoutingService routingService; |
|||
@Autowired |
|||
private ClusterRpcService rpcService; |
|||
@Autowired |
|||
private DataDecodingEncodingService encodingService; |
|||
|
|||
private TBKafkaConsumerTemplate<ToRuleEngineMsg> ruleEngineConsumer; |
|||
private TBKafkaProducerTemplate<ToTransportMsg> notificationsProducer; |
|||
|
|||
private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(); |
|||
|
|||
private volatile boolean stopped = false; |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToTransportMsg> notificationsProducerBuilder = TBKafkaProducerTemplate.builder(); |
|||
notificationsProducerBuilder.settings(kafkaSettings); |
|||
notificationsProducerBuilder.defaultTopic(notificationsTopic); |
|||
notificationsProducerBuilder.encoder(new ToTransportMsgEncoder()); |
|||
|
|||
notificationsProducer = notificationsProducerBuilder.build(); |
|||
notificationsProducer.init(); |
|||
|
|||
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToRuleEngineMsg> ruleEngineConsumerBuilder = TBKafkaConsumerTemplate.builder(); |
|||
ruleEngineConsumerBuilder.settings(kafkaSettings); |
|||
ruleEngineConsumerBuilder.topic(ruleEngineTopic); |
|||
ruleEngineConsumerBuilder.clientId(discoveryService.getNodeId()); |
|||
ruleEngineConsumerBuilder.groupId("tb-node"); |
|||
ruleEngineConsumerBuilder.autoCommit(true); |
|||
ruleEngineConsumerBuilder.autoCommitIntervalMs(autoCommitInterval); |
|||
ruleEngineConsumerBuilder.decoder(new ToRuleEngineMsgDecoder()); |
|||
|
|||
ruleEngineConsumer = ruleEngineConsumerBuilder.build(); |
|||
ruleEngineConsumer.subscribe(); |
|||
|
|||
mainConsumerExecutor.execute(() -> { |
|||
while (!stopped) { |
|||
try { |
|||
ConsumerRecords<String, byte[]> records = ruleEngineConsumer.poll(Duration.ofMillis(pollDuration)); |
|||
records.forEach(record -> { |
|||
try { |
|||
ToRuleEngineMsg toRuleEngineMsg = ruleEngineConsumer.decode(record); |
|||
if (toRuleEngineMsg.hasToDeviceActorMsg()) { |
|||
forwardToDeviceActor(toRuleEngineMsg.getToDeviceActorMsg()); |
|||
} |
|||
} catch (Throwable e) { |
|||
log.warn("Failed to process the notification.", e); |
|||
} |
|||
}); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to obtain messages from queue.", e); |
|||
try { |
|||
Thread.sleep(pollDuration); |
|||
} catch (InterruptedException e2) { |
|||
log.trace("Failed to wait until the server has capacity to handle new requests", e2); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
public void process(String nodeId, DeviceActorToTransportMsg msg) { |
|||
process(nodeId, msg, null, null); |
|||
} |
|||
|
|||
@Override |
|||
public void process(String nodeId, DeviceActorToTransportMsg msg, Runnable onSuccess, Consumer<Throwable> onFailure) { |
|||
notificationsProducer.send(notificationsTopic + "." + nodeId, |
|||
ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build() |
|||
, new QueueCallbackAdaptor(onSuccess, onFailure)); |
|||
} |
|||
|
|||
private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg) { |
|||
TransportToDeviceActorMsgWrapper wrapper = new TransportToDeviceActorMsgWrapper(toDeviceActorMsg); |
|||
Optional<ServerAddress> address = routingService.resolveById(wrapper.getDeviceId()); |
|||
if (address.isPresent()) { |
|||
rpcService.tell(encodingService.convertToProtoDataMessage(address.get(), wrapper)); |
|||
} else { |
|||
actorContext.getAppActor().tell(wrapper, ActorRef.noSender()); |
|||
} |
|||
} |
|||
|
|||
@PreDestroy |
|||
public void destroy() { |
|||
stopped = true; |
|||
if (ruleEngineConsumer != null) { |
|||
ruleEngineConsumer.unsubscribe(); |
|||
} |
|||
if (mainConsumerExecutor != null) { |
|||
mainConsumerExecutor.shutdownNow(); |
|||
} |
|||
} |
|||
|
|||
private static class QueueCallbackAdaptor implements Callback { |
|||
private final Runnable onSuccess; |
|||
private final Consumer<Throwable> onFailure; |
|||
|
|||
QueueCallbackAdaptor(Runnable onSuccess, Consumer<Throwable> onFailure) { |
|||
this.onSuccess = onSuccess; |
|||
this.onFailure = onFailure; |
|||
} |
|||
|
|||
@Override |
|||
public void onCompletion(RecordMetadata metadata, Exception exception) { |
|||
if (exception == null) { |
|||
if (onSuccess != null) { |
|||
onSuccess.run(); |
|||
} |
|||
} else { |
|||
if (onFailure != null) { |
|||
onFailure.accept(exception); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* <p> |
|||
* 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 |
|||
* <p> |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* <p> |
|||
* 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.thingsboard.server.service.transport; |
|||
|
|||
import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.; |
|||
|
|||
import java.util.function.Consumer; |
|||
|
|||
/** |
|||
* Created by ashvayka on 05.10.18. |
|||
*/ |
|||
public interface RuleEngineTransportService { |
|||
|
|||
void process(String nodeId, DeviceActorToTransportMsg msg); |
|||
|
|||
void process(String nodeId, DeviceActorToTransportMsg msg, Runnable onSuccess, Consumer<Throwable> onFailure); |
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.service.transport; |
|||
|
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.kafka.TbKafkaDecoder; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* Created by ashvayka on 05.10.18. |
|||
*/ |
|||
public class ToRuleEngineMsgDecoder implements TbKafkaDecoder<ToRuleEngineMsg> { |
|||
@Override |
|||
public ToRuleEngineMsg decode(byte[] data) throws IOException { |
|||
return ToRuleEngineMsg.parseFrom(data); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* <p> |
|||
* 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 |
|||
* <p> |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* <p> |
|||
* 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.thingsboard.server.service.transport; |
|||
|
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.kafka.TbKafkaEncoder; |
|||
|
|||
/** |
|||
* Created by ashvayka on 05.10.18. |
|||
*/ |
|||
public class ToTransportMsgEncoder implements TbKafkaEncoder<ToTransportMsg> { |
|||
@Override |
|||
public byte[] encode(ToTransportMsg value) { |
|||
return value.toByteArray(); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
package org.thingsboard.server.service.transport.msg; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.MsgType; |
|||
import org.thingsboard.server.common.msg.TbActorMsg; |
|||
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
|||
import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* Created by ashvayka on 09.10.18. |
|||
*/ |
|||
@Data |
|||
public class TransportToDeviceActorMsgWrapper implements TbActorMsg, DeviceAwareMsg, TenantAwareMsg, Serializable { |
|||
|
|||
private final TenantId tenantId; |
|||
private final DeviceId deviceId; |
|||
private final TransportToDeviceActorMsg msg; |
|||
|
|||
public TransportToDeviceActorMsgWrapper(TransportToDeviceActorMsg msg) { |
|||
this.msg = msg; |
|||
this.tenantId = new TenantId(new UUID(msg.getSessionInfo().getTenantIdMSB(), msg.getSessionInfo().getTenantIdLSB())); |
|||
this.deviceId = new DeviceId(new UUID(msg.getSessionInfo().getDeviceIdMSB(), msg.getSessionInfo().getDeviceIdLSB())); |
|||
} |
|||
|
|||
@Override |
|||
public MsgType getMsgType() { |
|||
return MsgType.TRANSPORT_TO_DEVICE_ACTOR_MSG; |
|||
} |
|||
} |
|||
@ -1,107 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.common.msg.device; |
|||
|
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.MsgType; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionType; |
|||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
@ToString |
|||
public class BasicDeviceToDeviceActorMsg implements DeviceToDeviceActorMsg { |
|||
|
|||
private static final long serialVersionUID = -1866795134993115408L; |
|||
|
|||
private final TenantId tenantId; |
|||
private final CustomerId customerId; |
|||
private final DeviceId deviceId; |
|||
private final SessionId sessionId; |
|||
private final SessionType sessionType; |
|||
private final ServerAddress serverAddress; |
|||
private final FromDeviceMsg msg; |
|||
|
|||
public BasicDeviceToDeviceActorMsg(DeviceToDeviceActorMsg other, FromDeviceMsg msg) { |
|||
this(null, other.getTenantId(), other.getCustomerId(), other.getDeviceId(), other.getSessionId(), other.getSessionType(), msg); |
|||
} |
|||
|
|||
public BasicDeviceToDeviceActorMsg(TransportToDeviceSessionActorMsg msg, SessionType sessionType) { |
|||
this(null, msg.getTenantId(), msg.getCustomerId(), msg.getDeviceId(), msg.getSessionId(), sessionType, msg.getSessionMsg().getMsg()); |
|||
} |
|||
|
|||
private BasicDeviceToDeviceActorMsg(ServerAddress serverAddress, TenantId tenantId, CustomerId customerId, DeviceId deviceId, SessionId sessionId, SessionType sessionType, |
|||
FromDeviceMsg msg) { |
|||
super(); |
|||
this.serverAddress = serverAddress; |
|||
this.tenantId = tenantId; |
|||
this.customerId = customerId; |
|||
this.deviceId = deviceId; |
|||
this.sessionId = sessionId; |
|||
this.sessionType = sessionType; |
|||
this.msg = msg; |
|||
} |
|||
|
|||
@Override |
|||
public DeviceId getDeviceId() { |
|||
return deviceId; |
|||
} |
|||
|
|||
@Override |
|||
public CustomerId getCustomerId() { |
|||
return customerId; |
|||
} |
|||
|
|||
public TenantId getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
@Override |
|||
public SessionId getSessionId() { |
|||
return sessionId; |
|||
} |
|||
|
|||
@Override |
|||
public SessionType getSessionType() { |
|||
return sessionType; |
|||
} |
|||
|
|||
@Override |
|||
public Optional<ServerAddress> getServerAddress() { |
|||
return Optional.ofNullable(serverAddress); |
|||
} |
|||
|
|||
@Override |
|||
public FromDeviceMsg getPayload() { |
|||
return msg; |
|||
} |
|||
|
|||
@Override |
|||
public DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress) { |
|||
return new BasicDeviceToDeviceActorMsg(otherAddress, tenantId, customerId, deviceId, sessionId, sessionType, msg); |
|||
} |
|||
|
|||
@Override |
|||
public MsgType getMsgType() { |
|||
return MsgType.DEVICE_SESSION_TO_DEVICE_ACTOR_MSG; |
|||
} |
|||
} |
|||
@ -1,41 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.common.msg.device; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Optional; |
|||
|
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.common.msg.TbActorMsg; |
|||
import org.thingsboard.server.common.msg.aware.CustomerAwareMsg; |
|||
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
|||
import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|||
import org.thingsboard.server.common.msg.session.SessionType; |
|||
|
|||
public interface DeviceToDeviceActorMsg extends TbActorMsg, DeviceAwareMsg, CustomerAwareMsg, TenantAwareMsg, Serializable { |
|||
|
|||
SessionId getSessionId(); |
|||
|
|||
SessionType getSessionType(); |
|||
|
|||
Optional<ServerAddress> getServerAddress(); |
|||
|
|||
FromDeviceMsg getPayload(); |
|||
|
|||
DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress); |
|||
} |
|||
@ -1,26 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* <p> |
|||
* 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
|
|||
* |
|||
* <p> |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* <p> |
|||
* 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.thingsboard.server.actors.session; |
|||
package org.thingsboard.server.common.transport; |
|||
|
|||
import org.thingsboard.server.actors.shared.ActorTerminationMsg; |
|||
import org.thingsboard.server.common.data.id.SessionId; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
|||
|
|||
public class SessionTerminationMsg extends ActorTerminationMsg<SessionId> { |
|||
/** |
|||
* Created by ashvayka on 04.10.18. |
|||
*/ |
|||
public interface SessionMsgListener { |
|||
|
|||
public SessionTerminationMsg(SessionId id) { |
|||
super(id); |
|||
} |
|||
void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse); |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* <p> |
|||
* 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 |
|||
* <p> |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* <p> |
|||
* 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.thingsboard.server.mqtt.service; |
|||
|
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.kafka.TbKafkaEncoder; |
|||
|
|||
/** |
|||
* Created by ashvayka on 05.10.18. |
|||
*/ |
|||
public class ToRuleEngineMsgEncoder implements TbKafkaEncoder<ToRuleEngineMsg> { |
|||
@Override |
|||
public byte[] encode(ToRuleEngineMsg value) { |
|||
return value.toByteArray(); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.mqtt.service; |
|||
|
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.kafka.TbKafkaDecoder; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* Created by ashvayka on 05.10.18. |
|||
*/ |
|||
public class ToTransportMsgResponseDecoder implements TbKafkaDecoder<ToTransportMsg> { |
|||
@Override |
|||
public ToTransportMsg decode(byte[] data) throws IOException { |
|||
return ToTransportMsg.parseFrom(data); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue