Skip to content

Commit

Permalink
Update endpoint v1/devices/inactive
Browse files Browse the repository at this point in the history
- Remove deprecated method getInactiveDevice and its dependents
- Redefine DeviceInactive constructor
- Add inactive threshold, start time and pagination ability
  • Loading branch information
longd3 committed Dec 11, 2014
1 parent b82898c commit 3cb377d
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.hello.suripu.core.models.DeviceAccountPair;
import com.hello.suripu.core.models.DeviceInactive;
import com.hello.suripu.core.models.DeviceStatus;
import com.hello.suripu.core.models.DeviceInactivePaginator;
import com.hello.suripu.core.models.PillRegistration;
import com.hello.suripu.core.oauth.AccessToken;
import com.hello.suripu.core.oauth.OAuthScope;
Expand Down Expand Up @@ -190,44 +191,66 @@ private List<Device> getDevicesByAccountId(final Long accountId) {
return devices;
}

@GET
@Timed
@Path("/inactive/hours/{inactive_hours}")
@Produces(MediaType.APPLICATION_JSON)
public List<DeviceInactive> getInactiveDevice(@Scope(OAuthScope.ADMINISTRATION_READ) final AccessToken accessToken, @PathParam("inactive_hours") Integer inactiveHours) {
final DateTime startTime = DateTime.now().minusMonths(2);
return deviceDAO.getInactiveDevice(startTime, inactiveHours);
}


