package cc.blynk.server.application.handlers.main.logic.dashboard.widget; import cc.blynk.server.application.handlers.main.auth.AppStateHolder; import cc.blynk.server.core.model.DashBoard; import cc.blynk.server.core.model.auth.User; import cc.blynk.server.core.model.widgets.Widget; import cc.blynk.server.core.model.widgets.controls.Timer; import cc.blynk.server.core.model.widgets.notifications.Notification; import cc.blynk.server.core.model.widgets.others.eventor.Eventor; import cc.blynk.server.core.model.widgets.ui.Tabs; import cc.blynk.server.core.protocol.exceptions.IllegalCommandException; import cc.blynk.server.core.protocol.exceptions.NotAllowedException; import cc.blynk.server.core.protocol.model.messages.StringMessage; import cc.blynk.server.workers.timer.TimerWorker; import cc.blynk.utils.JsonParser; import cc.blynk.utils.ParseUtil; import io.netty.channel.ChannelHandlerContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import static cc.blynk.utils.BlynkByteBufUtil.ok; import static cc.blynk.utils.StringUtils.split2; /** * The Blynk Project. * Created by Dmitriy Dumanskiy. * Created on 01.02.16. */ public class UpdateWidgetLogic { private static final Logger log = LogManager.getLogger(UpdateWidgetLogic.class); private final int MAX_WIDGET_SIZE; private final TimerWorker timerWorker; public UpdateWidgetLogic(int maxWidgetSize, TimerWorker timerWorker) { this.MAX_WIDGET_SIZE = maxWidgetSize; this.timerWorker = timerWorker; } public void messageReceived(ChannelHandlerContext ctx, AppStateHolder state, StringMessage message) { String[] split = split2(message.body); if (split.length < 2) { throw new IllegalCommandException("Wrong income message format."); } int dashId = ParseUtil.parseInt(split[0]) ; String widgetString = split[1]; if (widgetString == null || widgetString.isEmpty()) { throw new IllegalCommandException("Income widget message is empty."); } if (widgetString.length() > MAX_WIDGET_SIZE) { throw new NotAllowedException("Widget is larger then limit."); } final User user = state.user; DashBoard dash = user.profile.getDashByIdOrThrow(dashId); Widget newWidget = JsonParser.parseWidget(widgetString); if (newWidget.width < 1 || newWidget.height < 1) { throw new NotAllowedException("Widget has wrong dimensions."); } log.debug("Updating widget {}.", widgetString); int existingWidgetIndex = dash.getWidgetIndexById(newWidget.id); if (newWidget instanceof Tabs) { Tabs newTabs = (Tabs) newWidget; DeleteWidgetLogic.deleteTabs(timerWorker, user, state.userKey, dash, newTabs.tabs.length - 1); } Widget prevWidget = dash.widgets[existingWidgetIndex]; if (prevWidget instanceof Notification && newWidget instanceof Notification) { Notification prevNotif = (Notification) prevWidget; Notification newNotif = (Notification) newWidget; newNotif.iOSTokens.putAll(prevNotif.iOSTokens); newNotif.androidTokens.putAll(prevNotif.androidTokens); } //non atomic update. changes could not be visible in saving thread. //ignoring for now dash.widgets[existingWidgetIndex] = newWidget; dash.cleanPinStorage(newWidget); dash.updatedAt = System.currentTimeMillis(); user.lastModifiedTs = dash.updatedAt; if (prevWidget instanceof Timer) { timerWorker.delete(state.userKey, (Timer) prevWidget, dashId); } else if (prevWidget instanceof Eventor) { timerWorker.delete(state.userKey, (Eventor) prevWidget, dashId); } if (newWidget instanceof Timer) { timerWorker.add(state.userKey, (Timer) newWidget, dashId); } else if (newWidget instanceof Eventor) { timerWorker.add(state.userKey, (Eventor) newWidget, dashId); } ctx.writeAndFlush(ok(message.id), ctx.voidPromise()); } }