Skip to content

Commit

Permalink
Replace axios with native fetch
Browse files Browse the repository at this point in the history
Fixes stupid maxContentLength error on aborted requests (axios/axios#4806)
  • Loading branch information
Jalle19 committed Aug 8, 2024
1 parent bc5f2a2 commit 5c85f85
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 126 deletions.
91 changes: 0 additions & 91 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
},
"dependencies": {
"@influxdata/influxdb-client": "^1.33.2",
"axios": "^1.6.0",
"modbus-serial": "^8.0.16",
"mqtt": "^5.1.2",
"slugify": "^1.6.6",
Expand Down
24 changes: 14 additions & 10 deletions src/http/client.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import axios, { AxiosResponse } from 'axios'
import http from 'http'
import { createLogger } from '../logger'

const logger = createLogger('http')

const httpClient = axios.create({
// We keep polling the same hosts over and over so keep-alive is essential
httpAgent: new http.Agent({ keepAlive: true }),
})

let requestTimeout = 0
let lastTimestamp = 0
const promiseCache = new Map()

const createRequestParams = (): RequestInit => {
return {
// We keep polling the same hosts over and over so keep-alive is essential
keepalive: true,
// Use the configured timeout
signal: AbortSignal.timeout(requestTimeout),
}
}

export const setRequestTimeout = (timeoutMs: number) => {
httpClient.defaults.timeout = timeoutMs
requestTimeout = timeoutMs
logger.info(`Using ${timeoutMs} millisecond timeout for HTTP requests`)
}

export const getDedupedResponse = async (timestamp: number, url: string): Promise<AxiosResponse> => {
export const getDedupedResponse = async (timestamp: number, url: string): Promise<Response> => {
// Clear the cache whenever the timestamp changes
if (timestamp !== lastTimestamp) {
lastTimestamp = timestamp
Expand All @@ -30,7 +33,8 @@ export const getDedupedResponse = async (timestamp: number, url: string): Promis
return promiseCache.get(key)
}

const promise = httpClient.get(url)
const request = new Request(url, createRequestParams())
const promise = fetch(request)
promiseCache.set(key, promise)

return promise
Expand Down
12 changes: 6 additions & 6 deletions src/sensor/iotawatt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ export const getSensorData: PowerSensorPollFunction = async (
const sensor = circuit.sensor as IotawattSensor

try {
const configurationResult = await getDedupedResponse(timestamp, getConfigurationUrl(sensor))
const configuration = configurationResult.data as IotawattConfiguration
const statusResult = await getDedupedResponse(timestamp, getStatusUrl(sensor))
const status = statusResult.data as IotawattStatus
const configurationResult = (await getDedupedResponse(timestamp, getConfigurationUrl(sensor))).clone()
const configuration = (await configurationResult.json()) as IotawattConfiguration
const statusResult = (await getDedupedResponse(timestamp, getStatusUrl(sensor))).clone()
const status = (await statusResult.json()) as IotawattStatus

return {
timestamp: timestamp,
Expand All @@ -142,8 +142,8 @@ export const getCharacteristicsSensorData: CharacteristicsSensorPollFunction = a
const sensor = characteristics.sensor as IotawattCharacteristicsSensor

try {
const queryResult = await getDedupedResponse(timestamp, getQueryUrl(sensor))
const query = queryResult.data as IotawattCharacteristicsQuery
const queryResult = (await getDedupedResponse(timestamp, getQueryUrl(sensor))).clone()
const query = (await queryResult.json()) as IotawattCharacteristicsQuery

return {
timestamp: timestamp,
Expand Down
31 changes: 21 additions & 10 deletions src/sensor/shelly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
} from '../sensor'
import { Circuit } from '../circuit'
import { getDedupedResponse } from '../http/client'
import { AxiosResponse } from 'axios'
import { Characteristics } from '../characteristics'
import { createLogger } from '../logger'

Expand Down Expand Up @@ -66,9 +65,13 @@ const getSensorDataUrl = (sensor: ShellySensor | ShellyCharacteristicsSensor): s
}
}

const parseGen1Response = (timestamp: number, circuit: Circuit, httpResponse: AxiosResponse): PowerSensorData => {
const parseGen1Response = async (
timestamp: number,
circuit: Circuit,
httpResponse: Response,
): Promise<PowerSensorData> => {
const sensor = circuit.sensor as ShellySensor
const data = httpResponse.data as Gen1StatusResult
const data = (await httpResponse.json()) as Gen1StatusResult

return {
timestamp: timestamp,
Expand All @@ -77,8 +80,12 @@ const parseGen1Response = (timestamp: number, circuit: Circuit, httpResponse: Ax
}
}

const parseGen2PMResponse = (timestamp: number, circuit: Circuit, httpResponse: AxiosResponse): PowerSensorData => {
const data = httpResponse.data as Gen2SwitchGetStatusResult
const parseGen2PMResponse = async (
timestamp: number,
circuit: Circuit,
httpResponse: Response,
): Promise<PowerSensorData> => {
const data = (await httpResponse.json()) as Gen2SwitchGetStatusResult

return {
timestamp: timestamp,
Expand All @@ -87,9 +94,13 @@ const parseGen2PMResponse = (timestamp: number, circuit: Circuit, httpResponse:
}
}

const parseGen2EMResponse = (timestamp: number, circuit: Circuit, httpResponse: AxiosResponse): PowerSensorData => {
const parseGen2EMResponse = async (
timestamp: number,
circuit: Circuit,
httpResponse: Response,
): Promise<PowerSensorData> => {
const sensor = circuit.sensor as ShellySensor
const data = httpResponse.data as Gen2EMGetStatusResult
const data = (await httpResponse.json()) as Gen2EMGetStatusResult

let power = 0
let apparentPower = 0
Expand Down Expand Up @@ -129,7 +140,7 @@ export const getSensorData: PowerSensorPollFunction = async (
const url = getSensorDataUrl(sensor)

try {
const httpResponse = await getDedupedResponse(timestamp, url)
const httpResponse = (await getDedupedResponse(timestamp, url)).clone()

// Parse the response differently depending on what type of Shelly we're dealing with
switch (sensor.shelly.type as ShellyType) {
Expand Down Expand Up @@ -159,8 +170,8 @@ export const getCharacteristicsSensorData: CharacteristicsSensorPollFunction = a
}

try {
const httpResponse = await getDedupedResponse(timestamp, url)
const data = httpResponse.data as Gen2EMGetStatusResult
const httpResponse = (await getDedupedResponse(timestamp, url)).clone()
const data = (await httpResponse.json()) as Gen2EMGetStatusResult

let voltage = 0
let frequency = 0
Expand Down
14 changes: 6 additions & 8 deletions tests/sensor/shelly.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,22 @@ const gen2pmResponse = fs.readFileSync('./tests/sensor/shelly-plus-1pm.Switch.Ge

// Mock getDedupedResponse calls to return real-world data
jest.mock('../../src/http/client', () => ({
getDedupedResponse: (timestamp: number, url: string) => {
let contents
getDedupedResponse: async (timestamp: number, url: string) => {
let contents: string | null = null

switch (url) {
case 'http://127.0.0.1/status':
contents = gen1Response
contents = String(gen1Response)
break
case 'http://127.0.0.1/rpc/EM.GetStatus?id=0':
contents = gen2emResponse
contents = String(gen2emResponse)
break
case 'http://127.0.0.1/rpc/Switch.GetStatus?id=0':
contents = gen2pmResponse
contents = String(gen2pmResponse)
break
}

return {
data: JSON.parse(String(contents)),
}
return Promise.resolve(new Response(contents))
},
}))

Expand Down

0 comments on commit 5c85f85

Please sign in to comment.