expand notifyMyAndroid-plugin for multi recipients and/or different priorities #33

use csv/nma.csv to config different priorities or multiple recipients
This commit is contained in:
JHCD 2015-07-28 22:50:22 +02:00
parent 990f0b579d
commit b529e93763
5 changed files with 291 additions and 99 deletions

View file

@ -270,6 +270,11 @@ priority = 0
# (f.e. if you use more than one instance of BOSWatch)
appName = BOSWatch
# instead of a given APIKey/priority you could import them by a csv-file (0|1)
# APIKey and prioiry above will be ignored, if you use a csv
# configuration loaded from csv/nma.csv
usecsv = 0
#####################
##### Not ready yet #

29
csv/nma.csv Normal file
View file

@ -0,0 +1,29 @@
typ,id,APIKey,priority,comment
#
# BOSWatch CSV file for notifyMyAndroid-Plugin
#
# For each id (FMS, ZVEI, POC) you could set multiple APIKeys with different prioties
# Use the structure: typ, id, APIKey, priority, "comment"
#
# For more than one recipient you could you an id several times
#
# Typ: FMS|ZVEI|POC
#
# id:
# ---
# FMS: FMS Code
# ZVEI: ZVEI 5-tone Code
# POCSAG: POCSAG RIC + functionChar
# 1234567a = entry only for functionChar a
# 1234567* = entry for all functionChars
#
# Priority: goes from -2 (lowest) to 2 (highest). the default priority is 0 (normal)
#
# !!! DO NOT delete the first line !!!
#
POC,1000512*,123456789012345678901234567890123456789012345678,0,"Test for *"
POC,1000000a,123456789012345678901234567890123456789012345678,-2,"Priority-Test"
POC,1000000a,234567890123456789012345678901234567890123456789,-1,"Priority-Test"
POC,1000001b,123456789012345678901234567890123456789012345678,0,"Priority-Test"
POC,1000002c,123456789012345678901234567890123456789012345678,1,"Priority-Test"
POC,1000003d,123456789012345678901234567890123456789012345678,2,"Priority-Test"
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -1,73 +1,73 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Logging Handler for NotifyMyAndroid
@author: Jens Herrmann
"""
import logging
from includes.pynma import pynma
class NMAHandler(logging.Handler): # Inherit from logging.Handler
"""
Handler instances dispatch logging events to NotifyMyAndroid.
"""
def __init__(self, APIKey, application="BOSWatch", event="Logging-Handler"):
"""
Initializes the handler with NMA-specific parameters.
@param APIKey: might be a string containing 1 key or an array of keys
@param application: application name [256]
@param event: event name [1000]
"""
# run the regular Handler __init__
logging.Handler.__init__(self)
# Our custom argument
self.APIKey = APIKey
self.application = application
self.event = event
self.nma = pynma.PyNMA(self.APIKey)
def emit(self, record):
"""
Send logging record via NMA
"""
# record.message is the log message
message = record.message
# if exist, add details as NMA event:
# record.module is the module- or filename
if (len(record.module) > 0):
event = "Module: " + record.module
# record.functionName is the name of the function
# will be "<module>" if the message is not in a function
if len(record.funcName) > 0:
if not record.funcName == "<module>":
event += " - " + record.funcName + "()"
else:
# we have to set an event-text, use self.event now
event = self.event
# record.levelno is the log level
# loglevel: 10 = debug => priority: -2
# loglevel: 20 = info => priority: -1
# loglevel: 30 = warning => priority: 0
# loglevel: 40 = error => priority: 1
# loglevel: 50 = critical => priority: 2
if record.levelno >= 50:
priority = 2
elif record.levelno >= 40:
priority = 1
elif record.levelno >= 30:
priority = 0
elif record.levelno >= 20:
priority = -1
else:
priority = -2
# pynma.push(self, application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False)
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Logging Handler for NotifyMyAndroid
@author: Jens Herrmann
"""
import logging
from includes.pynma import pynma
class NMAHandler(logging.Handler): # Inherit from logging.Handler
"""
Handler instances dispatch logging events to NotifyMyAndroid.
"""
def __init__(self, APIKey, application="BOSWatch", event="Logging-Handler"):
"""
Initializes the handler with NMA-specific parameters.
@param APIKey: might be a string containing 1 key or an array of keys
@param application: application name [256]
@param event: event name [1000]
"""
# run the regular Handler __init__
logging.Handler.__init__(self)
# Our custom argument
self.APIKey = APIKey
self.application = application
self.event = event
self.nma = pynma.PyNMA(self.APIKey)
def emit(self, record):
"""
Send logging record via NMA
"""
# record.message is the log message
message = record.message
# if exist, add details as NMA event:
# record.module is the module- or filename
if (len(record.module) > 0):
event = "Module: " + record.module
# record.functionName is the name of the function
# will be "<module>" if the message is not in a function
if len(record.funcName) > 0:
if not record.funcName == "<module>":
event += " - " + record.funcName + "()"
else:
# we have to set an event-text, use self.event now
event = self.event
# record.levelno is the log level
# loglevel: 10 = debug => priority: -2
# loglevel: 20 = info => priority: -1
# loglevel: 30 = warning => priority: 0
# loglevel: 40 = error => priority: 1
# loglevel: 50 = critical => priority: 2
if record.levelno >= 50:
priority = 2
elif record.levelno >= 40:
priority = 1
elif record.levelno >= 30:
priority = 0
elif record.levelno >= 20:
priority = -1
else:
priority = -2
# pynma.push(self, application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False)
self.nma.push(application=self.application, event=event, description=message, priority=priority)

