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 |
* Copyright © 2016-2018 The Thingsboard Authors |
||||
* |
* <p> |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||
* |
* <p> |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
* <p> |
||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
* 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.gen.transport.TransportProtos.GetAttributeResponseMsg; |
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
|
|
||||
public class SessionTerminationMsg extends ActorTerminationMsg<SessionId> { |
/** |
||||
|
* Created by ashvayka on 04.10.18. |
||||
|
*/ |
||||
|
public interface SessionMsgListener { |
||||
|
|
||||
public SessionTerminationMsg(SessionId id) { |
void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse); |
||||
super(id); |
|
||||
} |
|
||||
} |
} |
||||
@ -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