Added memory cache.
This commit is contained in:
parent
773e50f4d9
commit
2970c80b83
|
@ -1,5 +1,7 @@
|
||||||
MOJI_APPCODE="YOUR_MOJI_APP_CODE"
|
MOJI_APPCODE="YOUR_MOJI_APP_CODE"
|
||||||
|
|
||||||
|
CACHE_TTL="1800"
|
||||||
|
|
||||||
IOT_MQTT_HOST="YOUR_MQTT_HOST"
|
IOT_MQTT_HOST="YOUR_MQTT_HOST"
|
||||||
IOT_MQTT_PORT="1883"
|
IOT_MQTT_PORT="1883"
|
||||||
|
|
||||||
|
|
|
@ -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 }}"
|
1
Gemfile
1
Gemfile
|
@ -4,6 +4,7 @@ source 'https://rubygems.org'
|
||||||
|
|
||||||
gem 'cbor', '~> 0.5.9.6'
|
gem 'cbor', '~> 0.5.9.6'
|
||||||
gem 'dotenv', '~>2.7'
|
gem 'dotenv', '~>2.7'
|
||||||
|
gem 'lru_redux', '~>1.1'
|
||||||
gem 'moji_weather', github: 'imi415/moji_weather', branch: 'master'
|
gem 'moji_weather', github: 'imi415/moji_weather', branch: 'master'
|
||||||
gem 'mqtt', '~>0.5'
|
gem 'mqtt', '~>0.5'
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ GEM
|
||||||
rexml
|
rexml
|
||||||
kramdown-parser-gfm (1.1.0)
|
kramdown-parser-gfm (1.1.0)
|
||||||
kramdown (~> 2.0)
|
kramdown (~> 2.0)
|
||||||
|
lru_redux (1.1.0)
|
||||||
mqtt (0.5.0)
|
mqtt (0.5.0)
|
||||||
multipart-post (2.2.3)
|
multipart-post (2.2.3)
|
||||||
nokogiri (1.13.8-x86_64-linux)
|
nokogiri (1.13.8-x86_64-linux)
|
||||||
|
@ -103,6 +104,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
cbor (~> 0.5.9.6)
|
cbor (~> 0.5.9.6)
|
||||||
dotenv (~> 2.7)
|
dotenv (~> 2.7)
|
||||||
|
lru_redux (~> 1.1)
|
||||||
moji_weather!
|
moji_weather!
|
||||||
mqtt (~> 0.5)
|
mqtt (~> 0.5)
|
||||||
rubocop
|
rubocop
|
||||||
|
|
|
@ -5,9 +5,10 @@ require 'bundler'
|
||||||
Bundler.require
|
Bundler.require
|
||||||
|
|
||||||
Dotenv.load
|
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'])
|
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)
|
def extract_device_id(topic)
|
||||||
devid = %r{iot/weather/(.*)/request}.match(topic)
|
devid = %r{iot/weather/(.*)/request}.match(topic)
|
||||||
|
@ -19,6 +20,17 @@ def extract_device_id(topic)
|
||||||
end
|
end
|
||||||
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
|
begin
|
||||||
client = MQTT::Client.new
|
client = MQTT::Client.new
|
||||||
|
|
||||||
|
@ -34,49 +46,60 @@ begin
|
||||||
|
|
||||||
client.connect
|
client.connect
|
||||||
|
|
||||||
|
puts "[#{Time.now}] client [#{client}] connected..."
|
||||||
|
|
||||||
client.subscribe('iot/weather/#')
|
client.subscribe('iot/weather/#')
|
||||||
|
|
||||||
client.get do |topic, payload|
|
client.get do |topic, payload|
|
||||||
# this method also checks if this is from a request topic.
|
# this method also checks if this is from a request topic.
|
||||||
dev_id = extract_device_id(topic)
|
dev_id = extract_device_id(topic)
|
||||||
unless dev_id.nil?
|
unless dev_id.nil?
|
||||||
puts "[#{dev_id}] <- #{payload.length}B"
|
puts "[#{Time.now}][#{dev_id}] <- #{payload.length}B"
|
||||||
|
|
||||||
# decode CBOR object, retrieve request.
|
# decode CBOR object, retrieve request.
|
||||||
dev_req = CBOR.decode(payload)
|
dev_req = CBOR.decode(payload)
|
||||||
|
|
||||||
wx_cond = case dev_req['type']
|
wx_cond = extract_req_type(dev_req['type'])
|
||||||
when 'condition'
|
|
||||||
MojiWeather::Api::ApiType::CONDITION
|
# Not a valid type
|
||||||
when 'aqi'
|
next if wx_cond.nil?
|
||||||
MojiWeather::Api::ApiType::AQI
|
|
||||||
when 'forecast24'
|
|
||||||
MojiWeather::Api::ApiType::FORECAST_24HRS
|
|
||||||
end
|
|
||||||
|
|
||||||
req_params = if !dev_req['city_id'].nil?
|
req_params = if !dev_req['city_id'].nil?
|
||||||
{ city_id: dev_req['city_id'] }
|
{ city_id: dev_req['city_id'] }
|
||||||
elsif !dev_req['location'].nil?
|
elsif !dev_req['location'].nil?
|
||||||
{ location: { lat: dev_req['location']['lat'], lon: dev_req['location']['lon'] } }
|
{ location: { lat: dev_req['location']['lat'], lon: dev_req['location']['lon'] } }
|
||||||
else
|
else
|
||||||
puts "[#{dev_id}] not a valid request"
|
puts "[#{Time.now}][#{dev_id}] not a valid request"
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
# Request external service for weather information
|
# Check cache
|
||||||
api_resp = wxapi.query(wx_cond, req_params)
|
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
|
# Encode CBOR object
|
||||||
|
resp = api_resp.to_cbor
|
||||||
|
|
||||||
# Publish to response topic.
|
# Publish to response topic.
|
||||||
resp = api_resp.to_cbor
|
puts "[#{Time.now}][#{dev_id}] -> #{resp.length}B"
|
||||||
puts "[#{dev_id}] -> #{resp.length}B"
|
|
||||||
|
|
||||||
|
# Send response
|
||||||
client.publish("iot/weather/#{dev_id}/response", resp)
|
client.publish("iot/weather/#{dev_id}/response", resp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue SystemExit, Interrupt
|
rescue SystemExit, Interrupt
|
||||||
puts "Interrupt caught, client [#{client}] disconnect."
|
puts "[#{Time.now}] Interrupt caught, client [#{client}] disconnect."
|
||||||
client.disconnect
|
client.disconnect
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
p e
|
p e
|
||||||
|
|
Loading…
Reference in New Issue