Commit ce6ade96 authored by Andrey Filippov's avatar Andrey Filippov

MCP FS access fine tuning, with examples

parent 8f31b82c
# Example MCP allowed-config file.
# Point -Delphel.mcp.allowed.configfile to this file.
# You can set either allowed.configdir or allowed.config.
#
# allowed.configdir=/media/elphel/btrfs-data/lwir16-proc/NC/config
# allowed.config=/media/elphel/btrfs-data/lwir16-proc/NC/config/MI184-v89-nc_site_30A-no_out.corr-xml
...@@ -17,11 +17,12 @@ import com.elphel.imagej.cameras.EyesisCorrectionParameters.CorrectionParameters ...@@ -17,11 +17,12 @@ import com.elphel.imagej.cameras.EyesisCorrectionParameters.CorrectionParameters
public class McpFsAccess { public class McpFsAccess {
private static final String PROP_ALLOWED_CONFIG = "elphel.mcp.allowed.config"; private static final String PROP_ALLOWED_CONFIG = "elphel.mcp.allowed.config";
private static final String PROP_ALLOWED_CONFIG_DIR = "elphel.mcp.allowed.configdir"; private static final String PROP_ALLOWED_CONFIG_DIR = "elphel.mcp.allowed.configdir";
private static final String PROP_ALLOWED_CONFIG_FILE = "elphel.mcp.allowed.configfile";
private static final String PROP_ALLOWED_EXTRA = "elphel.mcp.allowed.extra"; private static final String PROP_ALLOWED_EXTRA = "elphel.mcp.allowed.extra";
private static final String CONFIG_LIST_KEY = "CORRECTION_PARAMETERS.sourceSequencesList"; private static final String CONFIG_LIST_KEY = "CORRECTION_PARAMETERS.sourceSequencesList";
private static List<Path> cachedRoots = null; private static List<Path> cachedRoots = null;
private static String cachedConfig = null; private static String cachedConfigKey = null;
private static long cachedConfigMtime = -1L; private static long cachedConfigMtime = -1L;
private McpFsAccess() { private McpFsAccess() {
...@@ -30,16 +31,41 @@ public class McpFsAccess { ...@@ -30,16 +31,41 @@ public class McpFsAccess {
public static synchronized List<Path> getAllowedRoots() { public static synchronized List<Path> getAllowedRoots() {
String configPath = System.getProperty(PROP_ALLOWED_CONFIG); String configPath = System.getProperty(PROP_ALLOWED_CONFIG);
String configDir = System.getProperty(PROP_ALLOWED_CONFIG_DIR); String configDir = System.getProperty(PROP_ALLOWED_CONFIG_DIR);
long mtime = getMtime(configPath, configDir); String configFile = System.getProperty(PROP_ALLOWED_CONFIG_FILE);
if (cachedRoots != null && configEquals(configPath, cachedConfig) && mtime == cachedConfigMtime) { String[] resolved = resolveConfigFromFile(configPath, configDir, configFile);
configPath = resolved[0];
configDir = resolved[1];
String cacheKey = buildCacheKey(configPath, configDir, configFile);
long mtime = getMtime(configPath, configDir, configFile);
if (cachedRoots != null && configEquals(cacheKey, cachedConfigKey) && mtime == cachedConfigMtime) {
return cachedRoots; return cachedRoots;
} }
cachedRoots = buildAllowedRoots(configPath, configDir); cachedRoots = buildAllowedRoots(configPath, configDir);
cachedConfig = configPath; cachedConfigKey = cacheKey;
cachedConfigMtime = mtime; cachedConfigMtime = mtime;
return cachedRoots; return cachedRoots;
} }
public static boolean hasConfig() {
String configPath = System.getProperty(PROP_ALLOWED_CONFIG);
String configDir = System.getProperty(PROP_ALLOWED_CONFIG_DIR);
String configFile = System.getProperty(PROP_ALLOWED_CONFIG_FILE);
String[] resolved = resolveConfigFromFile(configPath, configDir, configFile);
configPath = resolved[0];
configDir = resolved[1];
return (configPath != null && !configPath.trim().isEmpty())
|| (configDir != null && !configDir.trim().isEmpty());
}
public static void ensureConfigured() {
if (!hasConfig()) {
throw new IllegalStateException(
"MCP enabled but no allowed config specified. Set -Delphel.mcp.allowed.configdir "
+ "or -Delphel.mcp.allowed.config, or provide -Delphel.mcp.allowed.configfile "
+ "pointing to a file with allowed.configdir.");
}
}
public static boolean isAllowed(Path path) { public static boolean isAllowed(Path path) {
if (path == null) { if (path == null) {
return false; return false;
...@@ -200,16 +226,17 @@ public class McpFsAccess { ...@@ -200,16 +226,17 @@ public class McpFsAccess {
return -1L; return -1L;
} }
private static long getMtime(String configPath) { private static long getMtime(String configPath, String configDir, String configFile) {
if (configPath == null || configPath.trim().isEmpty()) { long max = getMtime(configPath, configDir);
return -1L; if (configFile != null && !configFile.trim().isEmpty()) {
}
try { try {
return Files.getLastModifiedTime(Paths.get(configPath)).toMillis(); max = Math.max(max, Files.getLastModifiedTime(Paths.get(configFile)).toMillis());
} catch (IOException e) { } catch (IOException e) {
return -1L; // ignore
} }
} }
return max;
}
private static boolean configEquals(String a, String b) { private static boolean configEquals(String a, String b) {
if (a == null && b == null) { if (a == null && b == null) {
...@@ -220,4 +247,58 @@ public class McpFsAccess { ...@@ -220,4 +247,58 @@ public class McpFsAccess {
} }
return a.equals(b); return a.equals(b);
} }
private static String buildCacheKey(String configPath, String configDir, String configFile) {
StringBuilder sb = new StringBuilder();
if (configPath != null) {
sb.append(configPath);
}
sb.append("|");
if (configDir != null) {
sb.append(configDir);
}
sb.append("|");
if (configFile != null) {
sb.append(configFile);
}
return sb.toString();
}
private static String[] resolveConfigFromFile(String configPath, String configDir, String configFile) {
if ((configPath != null && !configPath.trim().isEmpty())
|| (configDir != null && !configDir.trim().isEmpty())) {
return new String[] { configPath, configDir };
}
if (configFile == null || configFile.trim().isEmpty()) {
return new String[] { configPath, configDir };
}
Path filePath = Paths.get(configFile).toAbsolutePath().normalize();
if (!Files.exists(filePath)) {
return new String[] { configPath, configDir };
}
try {
List<String> lines = Files.readAllLines(filePath);
for (String line : lines) {
String trimmed = line.trim();
if (trimmed.isEmpty() || trimmed.startsWith("#")) {
continue;
}
int eq = trimmed.indexOf('=');
if (eq > 0) {
String key = trimmed.substring(0, eq).trim();
String value = trimmed.substring(eq + 1).trim();
if (key.equals(PROP_ALLOWED_CONFIG)) {
configPath = value;
} else if (key.equals(PROP_ALLOWED_CONFIG_DIR) || key.equals("allowed.configdir")) {
configDir = value;
}
} else if (configDir == null || configDir.trim().isEmpty()) {
configDir = trimmed;
}
}
} catch (IOException e) {
return new String[] { configPath, configDir };
}
return new String[] { configPath, configDir };
}
} }
...@@ -30,6 +30,7 @@ public class McpServer { ...@@ -30,6 +30,7 @@ public class McpServer {
if (INSTANCE != null) { if (INSTANCE != null) {
return INSTANCE; return INSTANCE;
} }
McpFsAccess.ensureConfigured();
McpServer instance = new McpServer(owner, port); McpServer instance = new McpServer(owner, port);
instance.start(); instance.start();
INSTANCE = instance; INSTANCE = instance;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment