-
Notifications
You must be signed in to change notification settings - Fork 1
feat(api): optimize and harden HTTP/JSON-RPC API layer #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
746abf9
0fe5d6f
0980488
5080779
508cf88
29be3db
7e966c9
88b7f26
5b67bf6
ac05ea8
4c6df2d
3d41716
f200e1f
f4f7412
db91a72
a437574
0fdf579
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,11 @@ | |
| import com.google.common.base.Strings; | ||
| import io.prometheus.client.Histogram; | ||
| import java.io.IOException; | ||
| import java.lang.reflect.Constructor; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import javax.annotation.PostConstruct; | ||
| import javax.servlet.ServletException; | ||
| import javax.servlet.http.HttpServlet; | ||
|
|
@@ -31,56 +35,66 @@ | |
| @Slf4j | ||
| public abstract class RateLimiterServlet extends HttpServlet { | ||
| private static final String KEY_PREFIX_HTTP = "http_"; | ||
| private static final String ADAPTER_PREFIX = "org.tron.core.services.ratelimiter.adapter."; | ||
|
|
||
| static final Map<String, Class<? extends IRateLimiter>> ALLOWED_ADAPTERS; | ||
| static final String DEFAULT_ADAPTER_NAME = DefaultBaseQqsAdapter.class.getSimpleName(); | ||
|
|
||
| static { | ||
| List<Class<? extends IRateLimiter>> adapters = Arrays.asList( | ||
| GlobalPreemptibleAdapter.class, | ||
| QpsRateLimiterAdapter.class, | ||
| IPQPSRateLimiterAdapter.class, | ||
| DefaultBaseQqsAdapter.class); | ||
| Map<String, Class<? extends IRateLimiter>> m = new HashMap<>(); | ||
| for (Class<? extends IRateLimiter> c : adapters) { | ||
| m.put(c.getSimpleName(), c); | ||
| } | ||
| ALLOWED_ADAPTERS = Collections.unmodifiableMap(m); | ||
| } | ||
|
|
||
| @Autowired | ||
| private RateLimiterContainer container; | ||
|
|
||
| @PostConstruct | ||
| private void addRateContainer() { | ||
| RateLimiterInitialization.HttpRateLimiterItem item = Args.getInstance() | ||
| .getRateLimiterInitialization().getHttpMap().get(getClass().getSimpleName()); | ||
| boolean success = false; | ||
| final String name = getClass().getSimpleName(); | ||
| if (item != null) { | ||
| String cName = ""; | ||
| String params = ""; | ||
| Object obj; | ||
| try { | ||
| cName = item.getStrategy(); | ||
| params = item.getParams(); | ||
| // add the specific rate limiter strategy of servlet. | ||
| Class<?> c = Class.forName(ADAPTER_PREFIX + cName); | ||
| Constructor constructor; | ||
| if (c == GlobalPreemptibleAdapter.class || c == QpsRateLimiterAdapter.class | ||
| || c == IPQPSRateLimiterAdapter.class) { | ||
| constructor = c.getConstructor(String.class); | ||
| obj = constructor.newInstance(params); | ||
| container.add(KEY_PREFIX_HTTP, name, (IRateLimiter) obj); | ||
| } else { | ||
| constructor = c.getConstructor(); | ||
| obj = constructor.newInstance(QpsStrategy.DEFAULT_QPS_PARAM); | ||
| container.add(KEY_PREFIX_HTTP, name, (IRateLimiter) obj); | ||
| } | ||
| success = true; | ||
| } catch (Exception e) { | ||
| this.throwTronError(cName, params, name, e); | ||
| } | ||
| RateLimiterInitialization.HttpRateLimiterItem item = Args.getInstance() | ||
| .getRateLimiterInitialization().getHttpMap().get(name); | ||
|
|
||
| String cName; | ||
| String params; | ||
| if (item == null) { | ||
| cName = DEFAULT_ADAPTER_NAME; | ||
| params = QpsStrategy.DEFAULT_QPS_PARAM; | ||
| } else { | ||
| cName = item.getStrategy(); | ||
| params = item.getParams(); | ||
| } | ||
| if (!success) { | ||
| // if the specific rate limiter strategy of servlet is not defined or fail to add, | ||
| // then add a default Strategy. | ||
| try { | ||
| IRateLimiter rateLimiter = new DefaultBaseQqsAdapter(QpsStrategy.DEFAULT_QPS_PARAM); | ||
| container.add(KEY_PREFIX_HTTP, name, rateLimiter); | ||
| } catch (Exception e) { | ||
| this.throwTronError("DefaultBaseQqsAdapter", QpsStrategy.DEFAULT_QPS_PARAM, name, e); | ||
| } | ||
|
|
||
| try { | ||
| container.add(KEY_PREFIX_HTTP, name, buildAdapter(cName, params, name)); | ||
| } catch (Exception e) { | ||
| throw throwTronError(cName, params, name, e); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Adapter instantiation failures now throw instead of falling back to the default limiter, reducing fault tolerance for misconfigured params. Prompt for AI agents |
||
| } | ||
| } | ||
|
|
||
| static IRateLimiter buildAdapter(String cName, String params, String name) { | ||
| Class<? extends IRateLimiter> c = ALLOWED_ADAPTERS.get(cName); | ||
| if (c == null) { | ||
| throw throwTronError(cName, params, name, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Unknown adapter names now throw Prompt for AI agents |
||
| new IllegalArgumentException("unknown rate limiter adapter; allowed=" | ||
| + ALLOWED_ADAPTERS.keySet())); | ||
| } | ||
| try { | ||
| return c.getConstructor(String.class).newInstance(params); | ||
| } catch (Exception e) { | ||
| throw throwTronError(cName, params, name, e); | ||
| } | ||
| } | ||
|
|
||
| private void throwTronError(String strategy, String params, String servlet, Exception e) { | ||
| throw new TronError("failure to add the rate limiter strategy. servlet = " + servlet | ||
| private static TronError throwTronError(String strategy, String params, String servlet, | ||
| Exception e) { | ||
| return new TronError("failure to add the rate limiter strategy. servlet = " + servlet | ||
| + ", strategy name = " + strategy + ", params = \"" + params + "\".", | ||
| e, TronError.ErrCode.RATE_LIMITER_INIT); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -95,7 +95,7 @@ public static String printErrorMsg(Exception e) { | |||||||||||||||||
|
|
||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Handle Prompt for AI agents
Suggested change
|
||||||||||||||||||
| public static String printBlockList(BlockList list, boolean selfType) { | ||||||||||||||||||
| List<Block> blocks = list.getBlockList(); | ||||||||||||||||||
| JSONObject jsonObject = JSONObject.parseObject(JsonFormat.printToString(list, selfType)); | ||||||||||||||||||
| JSONObject jsonObject = new JSONObject(); | ||||||||||||||||||
| JSONArray jsonArray = new JSONArray(); | ||||||||||||||||||
| blocks.stream().forEach(block -> jsonArray.add(printBlockToJSON(block, selfType))); | ||||||||||||||||||
| jsonObject.put("block", jsonArray); | ||||||||||||||||||
|
|
@@ -110,8 +110,10 @@ public static String printBlock(Block block, boolean selfType) { | |||||||||||||||||
| public static JSONObject printBlockToJSON(Block block, boolean selfType) { | ||||||||||||||||||
| BlockCapsule blockCapsule = new BlockCapsule(block); | ||||||||||||||||||
| String blockID = ByteArray.toHexString(blockCapsule.getBlockId().getBytes()); | ||||||||||||||||||
| JSONObject jsonObject = JSONObject.parseObject(JsonFormat.printToString(block, selfType)); | ||||||||||||||||||
| JSONObject jsonObject = new JSONObject(); | ||||||||||||||||||
| jsonObject.put("blockID", blockID); | ||||||||||||||||||
| jsonObject.put("block_header", | ||||||||||||||||||
| JSONObject.parseObject(JsonFormat.printToString(block.getBlockHeader(), selfType))); | ||||||||||||||||||
| if (!blockCapsule.getTransactions().isEmpty()) { | ||||||||||||||||||
| jsonObject.put("transactions", | ||||||||||||||||||
| printTransactionListToJSON(blockCapsule.getTransactions(), selfType)); | ||||||||||||||||||
|
|
||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2:
strategy/paramsno longer default when empty, so partially configured rate-limiter entries can now fail servlet initialization.Prompt for AI agents