package freenet.node.useralerts;
import java.io.File;
import freenet.clients.fcp.FCPMessage;
import freenet.clients.fcp.FeedMessage;
import freenet.l10n.NodeL10n;
import freenet.node.NodeClientCore;
import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.io.FilenameGenerator;
/** Tell the user when there is insufficient disk space for either short term (transient requests,
* request completion) or long term (starting persistent requests).
* @author toad
*/
public class DiskSpaceUserAlert implements UserEvent {
final NodeClientCore core;
private Status status;
private long lastCheckedStatus;
static final int UPDATE_TIME = 100;
enum Status {
/** Everything is OK. */
OK,
/** Not enough space to start persistent requests: Space on persistent-temp-* < long term
* limit. */
PERSISTENT,
/** Not enough space to start transient requests, finish persistent requests or do
* anything much: Space on temp-* < short term limit */
TRANSIENT,
/** Not enough space to complete persistent requests: Space on persistent-temp-* < short
* term limit. */
PERSISTENT_COMPLETION;
public String getExplanation() {
return l10n("explanation."+toString());
}
}
Status evaluate() {
long shortTermLimit = core.getMinDiskFreeShortTerm();
long longTermLimit = core.getMinDiskFreeLongTerm();
File tempDir = core.tempFilenameGenerator.getDir();
if(tempDir.getUsableSpace() < shortTermLimit)
return Status.TRANSIENT; // Takes precedence.
FilenameGenerator fg = core.persistentFilenameGenerator;
if(fg != null) {
File persistentTempDir = fg.getDir();
long space = persistentTempDir.getUsableSpace();
if(space < shortTermLimit)
return Status.PERSISTENT_COMPLETION;
if(space < longTermLimit)
return Status.PERSISTENT;
}
return Status.OK;
}
public DiskSpaceUserAlert(NodeClientCore core) {
this.core = core;
}
@Override
public boolean userCanDismiss() {
return true;
}
@Override
public String getTitle() {
return l10n("title");
}
private static String l10n(String key) {
return NodeL10n.getBase().getString("DiskSpaceUserAlert."+key);
}
private static String l10n(String key, String pattern, String value) {
return NodeL10n.getBase().getString("DiskSpaceUserAlert."+key, pattern, value);
}
@Override
public String getText() {
Status status = getStatus();
StringBuffer sb = new StringBuffer();
sb.append(l10n("notEnoughSpaceIn", "where", getWhere(status).toString()));
sb.append(" ");
sb.append(status.getExplanation());
sb.append(" ");
sb.append(l10n("action"));
return sb.toString();
}
private File getWhere(Status status) {
// FIXME return the filesystem rather than the directory. Will need java.nio.file (1.7).
if(status == Status.PERSISTENT || status == Status.PERSISTENT_COMPLETION) {
// Be very careful about race conditions!
FilenameGenerator fg = core.persistentFilenameGenerator;
if(fg != null) {
return fg.getDir();
}
}
return core.tempFilenameGenerator.getDir();
}
private synchronized Status getStatus() {
long now = System.currentTimeMillis();
if(!(this.status == null || now - lastCheckedStatus > UPDATE_TIME)) return status;
try {
status = evaluate();
lastCheckedStatus = now;
return status;
} catch (Throwable t) {
// This is an alert. If it fails, it can break the web interface completely.
// So it's essential that we catch Throwable's here.
Logger.error(this, "Unable to check disk space: "+t, t);
return Status.OK;
}
}
@Override
public HTMLNode getHTMLText() {
return new HTMLNode("#", getText());
}
@Override
public String getShortText() {
return getTitle();
}
@Override
public short getPriorityClass() {
return UserAlert.CRITICAL_ERROR;
}
@Override
public boolean isValid() {
Status status = getStatus();
return status != Status.OK;
}
@Override
public void isValid(boolean validity) {
// Ignore.
}
@Override
public String dismissButtonText() {
return NodeL10n.getBase().getString("UserAlert.hide");
}
@Override
public boolean shouldUnregisterOnDismiss() {
return true;
}
@Override
public void onDismiss() {
// Ignore.
}
@Override
public String anchor() {
return "not-enough-disk-space";
}
@Override
public boolean isEventNotification() {
return false;
}
@Override
public FCPMessage getFCPMessage() {
return new FeedMessage(getTitle(), getShortText(), getText(), getPriorityClass(), getUpdatedTime());
}
@Override
public synchronized long getUpdatedTime() {
return lastCheckedStatus;
}
@Override
public Type getEventType() {
return null;
}
}