Skip to content

Commit

Permalink
refactor connections rate, per minute not second
Browse files Browse the repository at this point in the history
  • Loading branch information
paulo-ocean committed Dec 6, 2024
1 parent f822742 commit ab2283e
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export INDEXER_INTERVAL=
export ALLOWED_ADMINS=
export DASHBOARD=true
export RATE_DENY_LIST=
export MAX_REQ_PER_SECOND=
export MAX_REQ_PER_MINUTE=
export MAX_CHECKSUM_LENGTH=
export LOG_LEVEL=
export HTTP_API_PORT=
Expand Down
2 changes: 1 addition & 1 deletion docs/dockerDeployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ services:
# INDEXER_INTERVAL: ''
DASHBOARD: 'true'
# RATE_DENY_LIST: ''
# MAX_REQ_PER_SECOND: ''
# MAX_REQ_PER_MINUTE: ''
# MAX_CHECKSUM_LENGTH: ''
# LOG_LEVEL: ''
HTTP_API_PORT: '8000'
Expand Down
2 changes: 1 addition & 1 deletion docs/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Environmental variables are also tracked in `ENVIRONMENT_VARIABLES` within `src/
- `ALLOWED_ADMINS`: Sets the public address of accounts which have access to admin endpoints e.g. shutting down the node. Example: `"[\"0x967da4048cD07aB37855c090aAF366e4ce1b9F48\",\"0x388C818CA8B9251b393131C08a736A67ccB19297\"]"`
- `DASHBOARD`: If `false` the dashboard will not run. If not set or `true` the dashboard will start with the node. Example: `false`
- `RATE_DENY_LIST`: Blocked list of IPs and peer IDs. Example: `"{ \"peers\": [\"16Uiu2HAkuYfgjXoGcSSLSpRPD6XtUgV71t5RqmTmcqdbmrWY9MJo\"], \"ips\": [\"127.0.0.1\"] }"`
- `MAX_REQ_PER_SECOND`: Number of requests per second allowed by the same client. Example: `3`
- `MAX_REQ_PER_MINUTE`: Number of requests per minute allowed by the same client. Example: `30`
- `MAX_CHECKSUM_LENGTH`: Define the maximum length for a file if checksum is required (Mb). Example: `10`
- `IS_BOOTSTRAP`: Is this node to be used as bootstrap node or not. Default is `false`.

Expand Down
2 changes: 1 addition & 1 deletion scripts/ocean-node-quickstart.sh
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ services:
# INDEXER_INTERVAL: ''
DASHBOARD: 'true'
# RATE_DENY_LIST: ''
# MAX_REQ_PER_SECOND: ''
# MAX_REQ_PER_MINUTE: ''
# MAX_CHECKSUM_LENGTH: ''
# LOG_LEVEL: ''
HTTP_API_PORT: '$HTTP_API_PORT'
Expand Down
16 changes: 8 additions & 8 deletions src/components/core/handler/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export abstract class Handler implements ICommandHandler {

// TODO LOG, implement all handlers
async checkRateLimit(): Promise<boolean> {
const ratePerSecond = (await getConfiguration()).rateLimit
const ratePerMinute = (await getConfiguration()).rateLimit
const caller: string | string[] = this.getOceanNode().getRemoteCaller()
const requestTime = new Date().getTime()
let isOK = true
Expand All @@ -49,7 +49,7 @@ export abstract class Handler implements ICommandHandler {
const updatedRequestData = self.checkRequestData(
remoteCaller,
requestTime,
ratePerSecond
ratePerMinute
)
isOK = updatedRequestData.valid
self.requestMap.set(remoteCaller, updatedRequestData.updatedRequestData)
Expand Down Expand Up @@ -105,18 +105,18 @@ export abstract class Handler implements ICommandHandler {
/**
* Checks if the request is within the rate limit defined
* @param remote remote endpoint (ip or peer identifier)
* @param ratePerSecond number of calls per second allowed
* @param ratePerMinute number of calls per minute allowed (per ip or peer identifier)
* @returns updated request data
*/
checkRequestData(
remote: string,
currentTime: number,
ratePerSecond: number
ratePerMinute: number
): RequestDataCheck {
const requestData: RequestLimiter = this.requestMap.get(remote)
const diffSeconds = (currentTime - requestData.lastRequestTime) / 1000
// more than 1 sec difference means no problem
if (diffSeconds >= 1) {
const diffMinutes = ((currentTime - requestData.lastRequestTime) / 1000) * 60
// more than 1 minute difference means no problem
if (diffMinutes >= 1) {
// its fine
requestData.lastRequestTime = currentTime
requestData.numRequests = 1
Expand All @@ -128,7 +128,7 @@ export abstract class Handler implements ICommandHandler {
// requests in the same interval of 1 second
requestData.numRequests++
return {
valid: requestData.numRequests <= ratePerSecond,
valid: requestData.numRequests <= ratePerMinute,
updatedRequestData: requestData
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/test/unit/networking.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
DEFAULT_RATE_LIMIT_PER_SECOND,
DEFAULT_RATE_LIMIT_PER_MINUTE,
ENVIRONMENT_VARIABLES,
PROTOCOL_COMMANDS,
getConfiguration
Expand Down Expand Up @@ -105,7 +105,7 @@ describe('Test rate limitations and deny list defaults', () => {
// const node: OceanNode = OceanNode.getInstance()
before(async () => {
envOverrides = buildEnvOverrideConfig(
[ENVIRONMENT_VARIABLES.RATE_DENY_LIST, ENVIRONMENT_VARIABLES.MAX_REQ_PER_SECOND],
[ENVIRONMENT_VARIABLES.RATE_DENY_LIST, ENVIRONMENT_VARIABLES.MAX_REQ_PER_MINUTE],
[undefined, undefined]
)
await setupEnvironment(null, envOverrides)
Expand All @@ -115,7 +115,7 @@ describe('Test rate limitations and deny list defaults', () => {
const config = await getConfiguration(true)
expect(config.denyList.ips).to.be.length(0)
expect(config.denyList.peers).to.be.length(0)
expect(config.rateLimit).to.be.equal(DEFAULT_RATE_LIMIT_PER_SECOND)
expect(config.rateLimit).to.be.equal(DEFAULT_RATE_LIMIT_PER_MINUTE)
})

// put it back
Expand All @@ -132,7 +132,7 @@ describe('Test rate limitations and deny list settings', () => {
[
ENVIRONMENT_VARIABLES.PRIVATE_KEY,
ENVIRONMENT_VARIABLES.RATE_DENY_LIST,
ENVIRONMENT_VARIABLES.MAX_REQ_PER_SECOND
ENVIRONMENT_VARIABLES.MAX_REQ_PER_MINUTE
],
[
'0xcb345bd2b11264d523ddaf383094e2675c420a17511c3102a53817f13474a7ff',
Expand Down
18 changes: 9 additions & 9 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { C2DClusterType } from '../@types/C2D.js'
import { createFromPrivKey } from '@libp2p/peer-id-factory'
import { keys } from '@libp2p/crypto'
import {
DEFAULT_RATE_LIMIT_PER_SECOND,
DEFAULT_RATE_LIMIT_PER_MINUTE,
ENVIRONMENT_VARIABLES,
EnvVariable,
hexStringToByteArray
Expand Down Expand Up @@ -428,19 +428,19 @@ function logMissingVariableWithDefault(envVariable: EnvVariable) {
}
// have a rate limit for handler calls
function getRateLimit(isStartup: boolean = false) {
if (!existsEnvironmentVariable(ENVIRONMENT_VARIABLES.MAX_REQ_PER_SECOND)) {
if (!existsEnvironmentVariable(ENVIRONMENT_VARIABLES.MAX_REQ_PER_MINUTE)) {
if (isStartup) {
logMissingVariableWithDefault(ENVIRONMENT_VARIABLES.MAX_REQ_PER_SECOND)
logMissingVariableWithDefault(ENVIRONMENT_VARIABLES.MAX_REQ_PER_MINUTE)
}
return DEFAULT_RATE_LIMIT_PER_SECOND
return DEFAULT_RATE_LIMIT_PER_MINUTE
} else {
try {
return getIntEnvValue(process.env.MAX_REQ_PER_SECOND, DEFAULT_RATE_LIMIT_PER_SECOND)
return getIntEnvValue(process.env.MAX_REQ_PER_MINUTE, DEFAULT_RATE_LIMIT_PER_MINUTE)
} catch (err) {
CONFIG_LOGGER.error(
`Invalid "${ENVIRONMENT_VARIABLES.MAX_REQ_PER_SECOND.name}" env variable...`
`Invalid "${ENVIRONMENT_VARIABLES.MAX_REQ_PER_MINUTE.name}" env variable...`
)
return DEFAULT_RATE_LIMIT_PER_SECOND
return DEFAULT_RATE_LIMIT_PER_MINUTE
}
}
}
Expand Down Expand Up @@ -549,7 +549,7 @@ async function getEnvConfig(isStartup?: boolean): Promise<OceanNodeConfig> {
),
dhtMaxInboundStreams: getIntEnvValue(process.env.P2P_dhtMaxInboundStreams, 500),
dhtMaxOutboundStreams: getIntEnvValue(process.env.P2P_dhtMaxOutboundStreams, 500),
enableDHTServer: getBoolEnvValue(process.env.P2P_ENABLE_DHT_SERVER, false),
enableDHTServer: getBoolEnvValue('P2P_ENABLE_DHT_SERVER', false),
mDNSInterval: getIntEnvValue(process.env.P2P_mDNSInterval, 20e3), // 20 seconds
connectionsMaxParallelDials: getIntEnvValue(
process.env.P2P_connectionsMaxParallelDials,
Expand Down Expand Up @@ -617,7 +617,7 @@ async function getEnvConfig(isStartup?: boolean): Promise<OceanNodeConfig> {
isStartup,
knownUnsafeURLs
),
isBootstrap: getBoolEnvValue(process.env.IS_BOOTSTRAP, false)
isBootstrap: getBoolEnvValue('IS_BOOTSTRAP', false)
}

if (!previousConfiguration) {
Expand Down
14 changes: 8 additions & 6 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,10 @@ export const ENVIRONMENT_VARIABLES: Record<any, EnvVariable> = {
value: process.env.DASHBOARD,
required: false
},
MAX_REQ_PER_SECOND: {
// rate limit per second
name: 'MAX_REQ_PER_SECOND',
value: process.env.MAX_REQ_PER_SECOND,
MAX_REQ_PER_MINUTE: {
// rate limit per minute
name: 'MAX_REQ_PER_MINUTE',
value: process.env.MAX_REQ_PER_MINUTE,
required: false
},
RATE_DENY_LIST: {
Expand Down Expand Up @@ -325,8 +325,10 @@ export const ENVIRONMENT_VARIABLES: Record<any, EnvVariable> = {
}
}

// default to 3 requests per second (configurable)
export const DEFAULT_RATE_LIMIT_PER_SECOND = 3
// default to 30 requests per minute (configurable), per ip/peer
export const DEFAULT_RATE_LIMIT_PER_MINUTE = 30
// max connections per minute (configurable), all connections
export const DEFAULT_INCOMING_CONNECTIONS_PER_MINUTE = 60 * 2 // 120 requests per minute
// Typesense's maximum limit to send 250 hits at a time
export const TYPESENSE_HITS_CAP = 250
export const DDO_IDENTIFIER_PREFIX = 'did:op:'
Expand Down

0 comments on commit ab2283e

Please sign in to comment.