@GET
@Timed
@Path("/inactive")
@Produces(MediaType.APPLICATION_JSON)
public List<DeviceInactive> getInactiveDevices(@Scope(OAuthScope.ADMINISTRATION_READ) final AccessToken accessToken, @QueryParam("since") final Long timestamp) {
if(timestamp == null) {
LOGGER.error("Missing since parameter");
public DeviceInactivePaginator getInactiveDevices(@Scope(OAuthScope.ADMINISTRATION_READ) final AccessToken accessToken,
@QueryParam("start") final Long startTimeStamp,
@QueryParam("since") final Long inactiveSince,
@QueryParam("threshold") final Long inactiveThreshold,
@QueryParam("page") final Integer currentPage) {
if(startTimeStamp == null) {
LOGGER.error("Missing startTimestamp parameter");
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}

if(inactiveSince == null) {
LOGGER.error("Missing inactiveSince parameter");
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}

if(inactiveThreshold == null) {
LOGGER.error("Missing inactiveThreshold parameter");
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}

if(currentPage == null) {
LOGGER.error("Missing page parameter");
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}

final Integer maxDevicesPerPage = 40;
final Integer offset = Math.max(0, (currentPage - 1) * maxDevicesPerPage);
final Integer count = maxDevicesPerPage;

final Jedis jedis = jedisPool.getResource();
final Set<Tuple> tuples = new TreeSet<>();
Integer totalPages = 0;

LOGGER.debug("{} {} {} {}", inactiveSince - inactiveThreshold, inactiveSince, offset, count);
try {
tuples.addAll(jedis.zrangeByScoreWithScores("devices", 0, timestamp));
// e.g for startTimeStamp = 1417464883000: only care about devices last seen after Dec 1, 2014
// for inactiveSince = 1418070001000 e.g for inactiveThreshold = 259200000, this function returns
// devices which have been inactive for at least 3 days since Dec 4, 2014
tuples.addAll(jedis.zrangeByScoreWithScores("devices", startTimeStamp, inactiveSince - inactiveThreshold, offset, count));
totalPages = (int)Math.ceil(jedis.zcount("devices", startTimeStamp, inactiveSince - inactiveThreshold) / (double) maxDevicesPerPage);

} catch (Exception e) {
LOGGER.error("Failed retrieving list of devices", e.getMessage());
} finally {
jedisPool.returnResource(jedis);
}

final List<DeviceInactive> inactiveDevices = new ArrayList<>();
for(final Tuple tuple : tuples) {
final Long millis = (long) tuple.getScore();
final DateTime diff = DateTime.now().minus(new DateTime(millis).getMillis());
final DeviceInactive deviceInactive = new DeviceInactive(tuple.getElement(), 0L, "", diff);
final Long lastSeenTimestamp = (long) tuple.getScore();
final Long inactivePeriod = inactiveSince - lastSeenTimestamp;
final DeviceInactive deviceInactive = new DeviceInactive(tuple.getElement(), inactivePeriod);
inactiveDevices.add(deviceInactive);
}

return inactiveDevices;
return new DeviceInactivePaginator(currentPage, totalPages, inactiveDevices);
}

@Timed
Expand Down
11 changes: 0 additions & 11 deletions suripu-core/src/main/java/com/hello/suripu/core/db/DeviceDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@
import com.google.common.collect.ImmutableList;
import com.hello.suripu.core.db.mappers.AccountMapper;
import com.hello.suripu.core.db.mappers.DeviceAccountPairMapper;
import com.hello.suripu.core.db.mappers.DeviceInactiveMapper;
import com.hello.suripu.core.db.mappers.DeviceStatusMapper;
import com.hello.suripu.core.models.Account;
import com.hello.suripu.core.models.DeviceAccountPair;
import com.hello.suripu.core.models.DeviceInactive;
import com.hello.suripu.core.models.DeviceStatus;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.GetGeneratedKeys;
import org.skife.jdbi.v2.sqlobject.SqlQuery;
Expand Down Expand Up @@ -110,14 +107,6 @@ Optional<Long> getPillIdForAccountIdDeviceId(
@SqlQuery("SELECT id, device_id AS pill_id, firmware_version AS firmware_version, 100 AS battery_level, ts AS last_seen from device_sensors_master WHERE device_id = :sense_id ORDER BY id DESC LIMIT 1;")
Optional<DeviceStatus> senseStatus(@Bind("sense_id") final Long senseId);

@RegisterMapper(DeviceInactiveMapper.class)
@SingleValueResult(DeviceInactive.class)
@SqlQuery("SELECT sq.device_id, sq.id, sq.diff, sq.max_ts FROM (SELECT M.device_id AS device_id, MAX(M.id) AS id, MAX(D.ts) AS max_ts, now() - MAX(D.ts) AS diff FROM account_device_map M LEFT OUTER JOIN device_sensors_master D ON M.id = D.device_id WHERE D.ts > :start_time GROUP BY M.device_id) AS sq WHERE sq.diff >= :inactive_hours * interval '1 hour' LIMIT 100")
ImmutableList<DeviceInactive> getInactiveDevice(
@Bind("start_time") final DateTime startTime,
@Bind("inactive_hours") final Integer inactiveHours
);

@RegisterMapper(AccountMapper.class)
@SingleValueResult(Account.class)
@SqlQuery("SELECT * FROM account_device_map as m JOIN accounts as a ON (a.id = m.account_id) WHERE m.device_name = :device_id LIMIT :max_devices;")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@


import com.fasterxml.jackson.annotation.JsonProperty;
import org.joda.time.DateTime;

public class DeviceInactive{

@JsonProperty("device_id")
public final String deviceId;
public final Long id;
public final String diff;
@JsonProperty("max_ts")
public final DateTime maxTs;
@JsonProperty("inactive_period")
public final Long inactivePeriodInMilliseconds;

public DeviceInactive(final String deviceId, final Long id, final String diff, final DateTime maxTs) {
public DeviceInactive(final String deviceId, final Long inactivePeriodInMilliseconds) {
this.deviceId = deviceId;
this.id = id;
this.diff = diff;
this.maxTs = maxTs;
this.inactivePeriodInMilliseconds = inactivePeriodInMilliseconds;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.hello.suripu.core.models;

/**
* Created by zet on 12/11/14.
*/
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public class DeviceInactivePaginator {

@JsonProperty("current_page")
public final Integer currentPage;
@JsonProperty("total_pages")
public final Integer totalPages;
@JsonProperty("content")
public final List<DeviceInactive> content;

public DeviceInactivePaginator(final Integer currentPage, final Integer totalPages, final List<DeviceInactive> content) {
this.currentPage = currentPage;
this.totalPages = totalPages;
this.content = content;
}
}

0 comments on commit 3cb377d

Please sign in to comment.