diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java index 0c743f172a73522e526ccae233a17ab9121f8cec..53c2de687dd2bb1383c793ba42d20358def6fe07 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/config/ConfigurationOption.java @@ -84,7 +84,7 @@ public enum ConfigurationOption implements ConfigOptionDef { SITE_URL( "duniter4j.site.url", n("duniter4j.config.option.site.url.description"), - "http://ucoin.io/duniter4j", + "https://github.com/duniter/duniter4j", URL.class), ORGANIZATION_NAME( @@ -143,14 +143,14 @@ public enum ConfigurationOption implements ConfigOptionDef { NODE_HOST( "duniter4j.node.host", n("duniter4j.config.option.node.host.description"), - "metab.ucoin.io", + "cgeek.fr", String.class, false), NODE_PORT( "duniter4j.node.port", n("duniter4j.config.option.node.port.description"), - "9201", + "9330", Integer.class, false), diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java index 4f1bcd236bf23ffc7c45816bcc8e93ded73300e6..ac6e2f870ad5658a62ff92098be699e95962d5aa 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java @@ -29,6 +29,7 @@ import org.duniter.core.client.model.bma.Error; import org.duniter.core.client.model.bma.gson.GsonUtils; import org.duniter.core.client.model.local.Peer; import org.duniter.core.client.service.exception.HttpBadRequestException; +import org.duniter.core.client.service.exception.HttpNotFoundException; import org.duniter.core.client.service.exception.JsonSyntaxException; import org.duniter.core.client.service.exception.PeerConnectionException; import org.duniter.core.exception.TechnicalException; @@ -190,6 +191,8 @@ public class HttpServiceImpl implements HttpService, Closeable, InitializingBean case HttpStatus.SC_UNAUTHORIZED: case HttpStatus.SC_FORBIDDEN: throw new TechnicalException(I18n.t("duniter4j.client.authentication")); + case HttpStatus.SC_NOT_FOUND: + throw new HttpNotFoundException(I18n.t("duniter4j.client.notFound", request.toString())); case HttpStatus.SC_BAD_REQUEST: try { Error error = (Error)parseResponse(response, Error.class); @@ -199,7 +202,7 @@ public class HttpServiceImpl implements HttpService, Closeable, InitializingBean throw new HttpBadRequestException(I18n.t("duniter4j.client.status", response.getStatusLine().toString())); } default: - throw new TechnicalException(I18n.t("duniter4j.client.status", response.getStatusLine().toString())); + throw new TechnicalException(I18n.t("duniter4j.client.status", request.toString(), response.getStatusLine().toString())); } } catch (ConnectException e) { diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java index a272f1d6ee8bee382fa71a36ba0f2079ed24418e..8516a025b3929591f7e9bf43885e61af042843ed 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java @@ -30,6 +30,7 @@ import org.duniter.core.client.model.bma.BlockchainParameters; import org.duniter.core.client.model.local.Currency; import org.duniter.core.client.model.local.Peer; import org.duniter.core.client.model.local.Wallet; +import org.duniter.core.client.service.exception.BlockNotFoundException; import org.duniter.core.client.service.exception.PubkeyAlreadyUsedException; import org.duniter.core.client.service.exception.UidAlreadyUsedException; import org.duniter.core.client.service.exception.UidMatchAnotherPubkeyException; @@ -71,7 +72,7 @@ public interface BlockchainRemoteService extends Service { * @param number * @return */ - BlockchainBlock getBlock(long currencyId, long number); + BlockchainBlock getBlock(long currencyId, long number) throws BlockNotFoundException; /** * Retrieve the dividend of a block, by id (from 0 to current). @@ -81,7 +82,7 @@ public interface BlockchainRemoteService extends Service { * @param number * @return */ - Long getBlockDividend(long currencyId, long number); + Long getBlockDividend(long currencyId, long number) throws BlockNotFoundException; /** * Retrieve a block, by id (from 0 to current) @@ -90,7 +91,7 @@ public interface BlockchainRemoteService extends Service { * @param number the block number * @return */ - BlockchainBlock getBlock(Peer peer, int number); + BlockchainBlock getBlock(Peer peer, int number) throws BlockNotFoundException; /** * Retrieve a block, by id (from 0 to current) as JSON string @@ -99,7 +100,7 @@ public interface BlockchainRemoteService extends Service { * @param number the block number * @return */ - String getBlockAsJson(Peer peer, int number); + String getBlockAsJson(Peer peer, int number) throws BlockNotFoundException; /** * Retrieve a block, by id (from 0 to current) as JSON string diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java index 3fd751cd93defc0231fa3588d7341c15ca44d93a..490b3548b2bc62095896da73d4c37777d706ae3d 100644 --- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java @@ -32,10 +32,7 @@ import org.duniter.core.client.model.local.Identity; import org.duniter.core.client.model.local.Peer; import org.duniter.core.client.model.local.Wallet; import org.duniter.core.client.service.ServiceLocator; -import org.duniter.core.client.service.exception.HttpBadRequestException; -import org.duniter.core.client.service.exception.PubkeyAlreadyUsedException; -import org.duniter.core.client.service.exception.UidAlreadyUsedException; -import org.duniter.core.client.service.exception.UidMatchAnotherPubkeyException; +import org.duniter.core.client.service.exception.*; import org.duniter.core.exception.TechnicalException; import org.duniter.core.service.CryptoService; import org.duniter.core.util.ObjectUtils; @@ -143,35 +140,51 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement } @Override - public BlockchainBlock getBlock(long currencyId, long number) { - // get blockchain parameter + public BlockchainBlock getBlock(long currencyId, long number) throws BlockNotFoundException { String path = String.format(URL_BLOCK, number); - BlockchainBlock result = executeRequest(currencyId, path, BlockchainBlock.class); - return result; + try { + return executeRequest(currencyId, path, BlockchainBlock.class); + } + catch(HttpNotFoundException e) { + throw new BlockNotFoundException(String.format("Block #%s not found", number)); + } } @Override - public Long getBlockDividend(long currencyId, long number) { - // get blockchain parameter + public Long getBlockDividend(long currencyId, long number) throws BlockNotFoundException { String path = String.format(URL_BLOCK, number); - String json = executeRequest(currencyId, path, String.class); - return getDividendFromBlockJson(json); + try { + String json = executeRequest(currencyId, path, String.class); + return getDividendFromBlockJson(json); + } + catch(HttpNotFoundException e) { + throw new BlockNotFoundException(String.format("Block #%s not found", number)); + } } @Override - public BlockchainBlock getBlock(Peer peer, int number) { - // get blockchain parameter + public BlockchainBlock getBlock(Peer peer, int number) throws BlockNotFoundException { + // Get block from number String path = String.format(URL_BLOCK, number); - BlockchainBlock result = executeRequest(peer, path, BlockchainBlock.class); - return result; + try { + return executeRequest(peer, path, BlockchainBlock.class); + } + catch(HttpNotFoundException e) { + throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer)); + } } @Override public String getBlockAsJson(Peer peer, int number) { // get blockchain parameter String path = String.format(URL_BLOCK, number); - return executeRequest(peer, path, String.class); + try { + return executeRequest(peer, path, String.class); + } + catch(HttpNotFoundException e) { + throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer)); + } } @Override @@ -278,6 +291,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement throw new TechnicalException("Unable to get last UD from server"); } return lastUD.longValue(); + } /** @@ -424,8 +438,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement // search blockchain membership try { - BlockchainMemberships result = executeRequest(currencyId, path, BlockchainMemberships.class); - return result; + return executeRequest(currencyId, path, BlockchainMemberships.class); } catch (HttpBadRequestException e) { log.debug("No member matching this pubkey or uid: " + uidOrPubkey); return null; diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/BlockNotFoundException.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/BlockNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..6d9ec1ec33c3292716522b69d1975102a9648a87 --- /dev/null +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/BlockNotFoundException.java @@ -0,0 +1,49 @@ +package org.duniter.core.client.service.exception; + +/* + * #%L + * UCoin Java :: Core Client API + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import org.duniter.core.exception.BusinessException; + +/** + * Created by eis on 11/02/15. + */ +public class BlockNotFoundException extends BusinessException { + + private static final long serialVersionUID = -5260280401104018980L; + + public BlockNotFoundException() { + super(); + } + + public BlockNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public BlockNotFoundException(String message) { + super(message); + } + + public BlockNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/HttpNotFoundException.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/HttpNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..3aeaaa6f0702fd30934160c74c19a93279de486f --- /dev/null +++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/exception/HttpNotFoundException.java @@ -0,0 +1,49 @@ +package org.duniter.core.client.service.exception; + +/* + * #%L + * UCoin Java :: Core Client API + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import org.duniter.core.exception.BusinessException; + +/** + * Created by eis on 11/02/15. + */ +public class HttpNotFoundException extends BusinessException { + + private static final long serialVersionUID = -5260280401104018980L; + + public HttpNotFoundException() { + super(); + } + + public HttpNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public HttpNotFoundException(String message) { + super(message); + } + + public HttpNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties index 944871b69c621d834800ffc13805b16b8b4d6e39..248b16f292e44931725b5969f49819a380a6fd16 100644 --- a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties +++ b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_en_GB.properties @@ -3,6 +3,7 @@ duniter4j.client.core.connect=Could not connect to Duniter node [%s] duniter4j.client.core.emptyResponse= duniter4j.client.core.invalidResponse= duniter4j.client.core.timeout= +duniter4j.client.notFound=Resource non found [%s] duniter4j.client.status=Http request error\: %s duniter4j.config= duniter4j.config.option.basedir.description= diff --git a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties index 150dd8c9320d407d81893f712dc79ee0b982919f..94c99f6ee34f8adbe9bfbbd48e1b9e1d6d36607f 100644 --- a/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties +++ b/duniter4j-core-client/src/main/resources/i18n/duniter4j-core-client_fr_FR.properties @@ -3,7 +3,8 @@ duniter4j.client.core.connect=Echec de la connection au noeud Duniter [%s] duniter4j.client.core.emptyResponse= duniter4j.client.core.invalidResponse= duniter4j.client.core.timeout= -duniter4j.client.status=Echec de requete HTTP \: %s +duniter4j.client.notFound=Ressource non trouvée [%s] +duniter4j.client.status=Echec de requete HTTP [%s] \: %s duniter4j.config= duniter4j.config.option.basedir.description= duniter4j.config.option.cache.directory.description= diff --git a/duniter4j-core-shared/src/main/java/org/duniter/core/model/NullProgressionModel.java b/duniter4j-core-shared/src/main/java/org/duniter/core/model/NullProgressionModel.java new file mode 100644 index 0000000000000000000000000000000000000000..6eafb6c4596d0b1a0ca1ad85fd1bbb9311e54433 --- /dev/null +++ b/duniter4j-core-shared/src/main/java/org/duniter/core/model/NullProgressionModel.java @@ -0,0 +1,113 @@ +package org.duniter.core.model; + +/* + * #%L + * SIH-Adagio :: Synchro Server WebApp + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.Serializable; + +public class NullProgressionModel implements ProgressionModel, Serializable { + + private static final long serialVersionUID = 1L; + + public NullProgressionModel() { + super(); + } + + @Override + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { + } + + @Override + public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + } + + @Override + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { + } + + @Override + public synchronized String getMessage() { + return null; + } + + @Override + public synchronized void setTask(String task) { + } + + @Override + public synchronized String getTask() { + return null; + } + + @Override + public synchronized void setMessage(String progressionMessage) { + } + + @Override + public synchronized void setTotal(int total) { + } + + @Override + public int getTotal() { + return 0; + } + + @Override + public synchronized void setCurrent(int current) { + } + + @Override + public synchronized int getCurrent() { + return 0; + } + + @Override + public synchronized void increment() {} + + @Override + public synchronized void increment(int increment){} + + @Override + public synchronized void increment(String message) {} + + public boolean isCancel() { + return false; + } + + @Override + public void cancel() {} + + @Override + public synchronized Status getStatus() { + return null; + } + + @Override + public synchronized void setStatus(Status progressionStatus) { + } + +} diff --git a/duniter4j-elasticsearch/pom.xml b/duniter4j-elasticsearch/pom.xml index 201c5b8bf965dd32fe6668a4fb1d2758b66316d6..8473fcda6b98c9777a0bfa879054024fbd04d018 100644 --- a/duniter4j-elasticsearch/pom.xml +++ b/duniter4j-elasticsearch/pom.xml @@ -27,7 +27,7 @@ <duniter4j-elasticsearch.config>${project.basedir}/src/test/resources/duniter4j-elasticsearch-test.properties</duniter4j-elasticsearch.config> <assembly.skip>false</assembly.skip> - <cesium.download.url>https://github.com/duniter/cesium/releases/download/${cesium.version}/cesium-web-${cesium.version}.zip</cesium.download.url> + <cesium.download.url>https://github.com/duniter/cesium/releases/download/v${cesium.version}/cesium-v${cesium.version}-web.zip</cesium.download.url> </properties> <dependencies> @@ -393,7 +393,9 @@ <phase>integration-test</phase> <configuration> <mainClass>org.elasticsearch.bootstrap.Elasticsearch</mainClass> - <arguments>start</arguments> + <arguments> + <argument>start</argument> + </arguments> <includeProjectDependencies>false</includeProjectDependencies> <includePluginDependencies>true</includePluginDependencies> <systemProperties> diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java index 73c9f28828c61d45042be5776da28a9bbb1deff3..c660a140240b0230ea2346329904291616842f6e 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/Plugin.java @@ -25,9 +25,9 @@ package org.duniter.elasticsearch; import com.google.common.collect.Lists; import org.duniter.elasticsearch.action.RestModule; import org.duniter.elasticsearch.node.DuniterNode; -import org.duniter.elasticsearch.threadpool.ThreadPool; import org.duniter.elasticsearch.security.SecurityModule; import org.duniter.elasticsearch.service.ServiceModule; +import org.duniter.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Module; diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java index 1c9d46517ae630cf8fa0c1e34285999dc598691a..9590391789b7eeadd6c7c4b44b293802a72ba436 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/PluginSettings.java @@ -161,6 +161,10 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return settings.getAsInt("duniter.bulk.size", 1000); } + public int getNodeForkResyncWindow() { + return settings.getAsInt("duniter.fork.resync.window", 100); + } + public String getDefaultStringAnalyzer() { return settings.get("duniter.string.analyzer", "english"); } @@ -181,6 +185,14 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return settings.getAsBoolean("duniter.dev.enable", false); } + public int getNodeRetryCount() { + return settings.getAsInt("duniter.retry.count", 5); + } + + public int getNodeRetryWaitDuration() { + return settings.getAsInt("duniter.retry.waitDuration", 5000); + } + public Peer checkAndGetPeer() { if (StringUtils.isBlank(getNodeBmaHost())) { logger.error("ERROR: node host is required"); diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java index b79bda9f63376edc6011ef5ebef48e46142f1538..5220383c2343d76ebfad5c27917241646449a6dd 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/cli/action/IndexerCliAction.java @@ -51,7 +51,7 @@ public class IndexerCliAction { @Override public void handleMessage(String message) { String currencyName = GsonUtils.getValueFromJSONAsString(message, "blockchain"); - *///blockIndexerService.indexBlockAsJson(peer, message, true /*refresh*/, true /*wait*/); + *///blockIndexerService.indexLastBlockFromJson(peer, message, true /*refresh*/, true /*wait*/); //blockIndexerService.indexCurrentBlockAsJson(currencyName, message, true /*wait*/); /* } }); diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java index 4d47e5141b06ff7678ebc3f211e3f819f55a5cb0..f55ff99d9432fe907d50531b23bf972d901c9cd2 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/exception/InvalidFormatException.java @@ -22,7 +22,6 @@ package org.duniter.elasticsearch.exception; * #L% */ -import org.duniter.core.exception.BusinessException; import org.elasticsearch.rest.RestStatus; /** diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java index 80be1d95cea2f3afb2fceae8b4330c6ae52505f7..842a505ff8cdbb5ebce3acbcd21192d0b8ff3a32 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/node/DuniterNode.java @@ -30,9 +30,13 @@ import org.duniter.core.util.websocket.WebsocketClientEndpoint; import org.duniter.elasticsearch.PluginSettings; import org.duniter.elasticsearch.service.*; import org.duniter.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.action.admin.indices.stats.ShardStats; +import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Injector; +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; /** @@ -43,6 +47,7 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> { private final PluginSettings pluginSettings; private final ThreadPool threadPool; private final Injector injector; + private final static ESLogger logger = Loggers.getLogger("node"); @Inject public DuniterNode(Settings settings, PluginSettings pluginSettings, ThreadPool threadPool, final Injector injector) { @@ -50,16 +55,18 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> { this.pluginSettings = pluginSettings; this.threadPool = threadPool; this.injector = injector; - } @Override protected void doStart() { - threadPool.scheduleOnStarted(() -> { + threadPool.scheduleOnClusterHealthStatus(() -> { createIndices(); - synchronize(); - }); + // Waiting cluster back to GREEN or YELLOW state, before synchronize + threadPool.scheduleOnClusterHealthStatus(() -> { + synchronize(); + }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); + }, ClusterHealthStatus.YELLOW, ClusterHealthStatus.GREEN); } @Override @@ -106,7 +113,6 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> { if (logger.isInfoEnabled()) { logger.info("Checking Duniter indices..."); } - injector.getInstance(RegistryService.class).createIndexIfNotExists(); injector.getInstance(MarketService.class).createIndexIfNotExists(); injector.getInstance(MessageService.class).createIndexIfNotExists(); @@ -129,7 +135,7 @@ public class DuniterNode extends AbstractLifecycleComponent<DuniterNode> { // Index blocks (and listen if new block appear) injector.getInstance(BlockchainService.class) - //.indexLastBlocks(peer) + .indexLastBlocks(peer) .listenAndIndexNewBlock(peer); } diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java index 3ffc3aae4aba7e3e5517839bad1df7a015c971da..ab820f0760d1c97daaa325f75e622332d1eaa7f9 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/AbstractService.java @@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableSet; import com.google.gson.JsonSyntaxException; import org.duniter.core.beans.Bean; import org.duniter.core.client.model.elasticsearch.Record; +import org.duniter.core.client.service.exception.HttpBadRequestException; import org.duniter.core.exception.TechnicalException; import org.duniter.core.service.CryptoService; import org.duniter.core.util.StringUtils; @@ -47,16 +48,15 @@ import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.client.Client; import org.elasticsearch.client.Requests; import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.nuiton.i18n.I18n; import java.io.*; import java.util.Objects; import java.util.Set; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -73,21 +73,29 @@ public abstract class AbstractService implements Bean { protected final PluginSettings pluginSettings; protected final ObjectMapper objectMapper; protected final CryptoService cryptoService; + protected final int retryCount; + protected final int retryWaitDuration; - public AbstractService(Client client, PluginSettings pluginSettings, CryptoService cryptoService) { - this.logger = Loggers.getLogger(getClass()); + public AbstractService(String loggerName, Client client, PluginSettings pluginSettings, CryptoService cryptoService) { + this.logger = Loggers.getLogger(loggerName); this.client = client; this.pluginSettings = pluginSettings; this.cryptoService = cryptoService; this.objectMapper = new ObjectMapper(); + this.retryCount = pluginSettings.getNodeRetryCount(); + this.retryWaitDuration = pluginSettings.getNodeRetryWaitDuration(); + } + + public AbstractService(String loggerName, Client client, PluginSettings pluginSettings) { + this(loggerName, client, pluginSettings, null); } public AbstractService(Client client, PluginSettings pluginSettings) { - this.logger = Loggers.getLogger(getClass()); - this.client = client; - this.pluginSettings = pluginSettings; - this.cryptoService = null; - this.objectMapper = new ObjectMapper(); + this(client, pluginSettings, null); + } + + public AbstractService(Client client, PluginSettings pluginSettings, CryptoService cryptoService) { + this("duniter", client, pluginSettings, cryptoService); } /* -- protected methods -- */ @@ -368,4 +376,37 @@ public abstract class AbstractService implements Bean { return line; } } + + protected <T> T executeWithRetry(RetryFunction<T> retryFunction) throws TechnicalException{ + int retry = 0; + while (retry < retryCount) { + try { + return retryFunction.execute(); + } catch (TechnicalException e) { + retry++; + + if (retry == retryCount) { + throw e; + } + + if (logger.isDebugEnabled()) { + logger.debug(I18n.t("duniter4j.removeServiceUtils.waitThenRetry", e.getMessage(), retry, retryCount)); + } + + try { + Thread.sleep(retryWaitDuration); // waiting + } catch (InterruptedException e2) { + throw new TechnicalException(e2); + } + } + } + + throw new TechnicalException("Error while trying to execute a function with retry"); + } + + public interface RetryFunction<T> { + + T execute() throws TechnicalException; + } + } diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java index 590d18a6061c8c261bdb2e63f8ed4204f6277ee2..a847e4780a166cdd8a215d619e529a2eb0c7043c 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java @@ -35,16 +35,18 @@ import org.duniter.core.client.model.bma.gson.JsonAttributeParser; import org.duniter.core.client.model.local.Peer; import org.duniter.core.client.service.bma.BlockchainRemoteService; import org.duniter.core.client.service.bma.NetworkRemoteService; +import org.duniter.core.client.service.exception.BlockNotFoundException; import org.duniter.core.client.service.exception.HttpBadRequestException; import org.duniter.core.client.service.exception.JsonSyntaxException; import org.duniter.core.exception.TechnicalException; +import org.duniter.core.model.NullProgressionModel; import org.duniter.core.model.ProgressionModel; import org.duniter.core.model.ProgressionModelImpl; import org.duniter.core.util.CollectionUtils; import org.duniter.core.util.ObjectUtils; import org.duniter.core.util.StringUtils; import org.duniter.elasticsearch.PluginSettings; -import org.duniter.elasticsearch.exception.*; +import org.duniter.elasticsearch.exception.DuplicateIndexIdException; import org.duniter.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; @@ -57,6 +59,7 @@ import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -83,18 +86,25 @@ public class BlockchainService extends AbstractService { private static final int SYNC_MISSING_BLOCK_MAX_RETRY = 5; + private final ProgressionModel nullProgressionModel = new NullProgressionModel(); + private BlockchainRemoteService blockchainRemoteService; private RegistryService registryService; + private ThreadPool threadPool; private JsonAttributeParser blockNumberParser = new JsonAttributeParser("number"); private JsonAttributeParser blockCurrencyParser = new JsonAttributeParser("currency"); + private JsonAttributeParser blockHashParser = new JsonAttributeParser("hash"); + private JsonAttributeParser blockPreviousHashParser = new JsonAttributeParser("previousHash"); private Gson gson; @Inject - public BlockchainService(Client client, PluginSettings settings, ThreadPool threadPool, final ServiceLocator serviceLocator){ - super(client, settings); + public BlockchainService(Client client, PluginSettings settings, ThreadPool threadPool, + final ServiceLocator serviceLocator){ + super("duniter.blockchain", client, settings); this.gson = GsonUtils.newBuilder().create(); + this.threadPool = threadPool; threadPool.scheduleOnStarted(() -> { blockchainRemoteService = serviceLocator.getBlockchainRemoteService(); }); @@ -107,17 +117,14 @@ public class BlockchainService extends AbstractService { public BlockchainService listenAndIndexNewBlock(Peer peer){ blockchainRemoteService.addNewBlockListener(peer, message -> { - indexBlockAsJson(peer, message, true /*refresh*/, true /*wait*/); - - // Update the current block - indexCurrentBlockAsJson(message, false /*wait*/); - + indexLastBlockFromJson(peer, message); }); return this; } public BlockchainService indexLastBlocks(Peer peer) { - return indexLastBlocks(peer, new ProgressionModelImpl()); + indexLastBlocks(peer, nullProgressionModel); + return this; } public BlockchainService indexLastBlocks(Peer peer, ProgressionModel progressionModel) { @@ -132,15 +139,13 @@ public class BlockchainService extends AbstractService { BlockchainParameters parameter = blockchainRemoteService.getParameters(peer); if (parameter == null) { progressionModel.setStatus(ProgressionModel.Status.FAILED); - logger.error(String.format("Could not connect to node [%s]", - peer.getUrl())); + logger.error(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.remoteParametersError",peer)); return this; } String currencyName = parameter.getCurrency(); - progressionModel.setTask(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", currencyName, peer.getHost(), peer.getPort())); - logger.info(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", - currencyName, pluginSettings.getNodeBmaHost(), pluginSettings.getNodeBmaPort())); + progressionModel.setTask(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", currencyName, peer)); + logger.info(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.task", currencyName, peer)); // Create index blockchain if need if (!registryService.isCurrencyExists(currencyName)) { @@ -148,63 +153,80 @@ public class BlockchainService extends AbstractService { } // Check if index exists - createIndexIfNotExists(currencyName); + createIndexIfNotExists(currencyName, true/*wait cluster health*/); // Then index all blocks - BlockchainBlock currentBlock = blockchainRemoteService.getCurrentBlock(peer); - - if (currentBlock != null) { - int maxBlockNumber = currentBlock.getNumber(); + BlockchainBlock peerCurrentBlock = blockchainRemoteService.getCurrentBlock(peer); - // DEV mode - if (pluginSettings.isDevMode() && maxBlockNumber > 5000) { - maxBlockNumber = 5000; - } + if (peerCurrentBlock != null) { + final int peerCurrentBlockNumber = peerCurrentBlock.getNumber(); // Get the last indexed block number int startNumber = 0; - int currentBlockNumber = -1; + // Check if a previous sync has been done BlockchainBlock indexedCurrentBlock = getCurrentBlock(currencyName); if (indexedCurrentBlock != null && indexedCurrentBlock.getNumber() != null) { - currentBlockNumber = indexedCurrentBlock.getNumber(); + int indexedCurrentBlockNumber = indexedCurrentBlock.getNumber(); - // Previous block could have been not indexed : so start at the max(number) - indexedCurrentBlock = getBlockById(currencyName, currentBlockNumber); - // If exists on blockchain, so can use it + // Make sure this block has been indexed by its number (not only with _id='current') + indexedCurrentBlock = getBlockById(currencyName, indexedCurrentBlockNumber); + + // If current block exists on index, by _id=number AND _id=current + // then keep it and sync only next blocks if (indexedCurrentBlock != null) { - startNumber = currentBlockNumber + 1; + startNumber = indexedCurrentBlockNumber + 1; } } - // Before to start at '0' (first block), try to use the max(number) + // When current block not found, + // try to use the max(number), because block with _id='current' may not has been indexed if (startNumber <= 1 ){ startNumber = getMaxBlockNumber(currencyName) + 1; } - if (startNumber <= maxBlockNumber) { + // If some block has been already indexed: detect and resolve fork + if (startNumber > 0) { + String peerStartPreviousHash; + try { + BlockchainBlock peerStartBlock = blockchainRemoteService.getBlock(peer, startNumber - 1); + peerStartPreviousHash = peerStartBlock.getHash(); + } + catch(BlockNotFoundException e) { + // block not exists: use a fake hash for fork detection (will force to compare previous blocks) + peerStartPreviousHash = "--"; + } + boolean resolved = detectAndResolveFork(peer, currencyName, peerStartPreviousHash, startNumber - 1); + if (!resolved) { + // Bad blockchain ! skipping sync + logger.error(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain", currencyName, peer)); + return this; + } + } + + if (startNumber <= peerCurrentBlockNumber) { Collection<String> missingBlocks = bulkIndex - ? indexBlocksUsingBulk(peer, currencyName, startNumber, maxBlockNumber, progressionModel) - : indexBlocksNoBulk(peer, currencyName, startNumber, maxBlockNumber, progressionModel); + ? indexBlocksUsingBulk(peer, currencyName, startNumber, peerCurrentBlockNumber, progressionModel) + : indexBlocksNoBulk(peer, currencyName, startNumber, peerCurrentBlockNumber, progressionModel); // If some blocks are missing, try to get it using other peers if (CollectionUtils.isNotEmpty(missingBlocks)) { progressionModel.setTask(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task", currencyName)); - missingBlocks = indexMissingBlocksFromOtherPeers(peer, currentBlock, missingBlocks, 1); + missingBlocks = indexMissingBlocksFromOtherPeers(peer, peerCurrentBlock, missingBlocks, 1); } if (CollectionUtils.isEmpty(missingBlocks)) { - logger.info(String.format("All blocks indexed [%s ms]", (System.currentTimeMillis() - timeStart))); + logger.info(I18n.t("duniter4j.blockIndexerService.indexLastBlocks.succeed", currencyName, peer, (System.currentTimeMillis() - timeStart))); progressionModel.setStatus(ProgressionModel.Status.SUCCESS); } else { - logger.warn(String.format("Could not indexed all blocks. Missing %s blocks.", missingBlocks.size())); + logger.warn(String.format("[%s] [%s] Could not indexed all blocks. Missing %s blocks.", currencyName, peer, missingBlocks.size())); progressionModel.setStatus(ProgressionModel.Status.FAILED); } } else { if (logger.isDebugEnabled()) { - logger.debug(String.format("Current block from peer [%s] is #%s. Index is up to date.", peer.getUrl(), maxBlockNumber)); + logger.debug(String.format("[%s] [%s] Already up to date at block #%s.", currencyName, peer, peerCurrentBlockNumber)); } progressionModel.setStatus(ProgressionModel.Status.SUCCESS); } @@ -226,9 +248,14 @@ public class BlockchainService extends AbstractService { return super.existsIndex(currencyName); } - public BlockchainService createIndexIfNotExists(String currencyName) { + public BlockchainService createIndexIfNotExists(String currencyName, boolean waitClusterHealth) { if (!existsIndex(currencyName)) { createIndex(currencyName); + + // when wait cluster state + if (waitClusterHealth) { + threadPool.waitClusterHealthStatus(ClusterHealthStatus.GREEN, ClusterHealthStatus.YELLOW); + } } return this; } @@ -344,7 +371,7 @@ public class BlockchainService extends AbstractService { * @param number the block number * @param json block as JSON */ - public void indexBlockAsJson(String currencyName, int number, byte[] json, boolean refresh, boolean wait) { + public BlockchainService indexBlockFromJson(String currencyName, int number, byte[] json, boolean refresh, boolean wait) { ObjectUtils.checkNotNull(json); ObjectUtils.checkArgument(json.length > 0); @@ -361,26 +388,54 @@ public class BlockchainService extends AbstractService { else { indexRequest.execute().actionGet(); } + + return this; + } + + /** + * Index the given block, as the last (current) block. This will check is a fork has occur, and apply a rollback so. + * @param peer a source peer + * @param json block as json + */ + public BlockchainService indexLastBlockFromJson(Peer peer, String json) { + ObjectUtils.checkNotNull(json); + ObjectUtils.checkArgument(json.length() > 0); + + indexBlockFromJson(peer, json, true /*refresh*/, true /*is current*/, true/*check fork*/, true/*wait*/); + + return this; } /** * * @param json block as json - * @param refresh is a existing block ? + * @param refresh Could be an existing block ? * @param wait need to wait until processed ? */ - public void indexBlockAsJson(Peer peer, String json, boolean refresh, boolean wait) { + public BlockchainService indexBlockFromJson(Peer peer, String json, boolean refresh, boolean isCurrent, boolean detectFork, boolean wait) { ObjectUtils.checkNotNull(json); ObjectUtils.checkArgument(json.length() > 0); String currencyName = blockCurrencyParser.getValueAsString(json); int number = blockNumberParser.getValueAsInt(json); + String hash = blockHashParser.getValueAsString(json); - logger.info(I18n.t("duniter4j.blockIndexerService.indexBlock", currencyName, peer, number)); + logger.info(I18n.t("duniter4j.blockIndexerService.indexBlock", currencyName, peer, number, hash)); if (logger.isTraceEnabled()) { logger.trace(json); } + // Detecting fork and rollback is necessary + if (detectFork) { + String previousHash = blockPreviousHashParser.getValueAsString(json); + boolean resolved = detectAndResolveFork(peer, currencyName, previousHash, number - 1); + if (!resolved) { + // Bad blockchain ! Skipping block indexation + logger.error(I18n.t("duniter4j.blockIndexerService.detectFork.invalidBlockchain", currencyName, peer, number, hash)); + return this; + } + } + // Preparing indexBlocksFromNode IndexRequestBuilder indexRequest = client.prepareIndex(currencyName, BLOCK_TYPE) .setId(String.valueOf(number)) @@ -394,6 +449,13 @@ public class BlockchainService extends AbstractService { else { indexRequest.execute().actionGet(); } + + // Update current + if (isCurrent) { + indexCurrentBlockFromJson(currencyName, json, true /*wait*/); + } + + return this; } /** @@ -410,29 +472,16 @@ public class BlockchainService extends AbstractService { // WARN: must use GSON, to have same JSON result (e.g identities and joiners field must be converted into String) String json = gson.toJson(currentBlock); - indexCurrentBlockAsJson(currentBlock.getCurrency(), json, wait); + indexCurrentBlockFromJson(currentBlock.getCurrency(), json, wait); } - /** - * - * @param currentBlockJson block as JSON - * @pram wait need to wait until block processed ? - */ - public void indexCurrentBlockAsJson(String json, boolean wait) { - ObjectUtils.checkNotNull(json); - ObjectUtils.checkArgument(json.length() > 0); - - String currencyName = blockCurrencyParser.getValueAsString(json); - - indexCurrentBlockAsJson(currencyName, json, wait); - } /** * * @param currencyName - * @param currentBlockJson block as JSON + * @param json block as JSON * @pram wait need to wait until block processed ? */ - public void indexCurrentBlockAsJson(String currencyName, String json, boolean wait) { + public void indexCurrentBlockFromJson(String currencyName, String json, boolean wait) { ObjectUtils.checkNotNull(json); ObjectUtils.checkArgument(json.length() > 0); ObjectUtils.checkArgument(StringUtils.isNotBlank(currencyName)); @@ -554,6 +603,11 @@ public class BlockchainService extends AbstractService { .field("type", "string") .endObject() + // previous hash + .startObject("previousHash") + .field("type", "string") + .endObject() + // membercount .startObject("memberCount") .field("type", "integer") @@ -597,13 +651,13 @@ public class BlockchainService extends AbstractService { // Execute query try { SearchResponse searchResponse = searchRequest.execute().actionGet(); - List<BlockchainBlock> currencies = toBlocks(searchResponse, false); - if (CollectionUtils.isEmpty(currencies)) { + List<BlockchainBlock> blocks = toBlocks(searchResponse, false); + if (CollectionUtils.isEmpty(blocks)) { return null; } // Return the unique result - return CollectionUtils.extractSingleton(currencies); + return CollectionUtils.extractSingleton(blocks); } catch(JsonSyntaxException e) { throw new TechnicalException(String.format("Error while getting indexed block #%s for blockchain [%s]", blockId, currencyName), e); @@ -670,12 +724,12 @@ public class BlockchainService extends AbstractService { try { String blockAsJson = blockchainRemoteService.getBlockAsJson(peer, curNumber); - indexBlockAsJson(currencyName, curNumber, blockAsJson.getBytes(), false, true /*wait*/); + indexBlockFromJson(currencyName, curNumber, blockAsJson.getBytes(), false, true /*wait*/); // If last block if (curNumber == lastNumber - 1) { // update the current block - indexCurrentBlockAsJson(currencyName, blockAsJson, true /*wait*/); + indexCurrentBlockFromJson(currencyName, blockAsJson, true /*wait*/); } } catch(Throwable t) { @@ -707,10 +761,11 @@ public class BlockchainService extends AbstractService { String[] blocksAsJson = null; try { - blocksAsJson = blockchainRemoteService.getBlocksAsJson(peer, batchSize, batchFirstNumber); - } catch(HttpBadRequestException e) { + final int batchFirstNumberFinal = batchFirstNumber; + blocksAsJson = executeWithRetry(()->blockchainRemoteService.getBlocksAsJson(peer, batchSize, batchFirstNumberFinal)); + } catch(TechnicalException e) { if (logger.isDebugEnabled()) { - logger.debug(String.format("Error while getting blocks from #%s (count=%s): %s. Skipping blocks.", batchFirstNumber, batchSize, e.getMessage())); + logger.debug(String.format("[%s] [%s] Error while getting blocks from #%s (count=%s): %s. Skipping blocks.",currencyName, peer, batchFirstNumber, batchSize, e.getMessage())); } } @@ -778,11 +833,11 @@ public class BlockchainService extends AbstractService { // Report progress reportIndexBlocksProgress(progressionModel, currencyName, peer, firstNumber, lastNumber, batchFirstNumber); - + batchFirstNumber++; // increment for next loop } if (StringUtils.isNotBlank(currentBlockJson)) { - indexCurrentBlockAsJson(currencyName, currentBlockJson, false); + indexCurrentBlockFromJson(currencyName, currentBlockJson, false); } return missingBlockNumbers; @@ -860,7 +915,7 @@ public class BlockchainService extends AbstractService { } // Index the missing block - indexBlockAsJson(currencyName, blockNumber, blockAsJson.getBytes(), false, true/*wait*/); + indexBlockFromJson(currencyName, blockNumber, blockAsJson.getBytes(), false, true/*wait*/); // Remove this block number from the final missing list newMissingBlocks.remove(blockNumber); @@ -922,4 +977,104 @@ public class BlockchainService extends AbstractService { } } + + protected boolean isBlockIndexed(String currencyName, int number, String hash) { + // Check if previous block exists + BlockchainBlock block = getBlockByIdStr(currencyName, String.valueOf(number)); + boolean blockExists = block != null; + if (!blockExists) { + return blockExists; + } + return block.getHash() != null && block.getHash().equals(hash); + } + + protected boolean detectAndResolveFork(Peer peer, final String currencyName, final String hash, final int number){ + int forkResyncWindow = pluginSettings.getNodeForkResyncWindow(); + String forkOriginHash = hash; + int forkOriginNumber = number; + boolean sameBlockIndexed = isBlockIndexed(currencyName, forkOriginNumber, forkOriginHash); + while (!sameBlockIndexed && forkOriginNumber > 0) { + + if (!sameBlockIndexed && logger.isInfoEnabled()) { + logger.info(I18n.t("duniter4j.blockIndexerService.detectFork.invalidBlock", currencyName, peer, forkOriginNumber, forkOriginHash)); + } + forkOriginNumber -= forkResyncWindow; + if (forkOriginNumber < 0) { + forkOriginNumber = 0; + } + + // Get remote block (with auto-retry) + try { + final int currentNumberFinal = forkOriginNumber; + String testBlock = executeWithRetry(() -> + blockchainRemoteService.getBlockAsJson(peer, currentNumberFinal)); + forkOriginHash = blockHashParser.getValueAsString(testBlock); + + // Check is exists on ES index + sameBlockIndexed = isBlockIndexed(currencyName, forkOriginNumber, forkOriginHash); + } catch (TechnicalException e) { + logger.warn(I18n.t("duniter4j.blockIndexerService.detectFork.remoteBlockNotFound", currencyName, peer, forkOriginNumber, e.getMessage())); + sameBlockIndexed = false; // continue (go back again) + } + } + + if (!sameBlockIndexed) { + return false; // sync could not be done (bad blockchain: no common blocks !) + } + + if (forkOriginNumber < number) { + logger.info(I18n.t("duniter4j.blockIndexerService.detectFork.resync", currencyName, peer, forkOriginNumber)); + // Remove some previous block + deleteBlocksFromNumber(currencyName, forkOriginNumber/*from*/, number+forkResyncWindow/*to*/); + + // Re-indexing blocks + indexBlocksUsingBulk(peer, currencyName, forkOriginNumber/*from*/, number, nullProgressionModel); + } + + return true; // sync OK + } + + /** + * Delete blocks from a start number (using bulk) + * @param currencyName + * @param fromNumber + */ + protected void deleteBlocksFromNumber(String currencyName, int fromNumber, int toNumber) { + + int bulkSize = pluginSettings.getIndexBulkSize(); + + BulkRequestBuilder bulkRequest = client.prepareBulk(); + for (int i=fromNumber; i<=toNumber; i++) { + + bulkRequest.add( + client.prepareDelete(currencyName, BLOCK_TYPE, String.valueOf(i)) + ); + + // Flush the bulk if not empty + if ((fromNumber - i % bulkSize) == 0) { + flushDeleteBulk(bulkRequest); + bulkRequest = client.prepareBulk(); + } + } + + // last flush + flushDeleteBulk(bulkRequest); + } + + protected void flushDeleteBulk(BulkRequestBuilder bulkRequest) { + if (bulkRequest.numberOfActions() > 0) { + BulkResponse bulkResponse = bulkRequest.get(); + // If failures, continue but save missing blocks + if (bulkResponse.hasFailures()) { + // process failures by iterating through each bulk response item + for (BulkItemResponse itemResponse : bulkResponse) { + boolean skip = !itemResponse.isFailed(); + if (!skip) { + int itemNumber = Integer.parseInt(itemResponse.getId()); + logger.debug(String.format("Error while deleting block #%s: %s. Skipping this deletion.", itemNumber, itemResponse.getFailureMessage())); + } + } + } + } + } } diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java index 3995e2d363af61909b90ef9d72124339db02c605..06e9b37ac67eaed43b1d3e67d416bad5fbb3fe5e 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/HistoryService.java @@ -50,7 +50,7 @@ public class HistoryService extends AbstractService { @Inject public HistoryService(Client client, PluginSettings settings, CryptoService cryptoService) { - super(client, settings, cryptoService); + super("gchange." + INDEX, client, settings, cryptoService); } /** diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java index 67d50dd9f321fb030ced759b169d9b5fad3051ec..08a8e0ac569e7b14f2d974d466ffd3a1c48e4e27 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MarketService.java @@ -56,7 +56,7 @@ public class MarketService extends AbstractService { @Inject public MarketService(Client client, PluginSettings settings, CryptoService cryptoService, WotRemoteService wotRemoteService) { - super(client, settings, cryptoService); + super("gchange." + INDEX, client, settings, cryptoService); this.wotRemoteService = wotRemoteService; } diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java index b201a228bd43874bec311dc55ebb3510d1e3c53d..632702c8a65ece046693d472979cac25d369b308 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/MessageService.java @@ -59,7 +59,7 @@ public class MessageService extends AbstractService { @Inject public MessageService(Client client, PluginSettings settings, CryptoService cryptoService) { - super(client, settings, cryptoService); + super("gchange." + INDEX, client, settings, cryptoService); } /** diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java index a12c15b24e96d3093ac6b86236bbacfae2aa00a5..826c7efe2e39f95c84e7b8b5714cf02bb646a50d 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/RegistryService.java @@ -87,7 +87,7 @@ public class RegistryService extends AbstractService { WotRemoteService wotRemoteService, CryptoService cryptoService, BlockchainRemoteService blockchainRemoteService) { - super(client, settings, cryptoService); + super("gchange." + INDEX, client, settings, cryptoService); gson = GsonUtils.newBuilder().create(); this.blockchainRemoteService = blockchainRemoteService; } diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java index 8dd1a7c9db1a4721a9af84d7c1f91975429b0d65..0342ebce2a0e090180bb8ee8d488e1d2ac3cb561 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/ServiceModule.java @@ -25,18 +25,15 @@ package org.duniter.elasticsearch.service; import org.duniter.core.beans.Bean; import org.duniter.core.client.dao.CurrencyDao; import org.duniter.core.client.dao.PeerDao; -import org.duniter.core.client.dao.mem.MemoryCurrencyDaoImpl; -import org.duniter.core.client.dao.mem.MemoryPeerDaoImpl; import org.duniter.core.client.service.DataContext; import org.duniter.core.client.service.HttpService; -import org.duniter.core.client.service.HttpServiceImpl; -import org.duniter.core.client.service.bma.*; +import org.duniter.core.client.service.bma.BlockchainRemoteService; +import org.duniter.core.client.service.bma.NetworkRemoteService; +import org.duniter.core.client.service.bma.TransactionRemoteService; +import org.duniter.core.client.service.bma.WotRemoteService; import org.duniter.core.client.service.local.CurrencyService; -import org.duniter.core.client.service.local.CurrencyServiceImpl; import org.duniter.core.client.service.local.PeerService; -import org.duniter.core.client.service.local.PeerServiceImpl; import org.duniter.core.service.CryptoService; -import org.duniter.core.service.Ed25519CryptoServiceImpl; import org.duniter.elasticsearch.PluginSettings; import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Module; @@ -66,6 +63,7 @@ public class ServiceModule extends AbstractModule implements Module { bindWithLocator(CurrencyDao.class); bindWithLocator(PeerDao.class); bindWithLocator(DataContext.class); + /* bindWithLocator(BlockchainRemoteServiceImpl.class); bindWithLocator(NetworkRemoteServiceImpl.class); diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java index 37fa19ca51e49c467e9925a269d72a1cb5c76c73..0a8086b902f802ac6b4227641984eef4df1f0de6 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/service/UserService.java @@ -55,7 +55,7 @@ public class UserService extends AbstractService { public UserService(Client client, PluginSettings settings, CryptoService cryptoService) { - super(client, settings,cryptoService); + super("gchange." + INDEX, client, settings,cryptoService); } /** diff --git a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java index 8ca23af5a9d97c078bd550878a6800cd50b939b4..b024cbc0d1e1dffe5ff41e47597f77044f1785d1 100644 --- a/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java +++ b/duniter4j-elasticsearch/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java @@ -22,23 +22,28 @@ package org.duniter.elasticsearch.threadpool; * #L% */ +import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import org.elasticsearch.action.admin.cluster.stats.ClusterStatsRequestBuilder; +import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Injector; +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.EsAbortPolicy; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.transport.TransportService; +import org.nuiton.i18n.I18n; import java.util.List; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; /** * Manage thread pool, to execute tasks asynchronously. @@ -48,6 +53,7 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> { private ScheduledThreadPoolExecutor scheduler = null; private Injector injector; + private ESLogger logger = Loggers.getLogger("threadpool"); private final List<Runnable> afterStartedCommands; @@ -94,16 +100,30 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> { /** * Schedules an action when node is started (all services and modules ready) * - * @param command the action to take + * @param job the action to execute when node started * @return a ScheduledFuture who's get will return when the task is complete and throw an exception if it is canceled */ - public void scheduleOnStarted(Runnable command) { - /*if (lifecycle.state() == Lifecycle.State.INITIALIZED ) { - afterStartedCommands.add(command); - } - else {*/ - scheduleAfterServiceState(TransportService.class, Lifecycle.State.STARTED, command); - // } + public void scheduleOnStarted(Runnable job) { + Preconditions.checkNotNull(job); + scheduleAfterServiceState(TransportService.class, Lifecycle.State.STARTED, job); + } + + /** + * Schedules an action when cluster is ready + * + * @param job the action to execute + * @param expectedStatus expected health status, to run the job + * @return a ScheduledFuture who's get will return when the task is complete and throw an exception if it is canceled + */ + public void scheduleOnClusterHealthStatus(Runnable job, ClusterHealthStatus... expectedStatus) { + Preconditions.checkNotNull(job); + + scheduleOnStarted(() -> { + if (waitClusterHealthStatus(expectedStatus)) { + // continue + job.run(); + } + }); } /** @@ -131,7 +151,13 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> { /* -- protected methods -- */ - protected <T extends LifecycleComponent<T>> ScheduledFuture<?> scheduleAfterServiceState(Class<T> waitingServiceClass, final Lifecycle.State waitingState, final Runnable job) { + protected <T extends LifecycleComponent<T>> ScheduledFuture<?> scheduleAfterServiceState(Class<T> waitingServiceClass, + final Lifecycle.State waitingState, + final Runnable job) { + Preconditions.checkNotNull(waitingServiceClass); + Preconditions.checkNotNull(waitingState); + Preconditions.checkNotNull(job); + final T service = injector.getInstance(waitingServiceClass); return schedule(() -> { while(service.lifecycleState() != waitingState) { @@ -147,94 +173,39 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> { }, TimeValue.timeValueSeconds(10)); } + public boolean waitClusterHealthStatus(ClusterHealthStatus... expectedStatus) { + Preconditions.checkNotNull(expectedStatus); + Preconditions.checkArgument(expectedStatus.length > 0); - /*public void resetAllData() { - //resetAllCurrencies(); - //resetDataBlocks(); - //resetMarketRecords(); - //resetRegistry(); - } - - public void resetAllCurrencies() { - currencyRegistryService.deleteAllCurrencies(); - } - - public void resetDataBlocks() { - BlockchainRemoteService blockchainService = serviceLocator.getBlockchainRemoteService(); - Peer peer = checkConfigAndGetPeer(pluginSettings); - - try { - // Get the blockchain name from node - BlockchainParameters parameter = blockchainService.getParameters(peer); - if (parameter == null) { - logger.error(String.format("Could not connect to node [%s:%s]", - pluginSettings.getNodeBmaHost(), pluginSettings.getNodeBmaPort())); - return; - } - String currencyName = parameter.getCurrency(); - - logger.info(String.format("Reset data for index [%s]", currencyName)); - - // Delete then create index on blockchain - boolean indexExists = blockBlockchainService.existsIndex(currencyName); - if (indexExists) { - blockBlockchainService.deleteIndex(currencyName); - blockBlockchainService.createIndex(currencyName); + Client client = injector.getInstance(Client.class); + ClusterStatsRequestBuilder statsRequest = client.admin().cluster().prepareClusterStats(); + ClusterStatsResponse stats = null; + boolean canContinue = false; + boolean firstTry = true; + while (!canContinue) { + try { + if (stats != null) Thread.sleep(100); // wait 100 ms + stats = statsRequest.execute().get(); + for (ClusterHealthStatus status: expectedStatus) { + if (stats.getStatus() == status) { + if (!firstTry && logger.isDebugEnabled()) { + logger.debug(I18n.t("duniter4j.threadPool.clusterHealthStatus.changed", status.name())); + } + canContinue = true; + break; + } + } + firstTry = false; + } catch (ExecutionException e) { + // Continue + } catch (InterruptedException e) { + return false; // stop } - - - logger.info(String.format("Successfully reset data for index [%s]", currencyName)); - } catch(Exception e) { - logger.error("Error during reset data: " + e.getMessage(), e); } - } - public void resetMarketRecords() { - try { - // Delete then create index on records - boolean indexExists = recordMarketService.existsIndex(); - if (indexExists) { - recordMarketService.deleteIndex(); - } - logger.info(String.format("Successfully reset market records")); - - categoryMarketService.createIndex(); - categoryMarketService.initCategories(); - logger.info(String.format("Successfully re-initialized market categories data")); - - } catch(Exception e) { - logger.error("Error during reset market records: " + e.getMessage(), e); - } + return canContinue; } - public void resetRegistry() { - try { - // Delete then create index on records - if (recordRegistryService.existsIndex()) { - recordRegistryService.deleteIndex(); - } - recordRegistryService.createIndex(); - logger.info(String.format("Successfully reset registry records")); - - - if (categoryRegistryService.existsIndex()) { - categoryRegistryService.deleteIndex(); - } - categoryRegistryService.createIndex(); - categoryRegistryService.initCategories(); - logger.info(String.format("Successfully re-initialized registry categories")); - - if (citiesRegistryService.existsIndex()) { - citiesRegistryService.deleteIndex(); - } - citiesRegistryService.initCities(); - logger.info(String.format("Successfully re-initialized registry cities")); - - } catch(Exception e) { - logger.error("Error during reset registry records: " + e.getMessage(), e); - } - }*/ - /* -- internal methods -- */ class LoggingRunnable implements Runnable { diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties index f1e0263f4b085ee3026df8d9c68b3f971767f435..a6067b359c9b1b3288467e75f3b34faaa2ce093d 100644 --- a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties +++ b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_en_GB.properties @@ -1,9 +1,16 @@ duniter4j-elasticsearch.config= -duniter4j.blockIndexerService.indexBlock= -duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task= -duniter4j.blockIndexerService.indexLastBlocks.progress= -duniter4j.blockIndexerService.indexLastBlocks.stopped= -duniter4j.blockIndexerService.indexLastBlocks.task= +duniter4j.blockIndexerService.detectFork.invalidBlock=[%s] [%s] Detecting fork\: block \#%s -> new hash [%s] +duniter4j.blockIndexerService.detectFork.invalidBlockchain=[%s] [%s] Peer has another blockchain (no common blocks \!). Skipping block \#%s - hash [%s]. +duniter4j.blockIndexerService.detectFork.remoteBlockNotFound=[%s] [%s] Unable to get block \#%s from peer\: %s +duniter4j.blockIndexerService.detectFork.resync=[%s] [%s] Rollback index from block \#%s, and resync +duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s - hash [%s] +duniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain= +duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers +duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)... +duniter4j.blockIndexerService.indexLastBlocks.remoteParametersError=[%s] Error when calling [/blockchain/parameters]\: %s +duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped +duniter4j.blockIndexerService.indexLastBlocks.succeed=[%s] [%s] All blocks indexed [%s ms] +duniter4j.blockIndexerService.indexLastBlocks.task=[%s] [%s] Indexing last blocks... duniter4j.config.option.basedir.description= duniter4j.config.option.data.directory.description= duniter4j.config.option.elasticsearch.bulk.enable.description= @@ -31,5 +38,7 @@ duniter4j.executor.task.waitingExecution= duniter4j.job.stopped= duniter4j.job.stopping= duniter4j.job.success= -duniter4j.task.issuer.system= -duniter4j.task.starting= +duniter4j.removeServiceUtils.waitThenRetry= +duniter4j.task.issuer.system=System +duniter4j.task.starting=Starting task... +duniter4j.threadPool.clusterHealthStatus.changed= diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties index f1e0263f4b085ee3026df8d9c68b3f971767f435..1ed787a11c6d3a2ab895f504f3a0940cdd8bc226 100644 --- a/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties +++ b/duniter4j-elasticsearch/src/main/resources/i18n/duniter4j-elasticsearch_fr_FR.properties @@ -1,9 +1,16 @@ duniter4j-elasticsearch.config= -duniter4j.blockIndexerService.indexBlock= -duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task= -duniter4j.blockIndexerService.indexLastBlocks.progress= -duniter4j.blockIndexerService.indexLastBlocks.stopped= -duniter4j.blockIndexerService.indexLastBlocks.task= +duniter4j.blockIndexerService.detectFork.invalidBlock=[%s] [%s] Detecting fork\: block \#%s -> new hash [%s] +duniter4j.blockIndexerService.detectFork.invalidBlockchain=[%s] [%s] Peer has another blockchain (no common blocks \!). Skipping block \#%s - hash [%s]. +duniter4j.blockIndexerService.detectFork.remoteBlockNotFound=[%s] [%s] Unable to get block \#%s from peer\: %s +duniter4j.blockIndexerService.detectFork.resync=[%s] [%s] Rollback index from block \#%s, and resync +duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s - hash [%s] +duniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain= +duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers +duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)... +duniter4j.blockIndexerService.indexLastBlocks.remoteParametersError=[%s] Error when calling [/blockchain/parameters]\: %s +duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped +duniter4j.blockIndexerService.indexLastBlocks.succeed=[%s] [%s] All blocks indexed [%s ms] +duniter4j.blockIndexerService.indexLastBlocks.task=[%s] [%s] Indexing last blocks... duniter4j.config.option.basedir.description= duniter4j.config.option.data.directory.description= duniter4j.config.option.elasticsearch.bulk.enable.description= @@ -31,5 +38,8 @@ duniter4j.executor.task.waitingExecution= duniter4j.job.stopped= duniter4j.job.stopping= duniter4j.job.success= -duniter4j.task.issuer.system= -duniter4j.task.starting= +duniter4j.removeServiceUtils.waitThenRetry=Remote request failed [%s]. Waiting then retry [%s/%s]... +duniter4j.task.issuer.system=Système +duniter4j.task.starting=Démarrage du traitement... +duniter4j.threadPool.clusterHealthStatus.changed=Cluster health status changed to [%s]. Executing pending job... +uniter4j.blockIndexerService.indexLastBlocks.invalidBlockchain=[%s] [%s] Peer has another blockchain (no common blocks \!). Skipping last blocks indexation. diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_en_GB.properties b/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_en_GB.properties deleted file mode 100644 index 77a2c0aec9ea89542b8ee93664c4e0ae9b67298e..0000000000000000000000000000000000000000 --- a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_en_GB.properties +++ /dev/null @@ -1,51 +0,0 @@ -duniter4j-elasticsearch.config= -duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s -duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers -duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)... -duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped -duniter4j.blockIndexerService.indexLastBlocks.task=Indexing last blocks of [%s] from peer [%s\:%s]... -duniter4j.config.option.basedir.description= -duniter4j.config.option.cache.directory.description= -duniter4j.config.option.data.directory.description= -duniter4j.config.option.elasticsearch.bulk.enable.description= -duniter4j.config.option.elasticsearch.bulk.size.description= -duniter4j.config.option.elasticsearch.cluster.name.description= -duniter4j.config.option.elasticsearch.embedded.enable.description= -duniter4j.config.option.elasticsearch.host.description= -duniter4j.config.option.elasticsearch.local.description= -duniter4j.config.option.i18n.directory.description= -duniter4j.config.option.i18n.locale.description= -duniter4j.config.option.index.parallel_processing.description= -duniter4j.config.option.node.elasticsearch.cluster.name.description= -duniter4j.config.option.node.elasticsearch.clusterName.description= -duniter4j.config.option.node.elasticsearch.embeddeb.description= -duniter4j.config.option.node.elasticsearch.embeddeb.http.description= -duniter4j.config.option.node.elasticsearch.embeddeb.local.description= -duniter4j.config.option.node.elasticsearch.embedded.enable.description= -duniter4j.config.option.node.elasticsearch.embedded.http.enable.description= -duniter4j.config.option.node.elasticsearch.embedded.local.description= -duniter4j.config.option.node.elasticsearch.host.description= -duniter4j.config.option.node.elasticsearch.http.enable.description= -duniter4j.config.option.node.elasticsearch.local.clusterName.description= -duniter4j.config.option.node.elasticsearch.local.description= -duniter4j.config.option.node.elasticsearch.port.description= -duniter4j.config.option.node.elasticsearch.protocol.description= -duniter4j.config.option.node.elasticsearch.rest.host.description= -duniter4j.config.option.node.elasticsearch.rest.port.description= -duniter4j.config.option.node.elasticsearch.rest.protocol.description= -duniter4j.config.option.node.elasticsearch.rest.url.description= -duniter4j.config.option.node.host.description= -duniter4j.config.option.node.port.description= -duniter4j.config.option.node.protocol.description= -duniter4j.config.option.plugins.directory.description= -duniter4j.config.option.taskExecutor.queueCapacity.description= -duniter4j.config.option.tasks.queueCapacity.description= -duniter4j.config.option.tmp.directory.description= -duniter4j.config.option.version.description= -duniter4j.config.parse.error= -duniter4j.executor.task.waitingExecution= -duniter4j.job.stopped= -duniter4j.job.stopping= -duniter4j.job.success= -duniter4j.task.issuer.system=System -duniter4j.task.starting=Starting task... diff --git a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_fr_FR.properties b/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_fr_FR.properties deleted file mode 100644 index 9a9c287b5aa7adc634d189df50b6c1c0c63c3236..0000000000000000000000000000000000000000 --- a/duniter4j-elasticsearch/src/main/resources/i18n/ucoinj-elasticsearch_fr_FR.properties +++ /dev/null @@ -1,51 +0,0 @@ -duniter4j-elasticsearch.config= -duniter4j.blockIndexerService.indexBlock=[%s] [%s] Indexing block \#%s -duniter4j.blockIndexerService.indexLastBlocks.otherPeers.task=Indexing missing blocks of [%s] from other peers -duniter4j.blockIndexerService.indexLastBlocks.progress=[%s] [%s] Indexing block \#%s / %s (%s%%)... -duniter4j.blockIndexerService.indexLastBlocks.stopped=[%s] [%s] Indexing last block - stopped -duniter4j.blockIndexerService.indexLastBlocks.task=Indexing last blocks of [%s] from peer [%s\:%s]... -duniter4j.config.option.basedir.description= -duniter4j.config.option.cache.directory.description= -duniter4j.config.option.data.directory.description= -duniter4j.config.option.elasticsearch.bulk.enable.description= -duniter4j.config.option.elasticsearch.bulk.size.description= -duniter4j.config.option.elasticsearch.cluster.name.description= -duniter4j.config.option.elasticsearch.embedded.enable.description= -duniter4j.config.option.elasticsearch.host.description= -duniter4j.config.option.elasticsearch.local.description= -duniter4j.config.option.i18n.directory.description= -duniter4j.config.option.i18n.locale.description= -duniter4j.config.option.index.parallel_processing.description= -duniter4j.config.option.node.elasticsearch.cluster.name.description= -duniter4j.config.option.node.elasticsearch.clusterName.description= -duniter4j.config.option.node.elasticsearch.embeddeb.description= -duniter4j.config.option.node.elasticsearch.embeddeb.http.description= -duniter4j.config.option.node.elasticsearch.embeddeb.local.description= -duniter4j.config.option.node.elasticsearch.embedded.enable.description= -duniter4j.config.option.node.elasticsearch.embedded.http.enable.description= -duniter4j.config.option.node.elasticsearch.embedded.local.description= -duniter4j.config.option.node.elasticsearch.host.description= -duniter4j.config.option.node.elasticsearch.http.enable.description= -duniter4j.config.option.node.elasticsearch.local.clusterName.description= -duniter4j.config.option.node.elasticsearch.local.description= -duniter4j.config.option.node.elasticsearch.port.description= -duniter4j.config.option.node.elasticsearch.protocol.description= -duniter4j.config.option.node.elasticsearch.rest.host.description= -duniter4j.config.option.node.elasticsearch.rest.port.description= -duniter4j.config.option.node.elasticsearch.rest.protocol.description= -duniter4j.config.option.node.elasticsearch.rest.url.description= -duniter4j.config.option.node.host.description= -duniter4j.config.option.node.port.description= -duniter4j.config.option.node.protocol.description= -duniter4j.config.option.plugins.directory.description= -duniter4j.config.option.taskExecutor.queueCapacity.description= -duniter4j.config.option.tasks.queueCapacity.description= -duniter4j.config.option.tmp.directory.description= -duniter4j.config.option.version.description= -duniter4j.config.parse.error= -duniter4j.executor.task.waitingExecution= -duniter4j.job.stopped= -duniter4j.job.stopping= -duniter4j.job.success= -duniter4j.task.issuer.system=Système -duniter4j.task.starting=Démarrage du traitement... diff --git a/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml b/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml index 54ccf34ddf381f34abc31f327276c0870a52a7e4..c72e3748928a8ab471ab4e3700c57deebb90ff84 100644 --- a/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml +++ b/duniter4j-elasticsearch/src/test/es-home/config/elasticsearch.yml @@ -15,13 +15,13 @@ # Use a descriptive name for your cluster: # # cluster.name: my-application -cluster.name: duniter4j-elasticsearch +cluster.name: duniter4j-elasticsearch-TEST # # ------------------------------------ Node ------------------------------------ # # Use a descriptive name for the node: # -# node.name: node-1 +node.name: EIS-DEV # # Add custom attributes to the node: # @@ -53,13 +53,13 @@ cluster.name: duniter4j-elasticsearch # Set the bind address to a specific IP (IPv4 or IPv6): # # network.host: 192.168.0.1 -#network.host: 192.168.0.28 +network.host: 192.168.0.28 # # Set a custom port for HTTP: # # http.port: 9200 -#http.port: 9200 +http.port: 9203 http.cors.allow-origin: "/.*/" http.cors.enabled: true @@ -73,7 +73,7 @@ http.cors.enabled: true # Pass an initial list of hosts to perform discovery when new node is started: # The default list of hosts is ["127.0.0.1", "[::1]"] # -# discovery.zen.ping.unicast.hosts: ["host1", "host2"] +discovery.zen.ping.unicast.hosts: ["192.168.0.5", "192.168.0.28"] #discovery.zen.ping.unicast.hosts: ["127.0.0.1", ""] # # Prevent the "split brain" by configuring the majority of nodes (total number of nodes / 2 + 1): @@ -100,7 +100,7 @@ http.cors.enabled: true # # Require explicit names when deleting indices: # -# action.destructive_requires_name: true +action.destructive_requires_name: true security.manager.enabled: false @@ -111,6 +111,8 @@ security.manager.enabled: false duniter.host: 192.168.0.5 duniter.port: 9201 +#duniter.host: 192.168.0.28 +#duniter.port: 9202 duniter.string.analyzer: french diff --git a/pom.xml b/pom.xml index 963d3a2141a60c2a3ada8b0671b906c3ed046b00..b4a8415175100b7f8db3edb41b0be696469272bd 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ <jna.version>4.1.0</jna.version> <tyrus.version>1.12</tyrus.version> - <cesium.version>0.2.1</cesium.version> + <cesium.version>0.2.12</cesium.version> <nuitonConfigVersion>3.0-rc-4</nuitonConfigVersion> <nuitonI18nVersion>3.5</nuitonI18nVersion>