Skip to content

Commit

Permalink
Merge pull request #86 from Jalle19/response-cloning
Browse files Browse the repository at this point in the history
Dedupe response bodies instead of responses
  • Loading branch information
Jalle19 authored Dec 8, 2024
2 parents 4463405 + abf7842 commit 38664d7
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 57 deletions.
13 changes: 9 additions & 4 deletions src/http/client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { createLogger } from '../logger'

const logger = createLogger('http')
type BodyPromise = Promise<string>

const logger = createLogger('http')
let requestTimeout = 0
let lastTimestamp = 0
const promiseCache = new Map<string, Promise<Response>>()
const promiseCache = new Map<string, BodyPromise>()

const createRequestParams = (): RequestInit => {
return {
Expand All @@ -20,7 +21,11 @@ export const setRequestTimeout = (timeoutMs: number) => {
logger.info(`Using ${timeoutMs} millisecond timeout for HTTP requests`)
}

export const getDedupedResponse = async (timestamp: number, url: string): Promise<Response> => {
const resolveBody = async (request: Request): BodyPromise => {
return (await fetch(request)).text()
}

export const getDedupedResponseBody = async (timestamp: number, url: string): BodyPromise => {
// Clear the cache whenever the timestamp changes
if (timestamp !== lastTimestamp) {
lastTimestamp = timestamp
Expand All @@ -35,7 +40,7 @@ export const getDedupedResponse = async (timestamp: number, url: string): Promis

const request = new Request(url, createRequestParams())
logger.debug(`GET ${url}`)
const promise = fetch(request)
const promise = resolveBody(request)
promiseCache.set(key, promise)

return promise
Expand Down
14 changes: 7 additions & 7 deletions src/sensor/iotawatt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
PowerSensorPollFunction,
} from '../sensor'
import { Circuit } from '../circuit'
import { getDedupedResponse } from '../http/client'
import { getDedupedResponseBody } from '../http/client'
import { Characteristics } from '../characteristics'
import { createLogger } from '../logger'

Expand Down 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))).clone()
const configuration = (await configurationResult.json()) as IotawattConfiguration
const statusResult = (await getDedupedResponse(timestamp, getStatusUrl(sensor))).clone()
const status = (await statusResult.json()) as IotawattStatus
const configurationResult = await getDedupedResponseBody(timestamp, getConfigurationUrl(sensor))
const configuration = JSON.parse(configurationResult) as unknown as IotawattConfiguration
const statusResult = await getDedupedResponseBody(timestamp, getStatusUrl(sensor))
const status = JSON.parse(statusResult) as unknown 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))).clone()
const query = (await queryResult.json()) as IotawattCharacteristicsQuery
const queryResult = await getDedupedResponseBody(timestamp, getQueryUrl(sensor))
const query = JSON.parse(queryResult) as unknown as IotawattCharacteristicsQuery

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

Expand Down Expand Up @@ -64,10 +64,10 @@ const getSensorDataUrl = (sensor: ShellySensor | ShellyCharacteristicsSensor): s
const parseGen1Response = async (
timestamp: number,
circuit: Circuit,
httpResponse: Response,
responseBody: string,
): Promise<PowerSensorData> => {
const sensor = circuit.sensor as ShellySensor
const data = (await httpResponse.json()) as Gen1StatusResult
const data = JSON.parse(responseBody) as unknown as Gen1StatusResult

return {
timestamp: timestamp,
Expand All @@ -79,9 +79,9 @@ const parseGen1Response = async (
const parseGen2PMResponse = async (
timestamp: number,
circuit: Circuit,
httpResponse: Response,
responseBody: string,
): Promise<PowerSensorData> => {
const data = (await httpResponse.json()) as Gen2SwitchGetStatusResult
const data = JSON.parse(responseBody) as unknown as Gen2SwitchGetStatusResult

return {
timestamp: timestamp,
Expand All @@ -93,10 +93,10 @@ const parseGen2PMResponse = async (
const parseGen2EMResponse = async (
timestamp: number,
circuit: Circuit,
httpResponse: Response,
responseBody: string,
): Promise<PowerSensorData> => {
const sensor = circuit.sensor as ShellySensor
const data = (await httpResponse.json()) as Gen2EMGetStatusResult
const data = JSON.parse(responseBody) as unknown as Gen2EMGetStatusResult

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

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

// Parse the response differently depending on what type of Shelly we're dealing with
switch (sensor.shelly.type as ShellyType) {
case ShellyType.Gen1:
return await parseGen1Response(timestamp, circuit, httpResponse)
return await parseGen1Response(timestamp, circuit, responseBody)
case ShellyType.Gen2PM:
return await parseGen2PMResponse(timestamp, circuit, httpResponse)
return await parseGen2PMResponse(timestamp, circuit, responseBody)
case ShellyType.Gen2EM:
return await parseGen2EMResponse(timestamp, circuit, httpResponse)
return await parseGen2EMResponse(timestamp, circuit, responseBody)
}
} catch (e) {
logger.error(e)
Expand All @@ -166,8 +166,8 @@ export const getCharacteristicsSensorData: CharacteristicsSensorPollFunction = a
}

try {
const httpResponse = (await getDedupedResponse(timestamp, url)).clone()
const data = (await httpResponse.json()) as Gen2EMGetStatusResult
const result = await getDedupedResponseBody(timestamp, url)
const data = JSON.parse(result) as unknown as Gen2EMGetStatusResult

let voltage = 0
let frequency = 0
Expand Down
6 changes: 3 additions & 3 deletions tests/sensor/shelly.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ 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: async (timestamp: number, url: string) => {
let contents: string | null = null
getDedupedResponseBody: async (timestamp: number, url: string): Promise<string> => {
let contents = ''

switch (url) {
case 'http://127.0.0.1/status':
Expand All @@ -25,7 +25,7 @@ jest.mock('../../src/http/client', () => ({
break
}

return Promise.resolve(new Response(contents))
return Promise.resolve(contents)
},
}))

Expand Down
66 changes: 37 additions & 29 deletions webif/package-lock.json

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

2 changes: 1 addition & 1 deletion webif/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.5.0",
"@sveltejs/kit": "^2.9.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
Expand Down

0 comments on commit 38664d7

Please sign in to comment.