Added memory cache.

This commit is contained in:
imi415 2022-07-25 23:46:21 +08:00
parent 773e50f4d9
commit 2970c80b83
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
5 changed files with 74 additions and 16 deletions

View File

@ -1,5 +1,7 @@
MOJI_APPCODE="YOUR_MOJI_APP_CODE"
CACHE_TTL="1800"
IOT_MQTT_HOST="YOUR_MQTT_HOST"
IOT_MQTT_PORT="1883"

View File

@ -0,0 +1,30 @@
name: "Build and publish image"
on:
push:
branches: ["master"]
jobs:
build:
runs-on: "ubuntu-latest"
steps:
- name: "Checkout repository"
uses: "actions/checkout@v2"
- name: "Login with Github packages"
uses: "docker/login-action@v1"
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- name: "Set up buildx"
uses: "docker/setup-buildx-action@v1"
- name: "Extract branch name"
shell: "bash"
run: "echo \"##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})\""
id: "extract_branch"
- name: "Build and push image"
uses: "docker/build-push-action@v2"
with:
context: "./"
file: "./Dockerfile"
push: true
tags: "ghcr.io/${{ github.repository_owner }}/iot-weather:${{ steps.extract_branch.outputs.branch }}"

View File

@ -4,6 +4,7 @@ source 'https://rubygems.org'
gem 'cbor', '~> 0.5.9.6'
gem 'dotenv', '~>2.7'
gem 'lru_redux', '~>1.1'
gem 'moji_weather', github: 'imi415/moji_weather', branch: 'master'
gem 'mqtt', '~>0.5'

View File

@ -48,6 +48,7 @@ GEM
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
lru_redux (1.1.0)
mqtt (0.5.0)
multipart-post (2.2.3)
nokogiri (1.13.8-x86_64-linux)
@ -103,6 +104,7 @@ PLATFORMS
DEPENDENCIES
cbor (~> 0.5.9.6)
dotenv (~> 2.7)
lru_redux (~> 1.1)
moji_weather!
mqtt (~> 0.5)
rubocop

View File

@ -5,9 +5,10 @@ require 'bundler'
Bundler.require
Dotenv.load
Dotenv.require_keys('MOJI_APPCODE', 'IOT_MQTT_HOST', 'IOT_MQTT_PORT', 'IOT_MQTT_SSL')
Dotenv.require_keys('MOJI_APPCODE', 'CACHE_TTL', 'IOT_MQTT_HOST', 'IOT_MQTT_PORT', 'IOT_MQTT_SSL')
wxapi = MojiWeather::Api::RestClient.new(app_code: ENV['MOJI_APPCODE'])
cache = LruRedux::TTL::Cache.new(100, ENV['CACHE_TTL'].to_i)
def extract_device_id(topic)
devid = %r{iot/weather/(.*)/request}.match(topic)
@ -19,6 +20,17 @@ def extract_device_id(topic)
end
end
def extract_req_type(type)
case type
when 'condition'
MojiWeather::Api::ApiType::CONDITION
when 'aqi'
MojiWeather::Api::ApiType::AQI
when 'forecast24'
MojiWeather::Api::ApiType::FORECAST_24HRS
end
end
begin
client = MQTT::Client.new
@ -34,49 +46,60 @@ begin
client.connect
puts "[#{Time.now}] client [#{client}] connected..."
client.subscribe('iot/weather/#')
client.get do |topic, payload|
# this method also checks if this is from a request topic.
dev_id = extract_device_id(topic)
unless dev_id.nil?
puts "[#{dev_id}] <- #{payload.length}B"
puts "[#{Time.now}][#{dev_id}] <- #{payload.length}B"
# decode CBOR object, retrieve request.
dev_req = CBOR.decode(payload)
wx_cond = case dev_req['type']
when 'condition'
MojiWeather::Api::ApiType::CONDITION
when 'aqi'
MojiWeather::Api::ApiType::AQI
when 'forecast24'
MojiWeather::Api::ApiType::FORECAST_24HRS
end
wx_cond = extract_req_type(dev_req['type'])
# Not a valid type
next if wx_cond.nil?
req_params = if !dev_req['city_id'].nil?
{ city_id: dev_req['city_id'] }
elsif !dev_req['location'].nil?
{ location: { lat: dev_req['location']['lat'], lon: dev_req['location']['lon'] } }
else
puts "[#{dev_id}] not a valid request"
puts "[#{Time.now}][#{dev_id}] not a valid request"
next
end
# Request external service for weather information
api_resp = wxapi.query(wx_cond, req_params)
# Check cache
api_resp = cache["cache_#{req_params}"]
# Cache missed..
if api_resp.nil?
puts "[#{Time.now}][#{dev_id}] cache missed"
# Request external service for weather information
api_resp = wxapi.query(wx_cond, req_params)
# Update cache entry
cache["cache_#{req_params}"] = api_resp
else
puts "[#{Time.now}][#{dev_id}] cache hit"
end
# Encode CBOR object
resp = api_resp.to_cbor
# Publish to response topic.
resp = api_resp.to_cbor
puts "[#{dev_id}] -> #{resp.length}B"
puts "[#{Time.now}][#{dev_id}] -> #{resp.length}B"
# Send response
client.publish("iot/weather/#{dev_id}/response", resp)
end
end
rescue SystemExit, Interrupt
puts "Interrupt caught, client [#{client}] disconnect."
puts "[#{Time.now}] Interrupt caught, client [#{client}] disconnect."
client.disconnect
rescue StandardError => e
p e