8
includes/pynma/pynma.py Executable file → Normal file
View file

@ -68,6 +68,14 @@ takes 2 optional arguments:
if type(developerkey) == str and len(developerkey) == 48:
self._developerkey = developerkey
def pushWithAPIKey(self, apikey=[], application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False):
"""Special Funktion"""
if apikey:
if type(apikey) == str:
apikey = [apikey]
self._apikey = uniq(apikey)
return self.push(application, event, description, url, contenttype, priority, batch_mode, html)
def push(self, application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False):
"""Pushes a message on the registered API keys.
takes 5 arguments:

View file

@ -13,6 +13,8 @@ import logging # Global logger
import socket # for connection
import json # for data-transfer
import csv # for loading the APIKeys
from includes import globals # Global variables
@ -21,9 +23,51 @@ from includes.helper import timeHandler
from includes.helper import uft8Converter # UTF-8 converter
from includes.pynma import pynma
# local variables
application = "BOSWatch"
APIKey = None
remainingMsgs = None
usecsv = False
# data structures: xAPIKeyList[id][i] = (APIKey, priority)
fmsAPIKeyList = {}
zveiAPIKeyList = {}
pocAPIKeyList = {}
def checkResponse(response, APIKey):
"""
Helper function to check the response of NMA
@type response: dict
@param response: Response of the pyNMA.push() method
@type data: string / array
@param data: a string containing 1 key or an array of keys
@return: nothing
"""
# local variables
global remainingMsgs
try:
#
# check HTTP-Response
#
if str(response[APIKey]['code']) == "200": #Check HTTP Response an print a Log or Error
logging.debug("NMA response: %s" , str(response[APIKey]['code']))
remainingMsgs = response[APIKey]['remaining']
if int(remainingMsgs) == 0:
logging.error("NMA remaining msgs: %s" , str(remainingMsgs))
if int(response[APIKey]['remaining']) < 20:
logging.warning("NMA remaining msgs: %s" , str(remainingMsgs))
else:
logging.debug("NMA remaining msgs: %s" , str(remainingMsgs))
else:
logging.warning("NMA response: %s - %s" , str(response[APIKey]['code']), str(response[APIKey]['message']))
except:
logging.error("cannot read pynma response")
logging.debug("cannot read pynma response", exc_info=True)
return
##
#
@ -42,12 +86,74 @@ def onLoad():
# local variables
global application
global APIKey
global usecsv
global fmsAPIKeyList
global zveiAPIKeyList
global pocAPIKeyList
# load config:
configHandler.checkConfig("notifyMyAndroid")
APIKey = globals.config.get("notifyMyAndroid","APIKey")
application = globals.config.get("notifyMyAndroid","appName")
usecsv = globals.config.getboolean("notifyMyAndroid","usecsv")
# if no csv should use, we take the APIKey directly
if usecsv == False:
APIKey = globals.config.get("notifyMyAndroid","APIKey")
else:
# import the csv-file
try:
logging.debug("-- loading nma.csv")
with open(globals.script_path+'/csv/nma.csv') as csvfile:
# DictReader expected structure described in first line of csv-file
reader = csv.DictReader(csvfile)
for row in reader:
logging.debug(row)
# only import rows with an supported types
supportedTypes = ["FMS", "ZVEI", "POC"]
if row['typ'] in supportedTypes:
try:
if "FMS" in row['typ']:
# if len for id in mainList raise an KeyErrorException, we have to init it...
try:
if len(fmsAPIKeyList[row['id']]) > 0:
pass
except KeyError:
fmsAPIKeyList[row['id']] = []
# data structure: fmsAPIKeyList[fms][i] = (APIKey, priority)
fmsAPIKeyList[row['id']].append((row['APIKey'], row['priority']))
elif "ZVEI" in row['typ']:
# if len for id in mainList raise an KeyErrorException, we have to init it...
try:
if len(zveiAPIKeyList[row['id']]) > 0:
pass
except KeyError:
zveiAPIKeyList[row['id']] = []
# data structure: zveiAPIKeyList[zvei][i] = (APIKey, priority)
zveiAPIKeyList[row['id']].append((row['APIKey'], row['priority']))
elif "POC" in row['typ']:
# if len for id in mainList raise an KeyErrorException, we have to init it...
try:
if len(pocAPIKeyList[row['id']]) > 0:
pass
except KeyError:
pocAPIKeyList[row['id']] = []
# data structure: zveiAPIKeyList[ric][i] = (APIKey, priority)
pocAPIKeyList[row['id']].append((row['APIKey'], row['priority']))
except:
# skip entry in case of an exception
logging.debug("error in shifting...", exc_info=True)
pass
# if row['typ'] in supportedTypes
# for row in reader:
logging.debug("-- loading csv finished")
except:
logging.error("loading csvList for nma failed")
logging.debug("loading csvList for nma failed", exc_info=True)
raise
# and if usecsv == True
return
@ -76,55 +182,99 @@ def run(typ,freq,data):
# local variables
global application
global APIKey
global remainingMsgs
global usecsv
global fmsAPIKeyList
global zveiAPIKeyList
global pocAPIKeyList
try:
try:
#
# initialize to pyNMA
#
nma = pynma.PyNMA(APIKey)
nma = pynma.PyNMA()
except:
logging.error("cannot initialize pyNMA")
logging.debug("cannot initialize %s-socket", exc_info=True)
logging.debug("cannot initialize pyNMA", exc_info=True)
# Without class, plugin couldn't work
return
else:
# toDo is equals for all types, so only check if typ is supported
supportedTypes = ["FMS", "ZVEI", "POC"]
if typ in supportedTypes:
logging.debug("Start %s to NMA", typ)
try:
# send data
event = data['description']
# build event and msg
event = uft8Converter.convertToUTF8(data['description'])
msg = timeHandler.curtime()
if len(data['msg']) > 0:
msg += "\n" + data['msg']
response = nma.push(application, uft8Converter.convertToUTF8(event), uft8Converter.convertToUTF8(msg), priority=globals.config.getint("notifyMyAndroid","priority"))
msg = uft8Converter.convertToUTF8(msg)
# if not using csv-import, all is simple...
if usecsv == False:
response = nma.pushWithAPIKey(APIKey, application, event, msg, priority=globals.config.getint("notifyMyAndroid","priority"))
checkResponse(response, APIKey)
else:
if "FMS" in typ:
# lets look for fms in fmsAPIKeyList
xID = data['fms']
try:
# data structure: fmsAPIKeyList[xID][i] = (xAPIKey, xPriority)
for i in range(len(fmsAPIKeyList[xID])):
(xAPIKey, xPriority) = fmsAPIKeyList[xID][i]
response = nma.pushWithAPIKey(xAPIKey, application, event, msg, priority=xPriority)
checkResponse(response, xAPIKey)
except KeyError:
# nothing found
pass
elif "ZVEI" in typ:
# lets look for zvei in zveiAPIKeyList
xID = data['zvei']
try:
# data structure: zveiAPIKeyList[xID][i] = (xAPIKey, xPriority)
for i in range(len(zveiAPIKeyList[xID])):
(xAPIKey, xPriority) = zveiAPIKeyList[xID][i]
response = nma.pushWithAPIKey(xAPIKey, application, event, msg, priority=xPriority)
checkResponse(response, xAPIKey)
except KeyError:
# nothing found
pass
elif "POC" in typ:
xID = ""
# 1. lets look for ric+functionChar in pocAPIKeyList
try:
xID = data['ric'] + data['functionChar']
# data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority)
for i in range(len(pocAPIKeyList[xID])):
(xAPIKey, xPriority) = pocAPIKeyList[xID][i]
response = nma.pushWithAPIKey(xAPIKey, application, event, msg, priority=xPriority)
checkResponse(response, xAPIKey)
except KeyError:
# nothing found
pass
# 2. lets look for ric* in pocAPIKeyList
try:
xID = data['ric'] + "*"
# data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority)
for i in range(len(pocAPIKeyList[xID])):
(xAPIKey, xPriority) = pocAPIKeyList[xID][i]
logging.debug("-- found %s, %s", xAPIKey, xPriority)
response = nma.pushWithAPIKey(xAPIKey, application, event, msg, priority=xPriority)
checkResponse(response, xAPIKey)
except KeyError:
# nothing found
pass
# end if "POC" in typ
# end if usecsv == True
except:
logging.error("%s to NMA failed", typ)
logging.debug("%s to NMA failed", typ, exc_info=True)
return
else:
try:
#
# check HTTP-Response
#
if str(response[APIKey]['code']) == "200": #Check HTTP Response an print a Log or Error
logging.debug("NMA response: %s" , str(response[APIKey]['code']))
if int(response[APIKey]['remaining']) == 0:
logging.error("NMA remaining msgs: %s" , str(response[APIKey]['remaining']))
if int(response[APIKey]['remaining']) < 20:
logging.warning("NMA remaining msgs: %s" , str(response[APIKey]['remaining']))
else:
logging.debug("NMA remaining msgs: %s" , str(response[APIKey]['remaining']))
else:
logging.warning("NMA response: %s - %s" , str(response[APIKey]['code']), str(response[APIKey]['message']))
except: #otherwise
logging.error("cannot read pynma response")
logging.debug("cannot read pynma response", exc_info=True)
return
else:
logging.warning("Invalid Typ: %s", typ)