class RulingWeatherSetting require "net/http" require 'json' include Mongoid::Document include Mongoid::Timestamps WEATHER_API_URL = "https://opendata.cwa.gov.tw".freeze field :time_offset, type: String, default: "+8" field :location, type: String, default: "" field :dataid, type: String, default: "" field :observatory_name, type: String, default: "" has_one :ruling_weather_cache def net_http_get_response(uri,headers={}) port = uri.port host = uri.host http = Net::HTTP.new(host, port) scheme = uri.scheme if scheme == "https" || port.to_i == 443 http.verify_mode = OpenSSL::SSL::VERIFY_NONE http.use_ssl = true http.open_timeout = 3 http.ssl_timeout = 1 end http.read_timeout = 1 relative_path = (uri.path.blank? ? "/" : uri.path) # if !relative_path.start_with?("http") && !relative_path.start_with?("/") # relative_path = "/" + relative_path # end # relative_path = relative_path.sub(/^\/\.\.\/(\.\.\/)*/,'/') # while relative_path.include?("/../") do # relative_path = relative_path.gsub(/\/[^\/]+\/\.\.\//,'/') # end # relative_path = relative_path.gsub('//','/') relative_path = URI.decode(relative_path) relative_path += (uri.query.blank? ? '' : "?#{URI.decode(uri.query)}") res = http.get(relative_path.gsub(" ","%20")) res end def get_now_info(custom_location=nil,custom_dataid=nil,custom_observatory_name=nil) time_now = DateTime.now.new_offset(self.time_offset) today = time_now.strftime("%Y-%m-%d") custom_dataid = custom_dataid || self.dataid url = "#{WEATHER_API_URL}/api/v1/rest/datastore/#{custom_dataid}.json" startt = "#{today}T00:00:00" endt = "#{today}T23:59:59" custom_location = custom_location || self.location data = {"Authorization" => "CWB-00BEC353-89FA-4261-B830-5F8C38547CD0", "timeFrom" => startt, "timeTo" => endt, "limit" => 1, "locationName" => custom_location} timeout_flag = false begin cache_model = self.ruling_weather_cache if cache_model.nil? cache_model = RulingWeatherCache.create(:cache=>{},:ruling_weather_setting=>self) elsif (cache_model.cache_time.to_i / 3600) == (time_now.to_i / 3600) #The same hour result = cache_model.cache if result["uvi_text"].blank? result["uvi_text"] = I18n.t("ruling_weather.none") end return result end cache = cache_model.cache rescue {} res = net_http_get_response(URI.parse("#{url}?#{data.to_query}")) content = JSON.parse(res.body) weather_data = get_weather_data(content) rescue {} rescue Errno::EHOSTUNREACH, Net::ReadTimeout, Net::OpenTimeout timeout_flag = true weather_data = {} end if timeout_flag || (weather_data.count == 0 rescue true) mint = cache["mint"].to_i maxt = cache["maxt"].to_i avgt = cache["avgt"].to_i rain_rate = cache["rain_rate"].to_i uvi = cache["uvi"].to_i uvi_text = cache["uvi_text"].to_s rh = cache["rh"].to_i wx_text = cache["wx_text"].to_s wx_code = cache["wx_code"].to_i ws = cache["ws"].to_i else mint = get_element_value(weather_data["MinT"]).to_i #最低溫度(攝氏度) maxt = get_element_value(weather_data["MaxT"]).to_i #最高溫度(攝氏度) avgt = get_element_value(weather_data["T"]).to_i #平均溫度(攝氏度) rain_rate = get_element_value(weather_data["PoP12h"]).to_i #降雨機率(百分比) uvi = get_element_value(weather_data["UVI"],0).to_i #紫外線指數(數值) uvi_text = get_element_value(weather_data["UVI"],1).to_s #紫外線指數(文字) rh = get_element_value(weather_data["RH"]).to_i #相對溼度 wx_text = get_element_value(weather_data["Wx"],0).to_s #天氣現象(文字) wx_code = get_element_value(weather_data["Wx"],1).to_i #天氣現象(編碼) ws = get_element_value(weather_data["WS"]).to_i #風速(m/s) end if wx_code < 10 wx_code = "0" + wx_code.to_s else wx_code = wx_code.to_s end if time_now.hour >= 18 svg_type = "night" else svg_type = "day" end wx_svg = "/assets/ruling_weather/svg_icon/#{svg_type}/#{wx_code}.svg" custom_observatory_name = custom_observatory_name || self.observatory_name data2 = {"Authorization" => "CWB-00BEC353-89FA-4261-B830-5F8C38547CD0", "elementName" => "NOW", "locationName" => custom_observatory_name} rain = nil if custom_observatory_name.present? if timeout_flag rain = cache["rain"].to_f rescue 0.0 else url2 = "#{WEATHER_API_URL}/api/v1/rest/datastore/O-A0002-001.json" begin res2 = net_http_get_response(URI.parse("#{url2}?#{data2.to_query}")) content2 = JSON.parse(res2.body) weather_data2 = get_weather_data(content2) rescue {} rescue Errno::EHOSTUNREACH, Net::ReadTimeout, Net::OpenTimeout weather_data2 = {} end if (weather_data2.count == 0 rescue true) rain = cache["rain"].to_f rescue 0.0 else rain = weather_data2["NOW"]["elementValue"].to_f rescue 0.0 end end end result = {"mint" => mint, "maxt" => maxt, "avgt" => avgt, "rain_rate" => rain_rate, "uvi" => uvi, "uvi_text" => uvi_text, "rh" => rh, "wx_code" => wx_code, "wx_text" => wx_text, "wx_svg" => wx_svg, "ws" => ws, "rain" => rain} cache_model.update(:cache=>result,:cache_time=>time_now) if uvi_text.blank? result["uvi_text"] = I18n.t("ruling_weather.none") end return result end def test time_now = DateTime.now.utc.new_offset(self.time_offset) today = time_now.strftime("%Y-%m-%d") custom_dataid = custom_dataid || self.dataid url = "#{WEATHER_API_URL}/api/v1/rest/datastore/#{custom_dataid}.json" startt = "#{today}T00:00:00" endt = "#{today}T23:59:59" custom_location = custom_location || self.location data = {"Authorization" => "CWB-00BEC353-89FA-4261-B830-5F8C38547CD0", "timeFrom" => startt, "timeTo" => endt, "limit" => 1, "locationName" => custom_location} res = net_http_get_response(URI.parse("#{url}?#{data.to_query}")) content = JSON.parse(res.body) weather_data = get_weather_data(content) rescue {} end def get_weather_data(content) if content["records"]["locations"] record_data = content["records"]["locations"][0] else record_data = content["records"] end location_record_data = record_data["location"][0] weather_data = location_record_data["weatherElement"].map{|h| [h["elementName"] , h.except("elementName")]}.to_h return weather_data end def get_element_value(element_info,idx=0) return element_info["time"][0]["elementValue"][idx]["value"] rescue "" end def get_element_value_and_measures(element_info) return (element_info["time"][0]["elementValue"][idx]["value"] + element_info["time"][0]["elementValue"][idx]["measures"].to_s) rescue "" end end