2018-10-13 01:42:33 +02:00
// +build linux
2018-09-25 23:06:23 +02:00
package service
2018-09-26 00:04:48 +02:00
import (
2018-10-13 15:34:46 +02:00
"context"
2018-10-01 17:28:24 +02:00
"errors"
2018-09-26 00:04:48 +02:00
"fmt"
2018-09-26 12:37:51 +02:00
"github.com/mame82/P4wnP1_go/common"
2018-09-26 00:04:48 +02:00
"github.com/mame82/P4wnP1_go/common_web"
pb "github.com/mame82/P4wnP1_go/proto"
2018-10-13 01:42:33 +02:00
"github.com/mame82/P4wnP1_go/service/util"
2018-10-13 15:34:46 +02:00
"io/ioutil"
2018-09-26 00:04:48 +02:00
"sync"
)
2018-10-13 01:42:33 +02:00
var (
ErrTaNotFound = errors . New ( "Couldn't find given TriggerAction" )
ErrTaImmutable = errors . New ( "Not allowed to change immutable TriggerAction" )
)
type triggerType int
const (
triggerTypeServiceStarted triggerType = iota
triggerTypeUsbGadgetConnected
triggerTypeUsbGadgetDisconnected
triggerTypeWifiAPStarted
triggerTypeWifiConnectedAsSta
triggerTypeSshLogin
triggerTypeDhcpLeaseGranted
triggerTypeGroupReceive
2018-10-26 16:58:27 +02:00
triggerTypeGroupReceiveMulti
2018-10-13 01:42:33 +02:00
triggerTypeGpioIn
)
var triggerTypeString = map [ triggerType ] string {
2018-10-26 16:58:27 +02:00
triggerTypeServiceStarted : "TRIGGER_SERVICE_STARTED" ,
triggerTypeUsbGadgetConnected : "TRIGGER_USB_GADGET_CONNECTED" ,
2018-10-13 01:42:33 +02:00
triggerTypeUsbGadgetDisconnected : "TRIGGER_USB_GADGET_DISCONNECTED" ,
2018-10-26 16:58:27 +02:00
triggerTypeWifiAPStarted : "TRIGGER_WIFI_AP_STARTED" ,
triggerTypeWifiConnectedAsSta : "TRIGGER_WIFI_CONNECTED_AS_STA" ,
triggerTypeSshLogin : "TRIGGER_SSH_LOGIN" ,
triggerTypeDhcpLeaseGranted : "TRIGGER_DHCP_LEASE_GRANTED" ,
triggerTypeGroupReceive : "TRIGGER_GROUP_RECEIVE" ,
triggerTypeGroupReceiveMulti : "TRIGGER_GROUP_RECEIVE_SEQUENCE" ,
triggerTypeGpioIn : "TRIGGER_GPIO_IN" ,
2018-10-13 01:42:33 +02:00
}
type actionType int
const (
actionTypeBashScript actionType = iota
actionTypeHidScript
actionTypeDeploySettingsTemplate
actionTypeLog
actionTypeGpioOut
actionTypeGroupSend
)
var actionTypeString = map [ actionType ] string {
actionTypeBashScript : "ACTION_BASH_SCRIPT" ,
actionTypeHidScript : "ACTION_HID_SCRIPT" ,
actionTypeDeploySettingsTemplate : "ACTION_DEPLOY_SETTINGS_TEMPLATE" ,
actionTypeLog : "ACTION_LOG" ,
actionTypeGpioOut : "ACTION_GPIO_OUT" ,
actionTypeGroupSend : "ACTION_GROUP_SEND" ,
}
func retrieveTriggerActionTypes ( ta * pb . TriggerAction ) ( ttype triggerType , atype actionType ) {
// Trigger
switch x := ta . Trigger . ( type ) {
case * pb . TriggerAction_ServiceStarted :
ttype = triggerTypeServiceStarted
case * pb . TriggerAction_UsbGadgetConnected :
ttype = triggerTypeUsbGadgetConnected
case * pb . TriggerAction_UsbGadgetDisconnected :
ttype = triggerTypeUsbGadgetDisconnected
case * pb . TriggerAction_WifiAPStarted :
ttype = triggerTypeWifiAPStarted
case * pb . TriggerAction_WifiConnectedAsSta :
ttype = triggerTypeWifiConnectedAsSta
case * pb . TriggerAction_SshLogin :
ttype = triggerTypeSshLogin
case * pb . TriggerAction_DhcpLeaseGranted :
ttype = triggerTypeDhcpLeaseGranted
case * pb . TriggerAction_GroupReceive :
ttype = triggerTypeGroupReceive
2018-10-26 16:58:27 +02:00
case * pb . TriggerAction_GroupReceiveMulti :
ttype = triggerTypeGroupReceiveMulti
2018-10-13 01:42:33 +02:00
case * pb . TriggerAction_GpioIn :
ttype = triggerTypeGpioIn
case nil :
default :
panic ( fmt . Sprintf ( "unexpected trigger type %T" , x ) )
}
// Action
switch x := ta . Action . ( type ) {
case * pb . TriggerAction_BashScript :
atype = actionTypeBashScript
case * pb . TriggerAction_HidScript :
atype = actionTypeHidScript
case * pb . TriggerAction_DeploySettingsTemplate :
atype = actionTypeDeploySettingsTemplate
case * pb . TriggerAction_Log :
atype = actionTypeLog
case * pb . TriggerAction_GpioOut :
atype = actionTypeGpioOut
case * pb . TriggerAction_GroupSend :
atype = actionTypeGroupSend
case nil :
default :
panic ( fmt . Sprintf ( "unexpected action type %T" , x ) )
}
return
}
2018-09-26 00:04:48 +02:00
type TriggerActionManager struct {
rootSvc * Service
evtRcv * EventReceiver
registeredTriggerActionMutex * sync . Mutex
2018-10-12 13:51:58 +02:00
//registeredTriggerAction []*pb.TriggerAction
registeredTriggerActions pb . TriggerActionSet
2018-09-26 12:37:51 +02:00
2018-10-13 01:42:33 +02:00
groupReceiveSequenceCheckers map [ * pb . TriggerAction ] * util . ValueSequenceChecker
groupReceiveSequenceCheckersMutex * sync . Mutex
2018-09-26 00:04:48 +02:00
nextID uint32
}
func ( tam * TriggerActionManager ) processing_loop ( ) {
2018-09-26 13:32:11 +02:00
2018-09-26 00:04:48 +02:00
fmt . Println ( "TAM processing loop started" )
Outer :
for {
select {
case evt := <- tam . evtRcv . EventQueue :
// avoid consuming empty messages, because channel is closed
if evt == nil {
break Outer // abort loop on "nil" event, as this indicates the EventQueue channel has been closed
}
2018-09-26 12:37:51 +02:00
//fmt.Println("TriggerActionManager received unfiltered event", evt)
2018-10-13 01:42:33 +02:00
tam . processTriggerEvent ( evt )
2018-09-26 00:04:48 +02:00
// check if relevant and dispatch to triggers
case <- tam . evtRcv . Ctx . Done ( ) :
// evvent Receiver cancelled or unregistered
break Outer
}
}
fmt . Println ( "TAM processing loop finished" )
}
2018-10-13 01:42:33 +02:00
// iterates over registered trigger actions
// if event matches a trigger, pass execution to respective on{Event} method, along with the arguments
// from the respective events
//
// Tasks of on{event} method:
// - decide if the given trigger fires, based on the event arguments
// - disable the TriggerAction, in case the trigger has fired
// - call the execute{Action} method, according to the Action defined in the trigger Action, in case the trigger fires
//
// Note: a event doesn't necessarily map to a trigger (f.e. a TRIGGER_EVT_TYPE_GROUP_RECEIVE carries a single value to a
// group, but a triggerTypeGroupReceive doesn't trigger if it is the wrong value)
//
func ( tam * TriggerActionManager ) processTriggerEvent ( evt * pb . Event ) {
//fmt.Printf("Remaining triggerActions: %+v\n", tam.registeredTriggerAction)
2018-10-13 12:44:11 +02:00
//fmt.Printf("TriggerActionManager Received event: %+v\n", evt)
2018-10-13 01:42:33 +02:00
tam . registeredTriggerActionMutex . Lock ( )
defer tam . registeredTriggerActionMutex . Unlock ( )
for _ , ta := range tam . registeredTriggerActions . TriggerActions {
// skip disabled triggeractions
if ! ta . IsActive { continue }
ttype , atype := retrieveTriggerActionTypes ( ta )
if taTriggerTypeMatchesEvtTriggerType ( ttype , evt ) {
switch ttEvt := common_web . EvtTriggerType ( evt . Values [ 0 ] . GetTint64 ( ) ) ; ttEvt {
case common_web . TRIGGER_EVT_TYPE_SERVICE_STARTED :
tam . onServiceStarted ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_SSH_LOGIN :
tam . onSSHLogin ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_WIFI_CONNECTED_AS_STA :
tam . onWifiConnectedAsSta ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_WIFI_AP_STARTED :
tam . onWifiApStarted ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_DHCP_LEASE_GRANTED :
// extract iface, mac and ip from event
tam . onDhcpLeaseGranted ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_USB_GADGET_CONNECTED :
tam . onUsbGadgetConnected ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_USB_GADGET_DISCONNECTED :
tam . onUsbGadgetDisconnected ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_GPIO_IN :
tam . onGpioIn ( evt , ta , ttype , atype )
case common_web . TRIGGER_EVT_TYPE_GROUP_RECEIVE :
tam . onGroupReceive ( evt , ta , ttype , atype )
default :
fmt . Println ( "unhandled trigger: " , ttEvt )
}
}
2018-09-26 12:37:51 +02:00
}
2018-10-13 01:42:33 +02:00
return
}
func ( tam * TriggerActionManager ) onServiceStarted ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
// always triggers
tam . executeAction ( evt , ta , tt , at )
2018-09-26 12:37:51 +02:00
return nil
}
2018-09-26 00:04:48 +02:00
2018-09-26 01:08:51 +02:00
2018-10-13 01:42:33 +02:00
func ( tam * TriggerActionManager ) onSSHLogin ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
//ToDo: allow filtering by login user
// always triggers
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onWifiConnectedAsSta ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
//ToDo: filter by AP name
// always triggers
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onWifiApStarted ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
2018-10-13 19:43:04 +02:00
//ToDo: provide AP name with event and hand it over to the action
2018-10-13 01:42:33 +02:00
// always triggers
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onDhcpLeaseGranted ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
//ToDo: filter by source interface, mac, IP
// always triggers
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onUsbGadgetConnected ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
// always triggers
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onUsbGadgetDisconnected ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
// always triggers
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onGpioIn ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
2018-10-13 19:43:04 +02:00
//ToDo: only trigger if PIN matches, important: Enum values have to be parsed for matching (0 != PIN0)
2018-10-13 01:42:33 +02:00
tam . executeAction ( evt , ta , tt , at )
return nil
}
func ( tam * TriggerActionManager ) onGroupReceive ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
evGroupName , evValue , err := DeconstructEventTriggerGroupReceive ( evt )
if err != nil { return err }
switch tt {
case triggerTypeGroupReceive :
triggerVal := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . Value
triggerGroupName := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . GroupName
if evGroupName != triggerGroupName {
return nil // don't handle on group mismatch, but return without error
}
if evValue != triggerVal {
return nil // don't handle on value mismatch, but return without error
}
tam . executeAction ( evt , ta , tt , at ) // fire action
return nil
2018-10-26 16:58:27 +02:00
case triggerTypeGroupReceiveMulti :
2018-10-13 12:44:11 +02:00
// fmt.Println("### Processing GroupReceive event for trigger type GroupReceiveSequence")
2018-10-26 16:58:27 +02:00
triggerGroupName := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . GroupName
2018-10-13 01:42:33 +02:00
if evGroupName != triggerGroupName {
2018-10-13 12:44:11 +02:00
return nil
}
// retrieve the sequence checker
if sc , exists := tam . groupReceiveSequenceCheckers [ ta ] ; exists {
if sc . Check ( evValue ) {
tam . executeAction ( evt , ta , tt , at ) // fire action
2018-10-13 01:42:33 +02:00
}
2018-10-13 12:44:11 +02:00
// fmt.Printf("GrpRcvSeq '%s' received '%d': %s\n", triggerGroupName, evValue, sc)
2018-10-13 01:42:33 +02:00
}
2018-10-13 12:44:11 +02:00
return nil // don't handle on group mismatch, but return without error
2018-10-13 01:42:33 +02:00
default :
return errors . New ( "Wrong trigger for onGroupReceive event" )
}
return nil
2018-09-26 12:37:51 +02:00
}
2018-10-13 01:42:33 +02:00
func ( tam * TriggerActionManager ) executeAction ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType ) error {
if ta . OneShot { ta . IsActive = false }
2018-09-26 12:37:51 +02:00
switch actionType := ta . Action . ( type ) {
case * pb . TriggerAction_BashScript :
2018-10-13 01:42:33 +02:00
go tam . executeActionBashScript ( evt , ta , tt , at , actionType . BashScript )
2018-09-26 12:37:51 +02:00
case * pb . TriggerAction_HidScript :
2018-10-13 01:42:33 +02:00
go tam . executeActionStartHidScript ( evt , ta , tt , at , actionType . HidScript )
2018-09-26 12:37:51 +02:00
case * pb . TriggerAction_Log :
2018-10-13 01:42:33 +02:00
go tam . executeActionLog ( evt , ta , tt , at , actionType . Log )
case * pb . TriggerAction_DeploySettingsTemplate :
go tam . executeActionDeploySettingsTemplate ( evt , ta , tt , at , actionType . DeploySettingsTemplate )
case * pb . TriggerAction_GroupSend :
tam . executeActionGroupSend ( evt , ta , tt , at , actionType . GroupSend )
case * pb . TriggerAction_GpioOut :
tam . executeActionGPIOOut ( evt , ta , tt , at , actionType . GpioOut )
2018-09-26 01:08:51 +02:00
}
2018-10-13 01:42:33 +02:00
2018-09-26 12:37:51 +02:00
return nil
2018-09-26 01:08:51 +02:00
}
2018-10-13 01:42:33 +02:00
2018-10-13 19:43:04 +02:00
func ( tam * TriggerActionManager ) executeActionDeploySettingsTemplate ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType , action * pb . ActionDeploySettingsTemplate ) {
2018-10-13 01:42:33 +02:00
triggerName := triggerTypeString [ tt ]
actionName := actionTypeString [ at ]
2018-10-13 19:43:04 +02:00
templateTypeName := pb . ActionDeploySettingsTemplate_TemplateType_name [ int32 ( action . Type ) ]
fmt . Printf ( "Trigger '%s' fired -> executing action '%s' (%s: '%s')\n" , triggerName , actionName , templateTypeName , action . TemplateName )
2018-10-13 01:42:33 +02:00
2018-10-15 03:31:14 +02:00
switch action . Type {
case pb . ActionDeploySettingsTemplate_FULL_SETTINGS :
// ToDo: Implement
case pb . ActionDeploySettingsTemplate_NETWORK :
_ , err := tam . rootSvc . SubSysRPC . DeployStoredEthernetInterfaceSettings ( context . Background ( ) , & pb . StringMessage { Msg : action . TemplateName } )
if err == nil {
fmt . Println ( "... stored settings deployed" )
} else {
fmt . Println ( "... deploying stored settings failed: " , err . Error ( ) )
}
case pb . ActionDeploySettingsTemplate_USB :
2018-10-15 14:29:46 +02:00
_ , err := tam . rootSvc . SubSysRPC . DeployStoredUSBSettings ( context . Background ( ) , & pb . StringMessage { Msg : action . TemplateName } )
if err == nil {
fmt . Println ( "... stored settings deployed" )
} else {
fmt . Println ( "... deploying stored settings failed: " , err . Error ( ) )
}
2018-10-15 03:31:14 +02:00
case pb . ActionDeploySettingsTemplate_WIFI :
_ , err := tam . rootSvc . SubSysRPC . DeployStoredWifiSettings ( context . Background ( ) , & pb . StringMessage { Msg : action . TemplateName } )
if err == nil {
fmt . Println ( "... stored settings deployed" )
} else {
fmt . Println ( "... deploying stored settings failed: " , err . Error ( ) )
}
case pb . ActionDeploySettingsTemplate_BLUETOOTH :
// ToDo: Implement
case pb . ActionDeploySettingsTemplate_TRIGGER_ACTIONS :
_ , err := tam . rootSvc . SubSysRPC . DeployStoredTriggerActionSetReplace ( context . Background ( ) , & pb . StringMessage { Msg : action . TemplateName } )
if err == nil {
fmt . Println ( "... stored settings deployed" )
} else {
fmt . Println ( "... deploying stored settings failed: " , err . Error ( ) )
}
}
2018-09-26 12:37:51 +02:00
}
2018-10-13 01:42:33 +02:00
func ( tam * TriggerActionManager ) executeActionGPIOOut ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType , action * pb . ActionGPIOOut ) {
triggerName := triggerTypeString [ tt ]
actionName := actionTypeString [ at ]
gpioNumName := pb . GPIONum_name [ int32 ( action . GpioNum ) ]
fmt . Printf ( "Trigger '%s' fired -> executing action '%s' ('%s')\n" , triggerName , actionName , gpioNumName )
// ToDo: Implement
2018-09-26 12:37:51 +02:00
}
2018-10-13 19:43:04 +02:00
func ( tam * TriggerActionManager ) executeActionGroupSend ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType , action * pb . ActionGroupSend ) {
triggerName := triggerTypeString [ tt ]
actionName := actionTypeString [ at ]
groupName := action . GroupName
value := action . Value
fmt . Printf ( "Trigger '%s' fired -> executing action '%s' ('%s': %d)\n" , triggerName , actionName , groupName , value )
tam . rootSvc . SubSysEvent . Emit ( ConstructEventTriggerGroupReceive ( groupName , value ) )
}
2018-10-13 01:42:33 +02:00
func ( tam * TriggerActionManager ) executeActionStartHidScript ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType , action * pb . ActionStartHIDScript ) {
triggerName := triggerTypeString [ tt ]
actionName := actionTypeString [ at ]
fmt . Printf ( "Trigger '%s' fired -> executing action '%s' ('%s')\n" , triggerName , actionName , action . ScriptName )
2018-10-13 15:34:46 +02:00
scriptPath := PATH_HID_SCRIPTS + "/" + action . ScriptName
2018-10-15 10:26:57 +02:00
preScript := fmt . Sprintf ( "var TRIGGER='%s';\n" , triggerName )
2018-10-13 15:34:46 +02:00
switch tt {
case triggerTypeGpioIn :
gpioPin := ta . Trigger . ( * pb . TriggerAction_GpioIn ) . GpioIn . GpioNum
gpioPinName := pb . GPIONum_name [ int32 ( gpioPin ) ]
2018-10-26 11:41:24 +02:00
preScript += fmt . Sprintf ( "var GPIO_PIN='%s';\n" , gpioPinName )
2018-10-26 16:58:27 +02:00
case triggerTypeGroupReceiveMulti :
groupName := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . GroupName
values := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . Values
rtype := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . Type
2018-10-13 15:34:46 +02:00
// create bash array of values
jsArray := "["
for idx , v := range values {
if idx >= len ( values ) - 1 {
jsArray += fmt . Sprintf ( "%d" , v )
} else {
jsArray += fmt . Sprintf ( "%d, " , v )
}
}
jsArray += "]"
2018-10-15 10:26:57 +02:00
preScript += fmt . Sprintf ( "var GROUP='%s';\n" , groupName )
2018-10-13 15:34:46 +02:00
preScript += fmt . Sprintf ( "var VALUES=%s;\n" , jsArray )
2018-10-26 16:58:27 +02:00
preScript += fmt . Sprintf ( "var MULTI_TYPE='%s';\n" , pb . GroupReceiveMultiType_name [ int32 ( rtype ) ] )
2018-10-13 15:34:46 +02:00
case triggerTypeGroupReceive :
groupName := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . GroupName
value := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . Value
2018-10-15 10:26:57 +02:00
preScript += fmt . Sprintf ( "var GROUP='%s';\n" , groupName )
preScript += fmt . Sprintf ( "var VALUE=%d;\n" , value )
2018-10-13 15:34:46 +02:00
case triggerTypeDhcpLeaseGranted :
iface := evt . Values [ 1 ] . GetTstring ( )
mac := evt . Values [ 2 ] . GetTstring ( )
ip := evt . Values [ 3 ] . GetTstring ( )
2018-10-26 11:41:24 +02:00
host := evt . Values [ 4 ] . GetTstring ( )
preScript += fmt . Sprintf ( "var DHCP_LEASE_IFACE='%s';\n" , iface )
preScript += fmt . Sprintf ( "var DHCP_LEASE_MAC='%s';\n" , mac )
preScript += fmt . Sprintf ( "var DHCP_LEASE_IP='%s';\n" , ip )
preScript += fmt . Sprintf ( "var DHCP_LEASE_HOST='%s';\n" , host )
2018-10-13 15:34:46 +02:00
case triggerTypeSshLogin :
loginUser := evt . Values [ 1 ] . GetTstring ( )
2018-10-26 11:41:24 +02:00
preScript += fmt . Sprintf ( "var SSH_LOGIN_USER='%s';\n" , loginUser )
2018-10-13 15:34:46 +02:00
}
err := tam . rootSvc . SubSysUSB . HidScriptUsable ( )
if err != nil { return }
scriptFile , err := ioutil . ReadFile ( scriptPath )
if err != nil {
fmt . Printf ( "Couldn't load HIDScript '%s': %v\n" , scriptPath , err )
return
}
newScriptFile := preScript + string ( scriptFile )
_ , err = tam . rootSvc . SubSysUSB . HidScriptStartBackground ( context . Background ( ) , newScriptFile )
if err != nil {
fmt . Printf ( "Couldn't start HIDScript as background job'%s': %v\n" , action . ScriptName , err )
return
}
return
2018-10-13 01:42:33 +02:00
}
func ( tam * TriggerActionManager ) executeActionBashScript ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType , action * pb . ActionStartBashScript ) {
triggerName := triggerTypeString [ tt ]
actionName := actionTypeString [ at ]
scriptPath := PATH_BASH_SCRIPTS + "/" + action . ScriptName
env := [ ] string {
fmt . Sprintf ( "TRIGGER=%s" , triggerName ) ,
}
switch tt {
case triggerTypeGpioIn :
gpioPin := ta . Trigger . ( * pb . TriggerAction_GpioIn ) . GpioIn . GpioNum
gpioPinName := pb . GPIONum_name [ int32 ( gpioPin ) ]
env = append ( env , fmt . Sprintf ( "GPIO_PIN=%s" , gpioPinName ) )
2018-10-26 16:58:27 +02:00
case triggerTypeGroupReceiveMulti :
groupName := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . GroupName
values := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . Values
rtype := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . Type
2018-10-13 01:42:33 +02:00
// create bash array of values
bashArray := "("
for _ , v := range values { bashArray += fmt . Sprintf ( "%d " , v ) }
bashArray += ")"
env = append ( env ,
fmt . Sprintf ( "GROUP='%s'" , groupName ) ,
fmt . Sprintf ( "VALUES=%s" , bashArray ) ,
2018-10-26 16:58:27 +02:00
fmt . Sprintf ( "MULTI_TYPE='%s'" , pb . GroupReceiveMultiType_name [ int32 ( rtype ) ] ) ,
2018-10-13 01:42:33 +02:00
)
case triggerTypeGroupReceive :
groupName := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . GroupName
value := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . Value
env = append ( env ,
fmt . Sprintf ( "GROUP='%s'" , groupName ) ,
2018-10-13 15:34:46 +02:00
fmt . Sprintf ( "VALUE=%d" , value ) ,
2018-10-13 01:42:33 +02:00
)
case triggerTypeDhcpLeaseGranted :
iface := evt . Values [ 1 ] . GetTstring ( )
mac := evt . Values [ 2 ] . GetTstring ( )
ip := evt . Values [ 3 ] . GetTstring ( )
2018-10-26 11:41:24 +02:00
host := evt . Values [ 4 ] . GetTstring ( )
2018-10-13 01:42:33 +02:00
env = append ( env ,
fmt . Sprintf ( "DHCP_LEASE_IFACE=%s" , iface ) ,
fmt . Sprintf ( "DHCP_LEASE_MAC=%s" , mac ) ,
fmt . Sprintf ( "DHCP_LEASE_IP=%s" , ip ) ,
2018-10-26 11:41:24 +02:00
fmt . Sprintf ( "DHCP_LEASE_HOST=\"%s\"" , host ) ,
2018-10-13 01:42:33 +02:00
)
case triggerTypeSshLogin :
loginUser := evt . Values [ 1 ] . GetTstring ( )
env = append ( env ,
fmt . Sprintf ( "SSH_LOGIN_USER=%s" , loginUser ) ,
)
}
fmt . Printf ( "Trigger '%s' fired -> executing action '%s' ('%s')\n" , triggerName , actionName , scriptPath )
common . RunBashScriptEnv ( scriptPath , env ... )
}
func ( tam * TriggerActionManager ) executeActionLog ( evt * pb . Event , ta * pb . TriggerAction , tt triggerType , at actionType , action * pb . ActionLog ) {
triggerName := triggerTypeString [ tt ]
actionName := actionTypeString [ at ]
logMessage := fmt . Sprintf ( "Trigger fired: %s" , triggerName )
switch tt {
case triggerTypeGpioIn :
gpioPin := ta . Trigger . ( * pb . TriggerAction_GpioIn ) . GpioIn . GpioNum
gpioPinName := pb . GPIONum_name [ int32 ( gpioPin ) ]
logMessage += fmt . Sprintf ( " (GPIO_PIN=%s)" , gpioPinName )
2018-10-26 16:58:27 +02:00
case triggerTypeGroupReceiveMulti :
groupName := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . GroupName
values := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . Values
2018-10-13 01:42:33 +02:00
logMessage += fmt . Sprintf ( " (GROUP='%s', VALUES=%v)" , groupName , values )
case triggerTypeGroupReceive :
groupName := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . GroupName
2018-10-26 16:58:27 +02:00
values := ta . Trigger . ( * pb . TriggerAction_GroupReceive ) . GroupReceive . Value
typeName := pb . GroupReceiveMultiType_name [ int32 ( ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) . GroupReceiveMulti . Type ) ]
logMessage += fmt . Sprintf ( " (GROUP='%s', VALUES=%+v, VALUE='%d')" , groupName , values , typeName )
2018-10-13 01:42:33 +02:00
case triggerTypeDhcpLeaseGranted :
iface := evt . Values [ 1 ] . GetTstring ( )
mac := evt . Values [ 2 ] . GetTstring ( )
ip := evt . Values [ 3 ] . GetTstring ( )
2018-10-26 11:41:24 +02:00
host := evt . Values [ 4 ] . GetTstring ( )
logMessage += fmt . Sprintf ( " (DHCP_LEASE_IFACE=%s, DHCP_LEASE_MAC=%s, DHCP_LEASE_IP=%s, DHCP_LEASE_HOST='%s')" , iface , mac , ip , host )
2018-10-13 01:42:33 +02:00
case triggerTypeSshLogin :
loginUser := evt . Values [ 1 ] . GetTstring ( )
logMessage += fmt . Sprintf ( " (SSH_LOGIN_USER=%s)" , loginUser )
}
fmt . Printf ( "Trigger '%s' fired -> executing action '%s'\n" , triggerName , actionName )
tam . rootSvc . SubSysEvent . Emit ( ConstructEventLog ( "TriggerAction" , 0 , logMessage ) )
}
2018-09-26 12:37:51 +02:00
// checks if the triggerType of the given event (if trigger event at all), matches the TriggerType of the TriggerAction
2018-10-13 01:42:33 +02:00
func taTriggerTypeMatchesEvtTriggerType ( ttype triggerType , evt * pb . Event ) bool {
2018-09-26 12:37:51 +02:00
if evt . Type != common_web . EVT_TRIGGER { return false }
triggerTypeEvt := common_web . EvtTriggerType ( evt . Values [ 0 ] . GetTint64 ( ) )
switch triggerTypeEvt {
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_SERVICE_STARTED :
if ttype == triggerTypeServiceStarted {
2018-09-26 12:37:51 +02:00
return true
}
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_DHCP_LEASE_GRANTED :
if ttype == triggerTypeDhcpLeaseGranted {
2018-09-26 12:37:51 +02:00
return true
}
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_WIFI_AP_STARTED :
if ttype == triggerTypeWifiAPStarted {
2018-09-26 12:37:51 +02:00
return true
}
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_WIFI_CONNECTED_AS_STA :
if ttype == triggerTypeWifiConnectedAsSta {
2018-09-26 12:37:51 +02:00
return true
}
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_USB_GADGET_CONNECTED :
if ttype == triggerTypeUsbGadgetConnected {
2018-09-26 12:37:51 +02:00
return true
}
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_USB_GADGET_DISCONNECTED :
if ttype == triggerTypeUsbGadgetDisconnected {
2018-09-26 12:37:51 +02:00
return true
}
2018-10-13 01:42:33 +02:00
case common_web . TRIGGER_EVT_TYPE_SSH_LOGIN :
if ttype == triggerTypeSshLogin {
return true
}
case common_web . TRIGGER_EVT_TYPE_GROUP_RECEIVE :
2018-10-26 16:58:27 +02:00
if ttype == triggerTypeGroupReceive || ttype == triggerTypeGroupReceiveMulti {
2018-10-13 01:42:33 +02:00
return true
}
case common_web . TRIGGER_EVT_TYPE_GPIO_IN :
if ttype == triggerTypeGpioIn {
2018-09-26 12:37:51 +02:00
return true
}
default :
return false
}
2018-10-13 01:42:33 +02:00
return false
2018-09-26 12:37:51 +02:00
}
2018-10-13 01:42:33 +02:00
2018-10-01 17:28:24 +02:00
// returns the TriggerAction with assigned ID
func ( tam * TriggerActionManager ) AddTriggerAction ( ta * pb . TriggerAction ) ( taAdded * pb . TriggerAction , err error ) {
2018-09-26 00:04:48 +02:00
tam . registeredTriggerActionMutex . Lock ( )
defer tam . registeredTriggerActionMutex . Unlock ( )
ta . Id = tam . nextID
tam . nextID ++
2018-10-12 13:51:58 +02:00
tam . registeredTriggerActions . TriggerActions = append ( tam . registeredTriggerActions . TriggerActions , ta )
taAdded = ta
2018-09-26 12:37:51 +02:00
2018-10-13 01:42:33 +02:00
//if new ta trigger is GroupReceiveSequence, add a SequenceChecker
2018-10-26 16:58:27 +02:00
if triggerGrpRcv , match := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) ; match {
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Lock ( )
2018-10-13 12:44:11 +02:00
//fmt.Printf("##### New val checker %+v\n", triggerGrpRcv.GroupReceiveSequence.Values)
2018-10-26 16:58:27 +02:00
switch triggerGrpRcv . GroupReceiveMulti . Type {
case pb . GroupReceiveMultiType_AND :
tam . groupReceiveSequenceCheckers [ ta ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_AND )
case pb . GroupReceiveMultiType_OR :
tam . groupReceiveSequenceCheckers [ ta ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_OR )
case pb . GroupReceiveMultiType_SEQUENCE :
tam . groupReceiveSequenceCheckers [ ta ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_SEQUENCE )
case pb . GroupReceiveMultiType_EXACT_SEQUENCE :
tam . groupReceiveSequenceCheckers [ ta ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_EXACT_SEQUENCE )
}
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Unlock ( )
}
2018-10-01 17:28:24 +02:00
return taAdded , nil
}
2018-10-12 13:51:58 +02:00
// removes the given TriggerAction
// ToDo: for now only the ID is compared, to assure we don't remove a TriggerAction which has been changed meanwhile, we should deep-compare the whole object
func ( tam * TriggerActionManager ) RemoveTriggerAction ( removeTa * pb . TriggerAction ) ( taRemoved * pb . TriggerAction , err error ) {
tam . registeredTriggerActionMutex . Lock ( )
defer tam . registeredTriggerActionMutex . Unlock ( )
for idx , ta := range tam . registeredTriggerActions . TriggerActions {
if ta . Id == removeTa . Id {
// remove element (not a problem for running `for`-loop, as it is interrupted here)
tam . registeredTriggerActions . TriggerActions = append ( tam . registeredTriggerActions . TriggerActions [ : idx ] , tam . registeredTriggerActions . TriggerActions [ idx + 1 : ] ... )
2018-10-13 01:42:33 +02:00
//if target ta trigger had a sequenceChecker assigned, remove it
2018-10-26 16:58:27 +02:00
if _ , match := ta . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) ; match {
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Lock ( )
delete ( tam . groupReceiveSequenceCheckers , ta )
tam . groupReceiveSequenceCheckersMutex . Unlock ( )
}
2018-10-12 13:51:58 +02:00
return ta , nil
}
}
return nil , ErrTaNotFound
}
2018-10-01 17:28:24 +02:00
func ( tam * TriggerActionManager ) GetTriggerActionByID ( Id uint32 ) ( ta * pb . TriggerAction , err error ) {
2018-10-12 13:51:58 +02:00
for _ , ta = range tam . registeredTriggerActions . TriggerActions {
2018-10-01 17:28:24 +02:00
if ta . Id == Id {
return ta , nil
}
}
return nil , ErrTaNotFound
}
func ( tam * TriggerActionManager ) UpdateTriggerAction ( srcTa * pb . TriggerAction , addIfMissing bool ) ( err error ) {
tam . registeredTriggerActionMutex . Lock ( )
defer tam . registeredTriggerActionMutex . Unlock ( )
if targetTA , err := tam . GetTriggerActionByID ( srcTa . Id ) ; err != nil {
if addIfMissing {
_ , err = tam . AddTriggerAction ( srcTa )
return err
} else {
return ErrTaNotFound
}
} else {
if targetTA . Immutable { return ErrTaImmutable }
2018-10-13 01:42:33 +02:00
//if target ta trigger had a sequenceChecker assigned, remove it
2018-10-26 16:58:27 +02:00
if _ , match := targetTA . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) ; match {
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Lock ( )
delete ( tam . groupReceiveSequenceCheckers , targetTA )
tam . groupReceiveSequenceCheckersMutex . Unlock ( )
}
2018-10-01 17:28:24 +02:00
targetTA . OneShot = srcTa . OneShot
targetTA . IsActive = srcTa . IsActive
targetTA . Immutable = srcTa . Immutable
targetTA . Action = srcTa . Action
targetTA . Trigger = srcTa . Trigger
2018-10-13 01:42:33 +02:00
//if new ta trigger is GroupReceiveSequence, add a SequenceChecker
2018-10-26 16:58:27 +02:00
if triggerGrpRcv , match := targetTA . Trigger . ( * pb . TriggerAction_GroupReceiveMulti ) ; match {
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Lock ( )
2018-10-26 16:58:27 +02:00
switch triggerGrpRcv . GroupReceiveMulti . Type {
case pb . GroupReceiveMultiType_AND :
tam . groupReceiveSequenceCheckers [ targetTA ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_AND )
case pb . GroupReceiveMultiType_OR :
tam . groupReceiveSequenceCheckers [ targetTA ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_OR )
case pb . GroupReceiveMultiType_SEQUENCE :
tam . groupReceiveSequenceCheckers [ targetTA ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_SEQUENCE )
case pb . GroupReceiveMultiType_EXACT_SEQUENCE :
tam . groupReceiveSequenceCheckers [ targetTA ] = util . NewValueSequenceChecker ( triggerGrpRcv . GroupReceiveMulti . Values , util . ValueSeqType_EXACT_SEQUENCE )
}
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Unlock ( )
}
2018-10-01 17:28:24 +02:00
return nil
}
2018-10-13 01:42:33 +02:00
2018-10-01 17:28:24 +02:00
}
func ( tam * TriggerActionManager ) ClearTriggerActions ( keepImmutable bool ) ( err error ) {
tam . registeredTriggerActionMutex . Lock ( )
defer tam . registeredTriggerActionMutex . Unlock ( )
if ! keepImmutable {
2018-10-12 13:51:58 +02:00
tam . registeredTriggerActions . TriggerActions = [ ] * pb . TriggerAction { }
2018-10-01 17:28:24 +02:00
return
}
newTas := [ ] * pb . TriggerAction { }
2018-10-12 13:51:58 +02:00
for _ , ta := range tam . registeredTriggerActions . TriggerActions {
2018-10-01 17:28:24 +02:00
if ta . Immutable {
newTas = append ( newTas , ta )
}
}
2018-10-12 13:51:58 +02:00
tam . registeredTriggerActions . TriggerActions = newTas
2018-10-13 01:42:33 +02:00
tam . groupReceiveSequenceCheckersMutex . Lock ( )
defer tam . groupReceiveSequenceCheckersMutex . Unlock ( )
tam . groupReceiveSequenceCheckers = make ( map [ * pb . TriggerAction ] * util . ValueSequenceChecker )
2018-09-26 00:04:48 +02:00
return nil
}
2018-10-01 17:28:24 +02:00
func ( tam * TriggerActionManager ) GetCurrentTriggerActionSet ( ) ( ta * pb . TriggerActionSet ) {
2018-10-12 13:51:58 +02:00
/ *
2018-10-01 17:28:24 +02:00
tam . registeredTriggerActionMutex . Lock ( )
2018-10-12 13:51:58 +02:00
resTAs := make ( [ ] * pb . TriggerAction , len ( tam . registeredTriggerActions . TriggerActions ) )
copy ( resTAs , tam . registeredTriggerActions . TriggerActions )
2018-10-01 17:28:24 +02:00
tam . registeredTriggerActionMutex . Unlock ( )
return & pb . TriggerActionSet { TriggerActions : resTAs }
2018-10-12 13:51:58 +02:00
* /
return & tam . registeredTriggerActions
2018-10-01 17:28:24 +02:00
}
2018-09-26 00:04:48 +02:00
func ( tam * TriggerActionManager ) Start ( ) {
2018-10-13 01:42:33 +02:00
tam . evtRcv = tam . rootSvc . SubSysEvent . RegisterReceiver ( common_web . EVT_TRIGGER )
2018-09-26 00:04:48 +02:00
go tam . processing_loop ( )
}
func ( tam * TriggerActionManager ) Stop ( ) {
tam . rootSvc . SubSysEvent . UnregisterReceiver ( tam . evtRcv ) // should end the processing loop, as the context of the event receiver is closed
}
func NewTriggerActionManager ( rootService * Service ) ( tam * TriggerActionManager ) {
tam = & TriggerActionManager {
2018-10-12 13:51:58 +02:00
registeredTriggerActions : pb . TriggerActionSet {
Name : "DeployedTriggerActions" ,
TriggerActions : [ ] * pb . TriggerAction { } ,
} ,
2018-09-26 00:04:48 +02:00
registeredTriggerActionMutex : & sync . Mutex { } ,
rootSvc : rootService ,
2018-10-13 01:42:33 +02:00
groupReceiveSequenceCheckers : make ( map [ * pb . TriggerAction ] * util . ValueSequenceChecker ) ,
groupReceiveSequenceCheckersMutex : & sync . Mutex { } ,
2018-09-26 00:04:48 +02:00
}
2018-09-26 12:37:51 +02:00
2018-09-26 00:04:48 +02:00
return tam
}