package com.beowulfe.hap.impl.connections;
import java.io.IOException;
import java.net.InetAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.beowulfe.hap.HomekitAccessory;
import com.beowulfe.hap.HomekitAuthInfo;
import com.beowulfe.hap.impl.HomekitRegistry;
import com.beowulfe.hap.impl.http.HomekitClientConnection;
import com.beowulfe.hap.impl.http.HttpRequest;
import com.beowulfe.hap.impl.http.HttpResponse;
import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser;
import com.beowulfe.hap.impl.json.AccessoryController;
import com.beowulfe.hap.impl.json.CharacteristicsController;
import com.beowulfe.hap.impl.pairing.PairVerificationManager;
import com.beowulfe.hap.impl.pairing.PairingManager;
import com.beowulfe.hap.impl.pairing.PairingUpdateController;
import com.beowulfe.hap.impl.responses.InternalServerErrorResponse;
import com.beowulfe.hap.impl.responses.NotFoundResponse;
class HttpSession {
private volatile PairingManager pairingManager;
private volatile PairVerificationManager pairVerificationManager;
private volatile AccessoryController accessoryController;
private volatile CharacteristicsController characteristicsController;
private final HomekitAuthInfo authInfo;
private final HomekitRegistry registry;
private final SubscriptionManager subscriptions;
private final HomekitClientConnection connection;
private final JmdnsHomekitAdvertiser advertiser;
private final static Logger logger = LoggerFactory.getLogger(HttpSession.class);
public HttpSession(HomekitAuthInfo authInfo, HomekitRegistry registry, SubscriptionManager subscriptions,
HomekitClientConnection connection, JmdnsHomekitAdvertiser advertiser) {
this.authInfo = authInfo;
this.registry = registry;
this.subscriptions = subscriptions;
this.connection = connection;
this.advertiser = advertiser;
}
public HttpResponse handleRequest(HttpRequest request) throws IOException {
switch(request.getUri()) {
case "/pair-setup":
return handlePairSetup(request);
case "/pair-verify":
return handlePairVerify(request);
default:
if (registry.isAllowUnauthenticatedRequests()) {
return handleAuthenticatedRequest(request);
} else {
logger.info("Unrecognized request for "+request.getUri());
return new NotFoundResponse();
}
}
}
public HttpResponse handleAuthenticatedRequest(HttpRequest request) throws IOException {
try {
switch(request.getUri()) {
case "/accessories":
return getAccessoryController().listing();
case "/characteristics":
switch(request.getMethod()) {
case PUT:
return getCharacteristicsController().put(request, connection);
default:
logger.info("Unrecognized method for "+request.getUri());
return new NotFoundResponse();
}
case "/pairings":
return new PairingUpdateController(authInfo, advertiser).handle(request);
default:
if (request.getUri().startsWith("/characteristics?")) {
return getCharacteristicsController().get(request);
}
logger.info("Unrecognized request for "+request.getUri());
return new NotFoundResponse();
}
} catch (Exception e) {
logger.error("Could not handle request", e);
return new InternalServerErrorResponse(e);
}
}
private HttpResponse handlePairSetup(HttpRequest request) {
if (pairingManager == null) {
synchronized(HttpSession.class) {
if (pairingManager == null) {
pairingManager = new PairingManager(authInfo, registry, advertiser);
}
}
}
try {
return pairingManager.handle(request);
} catch (Exception e) {
logger.error("Exception encountered during pairing", e);
return new InternalServerErrorResponse(e);
}
}
private HttpResponse handlePairVerify(HttpRequest request) {
if (pairVerificationManager == null) {
synchronized(HttpSession.class) {
if (pairVerificationManager == null) {
pairVerificationManager = new PairVerificationManager(authInfo, registry);
}
}
}
try {
return pairVerificationManager.handle(request);
} catch (Exception e) {
logger.error("Excepton encountered while verifying pairing", e);
return new InternalServerErrorResponse(e);
}
}
private synchronized AccessoryController getAccessoryController() {
if (accessoryController == null) {
accessoryController = new AccessoryController(registry);
}
return accessoryController;
}
private synchronized CharacteristicsController getCharacteristicsController() {
if (characteristicsController == null) {
characteristicsController = new CharacteristicsController(registry, subscriptions);
}
return characteristicsController;
}
public static class SessionKey {
private final InetAddress address;
private final HomekitAccessory accessory;
public SessionKey(InetAddress address, HomekitAccessory accessory) {
this.address = address;
this.accessory = accessory;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SessionKey) {
return address.equals(((SessionKey) obj).address) &&
accessory.equals(((SessionKey) obj).accessory);
} else {
return false;
}
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + address.hashCode();
hash = hash * 31 + accessory.hashCode();
return hash;
}
}
}