diff --git a/common_web/EventConst.go b/common_web/EventConst.go index 5bac8de..0168247 100644 --- a/common_web/EventConst.go +++ b/common_web/EventConst.go @@ -1,12 +1,20 @@ package common_web const ( - EVT_ANY = int64(0) - EVT_LOG = int64(1) - EVT_HID = int64(3) - EVT_TRIGGER = int64(4) + EVT_ANY = int64(0) + EVT_LOG = int64(1) + EVT_HID = int64(3) + EVT_TRIGGER = int64(4) + EVT_NOTIFY_STATE_CHANGE = int64(5) // fired if settings or a state changes (inform client about needed state update) ) +var EventTypeName = map[int64]string{ + EVT_TRIGGER: "TRIGGER", + EVT_LOG: "LOG", + EVT_NOTIFY_STATE_CHANGE: "NOTIFY_STATE_CHANGE", + EVT_HID: "HID", +} + type EvtTriggerType int64 const ( @@ -21,6 +29,37 @@ const ( TRIGGER_EVT_TYPE_GROUP_RECEIVE = EvtTriggerType(8) //used for group receive and group receive sequence ) +type EvtStateChangeType int64 + +const ( + STATE_CHANGE_EVT_TYPE_USB = EvtStateChangeType(0) + STATE_CHANGE_EVT_TYPE_WIFI = EvtStateChangeType(1) + STATE_CHANGE_EVT_TYPE_NETWORK = EvtStateChangeType(2) + STATE_CHANGE_EVT_TYPE_BLUETOOTH = EvtStateChangeType(3) + STATE_CHANGE_EVT_TYPE_HID = EvtStateChangeType(4) + STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS = EvtStateChangeType(5) + STATE_CHANGE_EVT_TYPE_LED = EvtStateChangeType(6) + + STATE_CHANGE_EVT_TYPE_STORED_HID_SCRIPTS_LIST = EvtStateChangeType(7) + STATE_CHANGE_EVT_TYPE_STORED_USB_SETTINGS_LIST = EvtStateChangeType(8) + STATE_CHANGE_EVT_TYPE_STORED_ETHERNET_INTERFACE_SETTINGS_LIST = EvtStateChangeType(9) + STATE_CHANGE_EVT_TYPE_STORED_WIFI_SETTINGS_LIST = EvtStateChangeType(10) + STATE_CHANGE_EVT_TYPE_STORED_BLUETOOTH_SETTINGS_LIST = EvtStateChangeType(11) + STATE_CHANGE_EVT_TYPE_STORED_TRIGGER_ACTION_SETS_LIST = EvtStateChangeType(12) + STATE_CHANGE_EVT_TYPE_STORED_BASH_SCRIPTS_LIST = EvtStateChangeType(13) + STATE_CHANGE_EVT_TYPE_STORED_GLOBAL_SETTINGS_LIST = EvtStateChangeType(14) +) + +var EventTypeStateChangeName = map[int64]string{ + int64(STATE_CHANGE_EVT_TYPE_USB): "USB", + int64(STATE_CHANGE_EVT_TYPE_WIFI): "WIFI", + int64(STATE_CHANGE_EVT_TYPE_NETWORK): "NETWORK", + int64(STATE_CHANGE_EVT_TYPE_BLUETOOTH): "BLUETOOTH", + int64(STATE_CHANGE_EVT_TYPE_HID): "HID", + int64(STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS): "TRIGGER_ACTIONS", + int64(STATE_CHANGE_EVT_TYPE_LED): "LED", +} + const ( HidEventType_JOB_STARTED = int64(0) HidEventType_JOB_STOPPED = int64(1) @@ -34,7 +73,7 @@ const ( HidEventType_JOB_NO_FREE_VM = int64(9) ) -var EventType_name = map[int64]string{ +var EventTypeHIDName = map[int64]string{ 0: "JOB STARTED", 1: "JOB STOPPED", 2: "CONTROLLER ABORTED", diff --git a/service/Event.go b/service/Event.go index 0a88be9..9233c6b 100644 --- a/service/Event.go +++ b/service/Event.go @@ -156,8 +156,16 @@ type EventReceiver struct { FilterEventType int64 } -func ConstructEventLog(source string, level int, message string) *pb.Event { +func ConstructEventNotifyStateChange(stateType common_web.EvtStateChangeType) *pb.Event { + return &pb.Event{ + Type: common_web.EVT_NOTIFY_STATE_CHANGE, + Values: []*pb.EventValue{ + {Val: &pb.EventValue_Tint64{Tint64: int64(stateType)}}, + }, + } +} +func ConstructEventLog(source string, level int, message string) *pb.Event { tJson, _ := time.Now().MarshalJSON() return &pb.Event{ diff --git a/service/rpc_server.go b/service/rpc_server.go index cf0a934..5bd034e 100644 --- a/service/rpc_server.go +++ b/service/rpc_server.go @@ -114,6 +114,7 @@ func (s *server) FireActionGroupSend(ctx context.Context, gs *pb.ActionGroupSend } func (s *server) DeployBluetoothSettings(ctx context.Context, settings *pb.BluetoothSettings) (resultSettings *pb.BluetoothSettings, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_BLUETOOTH)) as := settings.As ci := settings.Ci resultSettings = &pb.BluetoothSettings{} @@ -127,6 +128,7 @@ func (s *server) DeployBluetoothSettings(ctx context.Context, settings *pb.Bluet } func (s *server) StoreBluetoothSettings(ctx context.Context, req *pb.BluetoothRequestSettingsStorage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_BLUETOOTH_SETTINGS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Put(cSTORE_PREFIX_BLUETOOTH_SETTINGS + req.TemplateName, req.Settings, true) return @@ -139,18 +141,21 @@ func (s *server) GetStoredBluetoothSettings(ctx context.Context, templateName *p } func (s *server) DeployStoredBluetoothSettings(ctx context.Context, templateName *pb.StringMessage) (e *pb.BluetoothSettings, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_BLUETOOTH)) bts,err := s.GetStoredBluetoothSettings(ctx,templateName) if err != nil { return bts,err } return s.DeployBluetoothSettings(ctx, bts) } func (s *server) DeleteStoredBluetoothSettings(ctx context.Context, templateName *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_BLUETOOTH_SETTINGS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Delete(cSTORE_PREFIX_BLUETOOTH_SETTINGS + templateName.Msg) return } func (s *server) StoreDeployedBluetoothSettings(ctx context.Context, templateName *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_BLUETOOTH_SETTINGS_LIST)) e = &pb.Empty{} currentSettings := &pb.BluetoothSettings{} currentSettings.Ci,err = s.GetBluetoothControllerInformation(ctx, e) @@ -173,24 +178,28 @@ func (s *server) ListStoredBluetoothSettings(ctx context.Context, e *pb.Empty) ( } func (s *server) DeleteStoredUSBSettings(ctx context.Context, name *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_USB_SETTINGS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Delete(cSTORE_PREFIX_USB_SETTINGS + name.Msg) return } func (s *server) DeleteStoredWifiSettings(ctx context.Context, name *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_WIFI_SETTINGS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Delete(cSTORE_PREFIX_WIFI_SETTINGS + name.Msg) return } func (s *server) DeleteStoredEthernetInterfaceSettings(ctx context.Context, name *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_ETHERNET_INTERFACE_SETTINGS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Delete(cSTORE_PREFIX_ETHERNET_INTERFACE_SETTINGS + name.Msg) return } func (s *server) DeleteStoredTriggerActionSet(ctx context.Context, name *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_TRIGGER_ACTION_SETS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Delete(cSTORE_PREFIX_TRIGGER_ACTION_SET + name.Msg) return @@ -235,17 +244,20 @@ func (s *server) GetBluetoothAgentSettings(ctx context.Context, e *pb.Empty) (as } func (s *server) DeployBluetoothAgentSettings(ctx context.Context, src *pb.BluetoothAgentSettings) (res *pb.BluetoothAgentSettings, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_BLUETOOTH)) return s.rootSvc.SubSysBluetooth.DeployBluetoothAgentSettings(src) } // Unused, Server services are deployed via BluetoothControllerInformation func (s *server) SetBluetoothNetworkService(ctx context.Context, btNwSvc *pb.BluetoothNetworkService) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_BLUETOOTH)) e = &pb.Empty{} err = s.rootSvc.SubSysBluetooth.DeployBluetoothNetworkService(btNwSvc) return } func (s *server) DeployBluetoothControllerInformation(ctx context.Context, newBtCiRpc *pb.BluetoothControllerInformation) (updateBtCiRpc *pb.BluetoothControllerInformation, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_BLUETOOTH)) return s.rootSvc.SubSysBluetooth.DeployBluetoothControllerInformation(newBtCiRpc) } @@ -255,6 +267,7 @@ func (s *server) GetBluetoothControllerInformation(ctx context.Context, e *pb.Em } func (s *server) StoreUSBSettings(ctx context.Context, r *pb.USBRequestSettingsStorage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_USB_SETTINGS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Put(cSTORE_PREFIX_USB_SETTINGS + r.TemplateName, r.Settings, true) return @@ -267,6 +280,7 @@ func (s *server) GetStoredUSBSettings(ctx context.Context, m *pb.StringMessage) } func (s *server) DeployStoredUSBSettings(ctx context.Context, m *pb.StringMessage) (st *pb.GadgetSettings, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_USB)) ws,err := s.GetStoredUSBSettings(ctx,m) if err != nil { return &pb.GadgetSettings{},err } st,err = s.SetGadgetSettings(ctx, ws) @@ -312,6 +326,7 @@ func (s *server) ListStoredBashScripts(context.Context, *pb.Empty) (sa *pb.Strin } func (s *server) DeployStoredTriggerActionSetReplace(ctx context.Context, msg *pb.StringMessage) (tas *pb.TriggerActionSet, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS)) // load set from store tas = &pb.TriggerActionSet{} err = s.rootSvc.SubSysDataStore.Get(cSTORE_PREFIX_TRIGGER_ACTION_SET + msg.Msg, tas) @@ -321,6 +336,7 @@ func (s *server) DeployStoredTriggerActionSetReplace(ctx context.Context, msg *p } func (s *server) DeployStoredTriggerActionSetAdd(ctx context.Context, msg *pb.StringMessage) (tas *pb.TriggerActionSet, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS)) // load set from store tas = &pb.TriggerActionSet{} err = s.rootSvc.SubSysDataStore.Get(cSTORE_PREFIX_TRIGGER_ACTION_SET + msg.Msg, tas) @@ -330,6 +346,7 @@ func (s *server) DeployStoredTriggerActionSetAdd(ctx context.Context, msg *pb.St } func (s *server) StoreTriggerActionSet(ctx context.Context, set *pb.TriggerActionSet) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_TRIGGER_ACTION_SETS_LIST)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Put(cSTORE_PREFIX_TRIGGER_ACTION_SET+ set.Name, set, true) return @@ -350,6 +367,7 @@ func (s *server) GetDeployedTriggerActionSet(context.Context, *pb.Empty) (*pb.Tr } func (s *server) DeployTriggerActionSetReplace(ctx context.Context, tas *pb.TriggerActionSet) (resTas *pb.TriggerActionSet, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS)) // Clear old set, but keep immutables s.rootSvc.SubSysTriggerActions.ClearTriggerActions(true) // Add the new set @@ -359,6 +377,7 @@ func (s *server) DeployTriggerActionSetReplace(ctx context.Context, tas *pb.Trig } func (s *server) DeployTriggerActionSetAdd(ctx context.Context, tas *pb.TriggerActionSet) (resTas *pb.TriggerActionSet, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS)) addedTA := make([]*pb.TriggerAction, 0) for _,ta := range tas.TriggerActions { // we don't allow adding immutable settings via RPC call @@ -374,6 +393,7 @@ func (s *server) DeployTriggerActionSetAdd(ctx context.Context, tas *pb.TriggerA } func (s *server) DeployTriggerActionSetRemove(ctx context.Context, removeTas *pb.TriggerActionSet) (removedTas *pb.TriggerActionSet, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS)) removedOnes := make([]*pb.TriggerAction,0) for _,removeTa := range removeTas.TriggerActions { removed,err := s.rootSvc.SubSysTriggerActions.RemoveTriggerAction(removeTa) @@ -394,6 +414,7 @@ func (s *server) Stop() error { } func (s *server) StoreDeployedWifiSettings(ctx context.Context, m *pb.StringMessage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_WIFI_SETTINGS_LIST)) return s.StoreWifiSettings(ctx, &pb.WifiRequestSettingsStorage{ Settings: s.rootSvc.SubSysWifi.State.CurrentSettings, TemplateName: m.Msg, @@ -401,12 +422,14 @@ func (s *server) StoreDeployedWifiSettings(ctx context.Context, m *pb.StringMess } func (s *server) DeployStoredWifiSettings(ctx context.Context, m *pb.StringMessage) (st *pb.WiFiState, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_WIFI)) ws,err := s.GetStoredWifiSettings(ctx,m) if err != nil { return &pb.WiFiState{},err } return s.DeployWiFiSettings(ctx, ws) } func (s *server) StoreWifiSettings(ctx context.Context, r *pb.WifiRequestSettingsStorage) (e *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_WIFI)) e = &pb.Empty{} err = s.rootSvc.SubSysDataStore.Put(cSTORE_PREFIX_WIFI_SETTINGS + r.TemplateName, r.Settings, true) return @@ -427,6 +450,7 @@ func (s *server) ListStoredWifiSettings(ctx context.Context, e *pb.Empty) (sa *p } func (s *server) DeployWiFiSettings(ctx context.Context, wset *pb.WiFiSettings) (wstate *pb.WiFiState, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_WIFI)) return s.rootSvc.SubSysWifi.DeploySettings(wset) } @@ -573,11 +597,13 @@ func (s *server) HIDGetRunningScriptJobs(ctx context.Context, rEmpty *pb.Empty) } func (s *server) HIDCancelAllScriptJobs(ctx context.Context, rEmpty *pb.Empty) (empty *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_HID)) err = s.rootSvc.SubSysUSB.HidScriptCancelAllRunningBackgroundJobs() return } func (s *server) HIDCancelScriptJob(ctx context.Context, sJob *pb.HIDScriptJob) (empty *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_HID)) job,err := s.rootSvc.SubSysUSB.HidScriptGetBackgroundJobByID(int(sJob.Id)) if err != nil { return nil, err } @@ -586,6 +612,7 @@ func (s *server) HIDCancelScriptJob(ctx context.Context, sJob *pb.HIDScriptJob) } func (s *server) HIDRunScript(ctx context.Context, scriptReq *pb.HIDScriptRequest) (scriptRes *pb.HIDScriptResult, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_HID)) err = s.rootSvc.SubSysUSB.HidScriptUsable() if err != nil { return } @@ -614,6 +641,7 @@ func (s *server) HIDRunScript(ctx context.Context, scriptReq *pb.HIDScriptReques } func (s *server) HIDRunScriptJob(ctx context.Context, scriptReq *pb.HIDScriptRequest) (rJob *pb.HIDScriptJob, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_HID)) err = s.rootSvc.SubSysUSB.HidScriptUsable() if err != nil { return } @@ -684,6 +712,7 @@ func (s *server) GetAllDeployedEthernetInterfaceSettings(ctx context.Context, em } func (s *server) DeployEthernetInterfaceSettings(ctx context.Context, es *pb.EthernetInterfaceSettings) (empty *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_NETWORK)) log.Printf("Trying to deploy ethernet interface settings %v", es) empty = &pb.Empty{} @@ -699,6 +728,7 @@ func (s *server) DeployEthernetInterfaceSettings(ctx context.Context, es *pb.Eth } func (s *server) StoreEthernetInterfaceSettings(ctx context.Context, req *pb.EthernetRequestSettingsStorage) (empty *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_STORED_ETHERNET_INTERFACE_SETTINGS_LIST)) empty = &pb.Empty{} ifName := req.Settings.Name storageKey := cSTORE_PREFIX_ETHERNET_INTERFACE_SETTINGS + ifName + "_" + req.TemplateName @@ -713,6 +743,7 @@ func (s *server) GetStoredEthernetInterfaceSettings(ctx context.Context, m *pb.S } func (s *server) DeployStoredEthernetInterfaceSettings(ctx context.Context, msg *pb.StringMessage) (empty *pb.Empty, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_HID)) eis,err := s.GetStoredEthernetInterfaceSettings(ctx, msg) if err != nil { return empty,err } return s.DeployEthernetInterfaceSettings(ctx, eis) @@ -727,6 +758,7 @@ func (s *server) ListStoredEthernetInterfaceSettings(ctx context.Context, empty } func (s *server) MountUMSFile(ctx context.Context, gsu *pb.GadgetSettingsUMS) (*pb.Empty, error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_USB)) log.Printf("Trying to mount iamge `%s` to UMS ...", gsu.File) err := MountUMSFile(gsu.File) return nil, err @@ -750,6 +782,7 @@ func (s *server) GetDeployedGadgetSetting(ctx context.Context, e *pb.Empty) (gs } func (s *server) DeployGadgetSetting(context.Context, *pb.Empty) (gs *pb.GadgetSettings, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_USB)) gs_backup,_ := ParseGadgetState(USB_GADGET_NAME) //ToDo: Former gadgets are destroyed without testing if there're changes, this should be aborted if GadgetSettingsState == GetDeployedGadgetSettings() @@ -771,6 +804,7 @@ func (s *server) GetGadgetSettings(context.Context, *pb.Empty) (*pb.GadgetSettin } func (s *server) SetGadgetSettings(ctx context.Context, gs *pb.GadgetSettings) (res *pb.GadgetSettings, err error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_USB)) if err = ValidateGadgetSetting(*gs); err != nil { //We return the validation error and the current (unchanged) GadgetSettingsState res = s.rootSvc.SubSysUSB.State.UndeployedGadgetSettings @@ -792,6 +826,7 @@ func (s *server) GetLEDSettings(context.Context, *pb.Empty) (res *pb.LEDSettings } func (s *server) SetLEDSettings(ctx context.Context, ls *pb.LEDSettings) (*pb.Empty, error) { + defer s.rootSvc.SubSysEvent.Emit(ConstructEventNotifyStateChange(common_web.STATE_CHANGE_EVT_TYPE_LED)) log.Printf("SetLEDSettings %+v", ls) s.rootSvc.SubSysLed.DeploySettings(ls) return &pb.Empty{}, nil diff --git a/web_client/hvueCompHIDEvents.go b/web_client/hvueCompHIDEvents.go index e90de73..5243ee4 100644 --- a/web_client/hvueCompHIDEvents.go +++ b/web_client/hvueCompHIDEvents.go @@ -27,11 +27,11 @@ func InitCompHIDEvents() { hvue.DataFunc(newCompHIDEventsData), hvue.Computed("events", func(vm *hvue.VM) interface{} { - return vm.Get("$store").Get("state").Get("eventReceiver").Get("eventHidArray") + return vm.Get("$store").Get("state").Get("EventProcessor").Get("eventHidArray") }), hvue.Method("evIdToString", func(vm *hvue.VM, evID int64) (res string) { println("EvID", evID) - return common_web.EventType_name[evID] + return common_web.EventTypeHIDName[evID] }), ) diff --git a/web_client/hvueCompLogger.go b/web_client/hvueCompLogger.go index abae902..4ff0368 100644 --- a/web_client/hvueCompLogger.go +++ b/web_client/hvueCompLogger.go @@ -48,7 +48,7 @@ func InitCompLogger() { }), hvue.Computed("logArray", func(vm *hvue.VM) interface{} { - return vm.Get("$store").Get("state").Get("eventReceiver").Get("logArray") + return vm.Get("$store").Get("state").Get("EventProcessor").Get("logArray") }), ) //return o.NewComponent() diff --git a/web_client/hvueComponentWiFi.go b/web_client/hvueComponentWiFi.go index c0a4bbb..235c3ea 100644 --- a/web_client/hvueComponentWiFi.go +++ b/web_client/hvueComponentWiFi.go @@ -197,7 +197,7 @@ const templateWiFi = `
-
+
diff --git a/web_client/hvueComponentsDialog.go b/web_client/hvueComponentsDialog.go index 4a7278a..8fd4535 100644 --- a/web_client/hvueComponentsDialog.go +++ b/web_client/hvueComponentsDialog.go @@ -129,6 +129,25 @@ func InitComponentsDialog() { hvue.Types(hvue.PBoolean), ), ) + + hvue.NewComponent( + "disconnect-modal", + hvue.Template(templateDisconnectModal), + hvue.ComputedWithGetSet( + "visible", + func(vm *hvue.VM) interface{} { + return vm.Get("value") + }, + func(vm *hvue.VM, newValue *js.Object) { + vm.Call("$emit", "input", newValue) + }, + ), + hvue.PropObj( + "value", + hvue.Required, + hvue.Types(hvue.PBoolean), + ), + ) } const templateSelectStringModal = ` @@ -196,9 +215,29 @@ const templateInputStringModal = `
` + +const templateDisconnectModal = ` +
+ + + + + Not connection to server + + + +
+

No connection to server

+

Trying to reconnect ... Attempt: {{ $store.state.ConnectRetryCount }}

+
+
+
+
+` + const templateRansomModal = `
- +
You became victim of a VERY SILLY IDEA
diff --git a/web_client/jsDataHandling.go b/web_client/jsDataHandling.go index 370a4de..68af4d9 100644 --- a/web_client/jsDataHandling.go +++ b/web_client/jsDataHandling.go @@ -636,12 +636,12 @@ func NewEthernetRequestSettingsStorage() *jsEthernetRequestSettingsStorage { -type jsEthernetSettingsList struct { +type jsEthernetSettingsArray struct { *js.Object Interfaces *js.Object `js:"interfaces"` //every object property represents an EthernetSettings struct, the key is the interface name } -func (isl *jsEthernetSettingsList) fromGo(src *pb.DeployedEthernetInterfaceSettings) { +func (isl *jsEthernetSettingsArray) fromGo(src *pb.DeployedEthernetInterfaceSettings) { //Options array (converted from map) isl.Interfaces = js.Global.Get("Array").New() for _, ifSets := range src.List { @@ -649,9 +649,28 @@ func (isl *jsEthernetSettingsList) fromGo(src *pb.DeployedEthernetInterfaceSetti jsIfSets.fromGo(ifSets) isl.Interfaces.Call("push", jsIfSets) } + + + // sort the resulting array + /* + store.state.InterfaceSettings.interfaces.sort(function(a,b) { + return a.name>b.name ? 1 : (a.name b.Name: + return 1 + case a.Name < b.Name: + return -1 + default: + return 0 + } + }) } -func (isl *jsEthernetSettingsList) updateSingleInterface(updatedSettings *jsEthernetInterfaceSettings) { +func (isl *jsEthernetSettingsArray) updateSingleInterface(updatedSettings *jsEthernetInterfaceSettings) { //Options array (converted from map) for i:=0; i"), @@ -125,7 +126,7 @@ const templateMainApp = ` - P4wnP1 web-frontend + P4wnP1 web-frontend ({{ $store.getters.isConnected }}) by MaMe82 @@ -153,12 +154,15 @@ const templateMainApp = ` - + + diff --git a/web_client/mvuexGlobalState.go b/web_client/mvuexGlobalState.go index 775b9bd..411563a 100644 --- a/web_client/mvuexGlobalState.go +++ b/web_client/mvuexGlobalState.go @@ -3,11 +3,14 @@ package main import ( + "context" "github.com/gopherjs/gopherjs/js" + "github.com/mame82/P4wnP1_go/common_web" pb "github.com/mame82/P4wnP1_go/proto/gopherjs" "github.com/mame82/hvue" "github.com/mame82/mvuex" "github.com/pkg/errors" + "io" "path/filepath" "strings" "time" @@ -15,24 +18,30 @@ import ( var globalState *GlobalState - - const ( maxLogEntries = 500 + VUEX_ACTION_UPDATE_ALL_STATES = "updateAllStates" + + //Events + VUEX_ACTION_START_EVENT_LISTEN = "startEventListen" + VUEX_ACTION_STOP_EVENT_LISTEN = "stopEventListen" + + VUEX_MUTATION_SET_EVENT_LISTENER_RUNNING = "setEventListenerRunning" + //Bluetooth VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION = "updateCurrentBluetoothControllerInformation" VUEX_ACTION_DEPLOY_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION = "deployCurrentBluetoothControllerInformation" - VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_AGENT_SETTINGS = "updateCurrentBluetoothAgentSettings" - VUEX_ACTION_DEPLOY_CURRENT_BLUETOOTH_AGENT_SETTINGS = "deployCurrentBluetoothAgentSettings" - VUEX_ACTION_STORE_BLUETOOTH_SETTINGS = "storedBluetoothSettings" - VUEX_ACTION_DELETE_STORED_BLUETOOTH_SETTINGS = "deleteStoredBluetoothSettings" - VUEX_ACTION_DEPLOY_STORED_BLUETOOTH_SETTINGS = "deployStoredBluetoothSettings" - VUEX_ACTION_UPDATE_STORED_BLUETOOTH_SETTINGS_LIST = "setStoredBluetoothSettingsList" + VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_AGENT_SETTINGS = "updateCurrentBluetoothAgentSettings" + VUEX_ACTION_DEPLOY_CURRENT_BLUETOOTH_AGENT_SETTINGS = "deployCurrentBluetoothAgentSettings" + VUEX_ACTION_STORE_BLUETOOTH_SETTINGS = "storedBluetoothSettings" + VUEX_ACTION_DELETE_STORED_BLUETOOTH_SETTINGS = "deleteStoredBluetoothSettings" + VUEX_ACTION_DEPLOY_STORED_BLUETOOTH_SETTINGS = "deployStoredBluetoothSettings" + VUEX_ACTION_UPDATE_STORED_BLUETOOTH_SETTINGS_LIST = "setStoredBluetoothSettingsList" VUEX_MUTATION_SET_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION = "setCurrentBluetoothControllerInformation" - VUEX_MUTATION_SET_CURRENT_BLUETOOTH_AGENT_SETTINGS = "setCurrentBluetoothAgentSettings" - VUEX_MUTATION_SET_STORED_BLUETOOTH_SETTINGS_LIST = "setStoredBluetoothSettingsList" + VUEX_MUTATION_SET_CURRENT_BLUETOOTH_AGENT_SETTINGS = "setCurrentBluetoothAgentSettings" + VUEX_MUTATION_SET_STORED_BLUETOOTH_SETTINGS_LIST = "setStoredBluetoothSettingsList" //HIDScripts and jobs VUEX_ACTION_UPDATE_RUNNING_HID_JOBS = "updateRunningHidJobs" @@ -107,29 +116,34 @@ const ( type GlobalState struct { *js.Object - Title string `js:"title"` - CurrentHIDScriptSource string `js:"currentHIDScriptSource"` - CurrentGadgetSettings *jsGadgetSettings `js:"currentGadgetSettings"` - CurrentlyDeployingGadgetSettings bool `js:"deployingGadgetSettings"` - CurrentlyDeployingWifiSettings bool `js:"deployingWifiSettings"` - EventReceiver *jsEventReceiver `js:"eventReceiver"` - HidJobList *jsHidJobStateList `js:"hidJobList"` - TriggerActionList *jsTriggerActionSet `js:"triggerActionList"` - IsModalEnabled bool `js:"isModalEnabled"` - IsConnected bool `js:"isConnected"` - FailedConnectionAttempts int `js:"failedConnectionAttempts"` - InterfaceSettings *jsEthernetSettingsList `js:"InterfaceSettings"` + Title string `js:"title"` + CurrentHIDScriptSource string `js:"currentHIDScriptSource"` + CurrentGadgetSettings *jsGadgetSettings `js:"currentGadgetSettings"` + CurrentlyDeployingGadgetSettings bool `js:"deployingGadgetSettings"` + CurrentlyDeployingWifiSettings bool `js:"deployingWifiSettings"` + EventProcessor *jsEventProcessor `js:"EventProcessor"` + HidJobList *jsHidJobStateList `js:"hidJobList"` + TriggerActionList *jsTriggerActionSet `js:"triggerActionList"` + IsModalEnabled bool `js:"isModalEnabled"` + IsConnected bool `js:"isConnected"` + FailedConnectionAttempts int `js:"failedConnectionAttempts"` + InterfaceSettings *jsEthernetSettingsArray `js:"InterfaceSettings"` WiFiState *jsWiFiState `js:"wifiState"` CurrentBluetoothControllerInformation *jsBluetoothControllerInformation `js:"CurrentBluetoothControllerInformation"` - CurrentBluetoothAgentSettings *jsBluetoothAgentSettings `js:"CurrentBluetoothAgentSettings"` + CurrentBluetoothAgentSettings *jsBluetoothAgentSettings `js:"CurrentBluetoothAgentSettings"` - StoredWifiSettingsList []string `js:"StoredWifiSettingsList"` - StoredEthernetInterfaceSettingsList []string `js:"StoredEthernetInterfaceSettingsList"` - StoredTriggerActionSetsList []string `js:"StoredTriggerActionSetsList"` - StoredBashScriptsList []string `js:"StoredBashScriptsList"` - StoredHIDScriptsList []string `js:"StoredHIDScriptsList"` - StoredUSBSettingsList []string `js:"StoredUSBSettingsList"` - StoredBluetoothSettingsList []string `js:"StoredBluetoothSettingsList"` + StoredWifiSettingsList []string `js:"StoredWifiSettingsList"` + StoredEthernetInterfaceSettingsList []string `js:"StoredEthernetInterfaceSettingsList"` + StoredTriggerActionSetsList []string `js:"StoredTriggerActionSetsList"` + StoredBashScriptsList []string `js:"StoredBashScriptsList"` + StoredHIDScriptsList []string `js:"StoredHIDScriptsList"` + StoredUSBSettingsList []string `js:"StoredUSBSettingsList"` + StoredBluetoothSettingsList []string `js:"StoredBluetoothSettingsList"` + + ConnectRetryCount int `js:"ConnectRetryCount"` + EventListenerRunning bool `js:"EventListenerRunning"` + EventListenerShouldBeRunning bool `js:"EventListenerShouldBeRunning"` + EventListenerCancelFunc context.CancelFunc // not accessible from JS !!! } func createGlobalStateStruct() GlobalState { @@ -140,7 +154,7 @@ func createGlobalStateStruct() GlobalState { state.CurrentlyDeployingWifiSettings = false state.HidJobList = NewHIDJobStateList() state.TriggerActionList = NewTriggerActionSet() - state.EventReceiver = NewEventReceiver(maxLogEntries, state.HidJobList) + state.EventProcessor = NewEventProcessor(maxLogEntries, state.HidJobList) state.IsConnected = false state.IsModalEnabled = false state.FailedConnectionAttempts = 0 @@ -158,17 +172,163 @@ func createGlobalStateStruct() GlobalState { state.CurrentBluetoothControllerInformation = NewBluetoothControllerInformation() state.CurrentBluetoothAgentSettings = NewBluetoothAgentSettings() - /* - wifiSettings, err := RpcClient.GetWifiState(time.Second * 5) - if err != nil { - panic("Couldn't retrieve WiFi settings") - } - */ //state.WiFiSettings = NewWifiSettings() state.WiFiState = NewWiFiState() + + //Events + state.EventListenerRunning = false + state.EventListenerShouldBeRunning = false + + state.ConnectRetryCount = 0 return state } +func processEvent(evt *pb.Event, store *mvuex.Store, state *GlobalState) { + println("New event", evt) + + typeName := common_web.EventTypeName[evt.Type] + switch evt.Type { + case common_web.EVT_NOTIFY_STATE_CHANGE: + chgType := evt.Values[0].GetTint64() + println("State change notify", common_web.EventTypeStateChangeName[chgType]) + switch common_web.EvtStateChangeType(chgType) { + case common_web.STATE_CHANGE_EVT_TYPE_LED: + println("Notify LED change, nothing to do") + case common_web.STATE_CHANGE_EVT_TYPE_USB: + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_USB_SETTINGS) + store.Dispatch(VUEX_ACTION_UPDATE_RUNNING_HID_JOBS) + case common_web.STATE_CHANGE_EVT_TYPE_NETWORK: + store.Dispatch(VUEX_ACTION_UPDATE_ALL_ETHERNET_INTERFACE_SETTINGS) + case common_web.STATE_CHANGE_EVT_TYPE_HID: + store.Dispatch(VUEX_ACTION_UPDATE_RUNNING_HID_JOBS) // handled by dedicated listener + case common_web.STATE_CHANGE_EVT_TYPE_WIFI: + store.Dispatch(VUEX_ACTION_UPDATE_WIFI_STATE) + case common_web.STATE_CHANGE_EVT_TYPE_TRIGGER_ACTIONS: + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_TRIGGER_ACTIONS_FROM_SERVER) + case common_web.STATE_CHANGE_EVT_TYPE_BLUETOOTH: + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION) + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_AGENT_SETTINGS) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_BASH_SCRIPTS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_BASH_SCRIPTS_LIST) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_HID_SCRIPTS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_HID_SCRIPTS_LIST) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_USB_SETTINGS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_USB_SETTINGS_LIST) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_ETHERNET_INTERFACE_SETTINGS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_ETHERNET_INTERFACE_SETTINGS_LIST) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_WIFI_SETTINGS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_WIFI_SETTINGS_LIST) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_BLUETOOTH_SETTINGS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_BLUETOOTH_SETTINGS_LIST) + case common_web.STATE_CHANGE_EVT_TYPE_STORED_TRIGGER_ACTION_SETS_LIST: + store.Dispatch(VUEX_ACTION_UPDATE_STORED_TRIGGER_ACTION_SETS_LIST) + } + default: + // events which aren't of type "notify state change" are processed by the EventProcessor + state.EventProcessor.HandleEvent(evt) + println("Unhandled event of type ", typeName, evt) + } +} + +func actionUpdateAllStates(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { + println("Updating all states") + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_USB_SETTINGS) + store.Dispatch(VUEX_ACTION_UPDATE_RUNNING_HID_JOBS) + store.Dispatch(VUEX_ACTION_UPDATE_ALL_ETHERNET_INTERFACE_SETTINGS) + store.Dispatch(VUEX_ACTION_UPDATE_WIFI_STATE) + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION) + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_AGENT_SETTINGS) + store.Dispatch(VUEX_ACTION_UPDATE_CURRENT_TRIGGER_ACTIONS_FROM_SERVER) + + store.Dispatch(VUEX_ACTION_UPDATE_STORED_HID_SCRIPTS_LIST) + store.Dispatch(VUEX_ACTION_UPDATE_STORED_USB_SETTINGS_LIST) + store.Dispatch(VUEX_ACTION_UPDATE_STORED_ETHERNET_INTERFACE_SETTINGS_LIST) + store.Dispatch(VUEX_ACTION_UPDATE_STORED_WIFI_SETTINGS_LIST) + store.Dispatch(VUEX_ACTION_UPDATE_STORED_BLUETOOTH_SETTINGS_LIST) + store.Dispatch(VUEX_ACTION_UPDATE_STORED_TRIGGER_ACTION_SETS_LIST) + store.Dispatch(VUEX_ACTION_UPDATE_STORED_BASH_SCRIPTS_LIST) + +} + +func actionStartEventListen(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { + globalState.EventListenerShouldBeRunning = true + go func() { + for state.EventListenerShouldBeRunning { + println("Starting store event listener") + + evStream, cancel, err := RpcClient.StartEventListening(time.Second * 2) + if err != nil { + println("Couldn't start event listener or connect to server ...") + //return + if globalState.EventListenerShouldBeRunning { + // unintended disconnect, sleep, increase retry count, reconnect + state.ConnectRetryCount++ + time.Sleep(time.Second * 2) // We add an addional timeout, to avoid immediate reconnect if `startEventListening` fails without consuming the timeout + continue + } else { + // set retry count to zero + state.ConnectRetryCount = 0 + break + } + } + println(" ... Event listener started") + + defer cancel() + defer evStream.CloseSend() + + if state.EventListenerCancelFunc != nil { + globalState.EventListenerCancelFunc() // cancel old event listeners + } + globalState.EventListenerCancelFunc = cancel + //state.EventListenerRunning = true // should be done with mutation + store.Commit(VUEX_MUTATION_SET_EVENT_LISTENER_RUNNING, true) + store.Dispatch(VUEX_ACTION_UPDATE_ALL_STATES) + + // dummy, retrieve and print events + for { + newEvent, err := evStream.Recv() //Error if Websocket connection fails/aborts, but success is indicated only if stream data is received + if err != nil { + if err == io.EOF { + println("Event listening aborted because end of event stream was reached") + } else { + println("Event listening aborted because of error", err) + } + break + } + + // only print event + processEvent(newEvent, store, state) + + } + + println("Stopped store event listener") + + //state.EventListenerRunning = false // should be done with mutation + store.Commit(VUEX_MUTATION_SET_EVENT_LISTENER_RUNNING, false) + globalState.EventListenerCancelFunc = nil + + } + + }() + + return +} + +func actionStopEventListen(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { + // Note: this action accesses `globalState` instead of `state` + // both values point to the vuex state, but globalState holds fields only accessible from Go + // (like the `EventListenerCancelFunc` which is used here). + // Even if those fields would be exposed to JS by tagging them , they couldn't be externalized/internalized + // correctly by gopherjs, as there's no JavaScript representation of the underlying Go objects. + + println("Stopping event listener") + globalState.EventListenerShouldBeRunning = false + if globalState.EventListenerCancelFunc != nil { + println("Calling event listener cancel func") + globalState.EventListenerCancelFunc() + } +} + func actionUpdateStoredBluetoothSettingsList(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { println("Trying to fetch bluetooth settings list") @@ -214,7 +374,7 @@ func actionDeleteStoredBluetoothSettings(store *mvuex.Store, context *mvuex.Acti QuasarNotifyError("Error deleting stored Bluetooth Settings", err.Error(), QUASAR_NOTIFICATION_POSITION_BOTTOM) } QuasarNotifySuccess("Bluetooth settings deleted", "", QUASAR_NOTIFICATION_POSITION_TOP) - actionUpdateStoredBluetoothSettingsList(store,context,state) + actionUpdateStoredBluetoothSettingsList(store, context, state) }() } @@ -230,7 +390,6 @@ func actionStoreBluetoothSettings(store *mvuex.Store, context *mvuex.ActionConte }() } - func actionDeleteStoredUSBSettings(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState, settingsName *js.Object) { go func() { println("Vuex dispatch delete USB settings: ", settingsName.String()) @@ -240,7 +399,7 @@ func actionDeleteStoredUSBSettings(store *mvuex.Store, context *mvuex.ActionCont QuasarNotifyError("Error deleting stored USB Settings", err.Error(), QUASAR_NOTIFICATION_POSITION_BOTTOM) } QuasarNotifySuccess("USB settings deleted", "", QUASAR_NOTIFICATION_POSITION_TOP) - actionUpdateStoredUSBSettingsList(store,context,state) + actionUpdateStoredUSBSettingsList(store, context, state) }() } @@ -272,7 +431,7 @@ func actionDeleteStoredWifiSettings(store *mvuex.Store, context *mvuex.ActionCon QuasarNotifyError("Error deleting stored WiFi Settings", err.Error(), QUASAR_NOTIFICATION_POSITION_BOTTOM) } QuasarNotifySuccess("Stored WiFi settings deleted", "", QUASAR_NOTIFICATION_POSITION_TOP) - actionUpdateStoredWifiSettingsList(store,context,state) + actionUpdateStoredWifiSettingsList(store, context, state) }() } @@ -363,17 +522,17 @@ func actionDeployCurrentBluetoothAgentSettings(store *mvuex.Store, context *mvue func actionUpdateStoredUSBSettingsList(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { - println("Trying to fetch wsList") + println("Trying to fetch stored USB settings list") //fetch deployed gadget settings - wsList, err := RpcClient.GetStoredUSBSettingsList(defaultTimeout) + usbsList, err := RpcClient.GetStoredUSBSettingsList(defaultTimeout) if err != nil { - println("Couldn't retrieve WifiSettingsList") + println("Couldn't retrieve USB SettingsList") return } //commit to current - println(wsList) - context.Commit(VUEX_MUTATION_SET_STORED_USB_SETTINGS_LIST, wsList) + println(usbsList) + context.Commit(VUEX_MUTATION_SET_STORED_USB_SETTINGS_LIST, usbsList) //context.Commit(VUEX_MUTATION_SET_STORED_WIFI_SETTINGS_LIST, []string{"test1", "test2"}) }() @@ -427,7 +586,7 @@ func actionDeployStoredUSBSettings(store *mvuex.Store, context *mvuex.ActionCont func actionUpdateAllEthernetInterfaceSettings(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) interface{} { return NewPromise(func() (res interface{}, err error) { - + println("Trying to fetch all deployed Ethernet Interface settings") ifSettings, err := RpcClient.GetAllDeployedEthernetInterfaceSettings(time.Second * 5) if err != nil { err = errors.New("Couldn't retrieve interface settings") @@ -560,15 +719,15 @@ func actionUpdateStoredBashScriptsList(store *mvuex.Store, context *mvuex.Action go func() { println("Trying to fetch stored BashScripts list") //fetch deployed gadget settings - wsList, err := RpcClient.GetStoredBashScriptsList(defaultTimeout) + bsList, err := RpcClient.GetStoredBashScriptsList(defaultTimeout) if err != nil { println("Couldn't retrieve stored BashScripts list") return } //commit to current - println(wsList) - context.Commit(VUEX_MUTATION_SET_STORED_BASH_SCRIPTS_LIST, wsList) + println(bsList) + context.Commit(VUEX_MUTATION_SET_STORED_BASH_SCRIPTS_LIST, bsList) }() return @@ -578,15 +737,15 @@ func actionUpdateStoredHIDScriptsList(store *mvuex.Store, context *mvuex.ActionC go func() { println("Trying to fetch stored HIDScripts list") //fetch deployed gadget settings - wsList, err := RpcClient.GetStoredHIDScriptsList(defaultTimeout) + hidsList, err := RpcClient.GetStoredHIDScriptsList(defaultTimeout) if err != nil { println("Couldn't retrieve stored HIDScripts list") return } //commit to current - println(wsList) - context.Commit(VUEX_MUTATION_SET_STORED_HID_SCRIPTS_LIST, wsList) + println(hidsList) + context.Commit(VUEX_MUTATION_SET_STORED_HID_SCRIPTS_LIST, hidsList) }() return @@ -594,6 +753,7 @@ func actionUpdateStoredHIDScriptsList(store *mvuex.Store, context *mvuex.ActionC func actionUpdateGadgetSettingsFromDeployed(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { + println("Trying to fetch deployed USB gadget settings") //fetch deployed gadget settings dGS, err := RpcClient.GetDeployedGadgetSettings(defaultTimeoutShort) if err != nil { @@ -613,7 +773,8 @@ func actionUpdateGadgetSettingsFromDeployed(store *mvuex.Store, context *mvuex.A func actionUpdateWifiState(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { - //fetch deployed gadget settings + println("Trying to fetch deployed WiFi state list") + //fetch WiFi state state, err := RpcClient.GetWifiState(defaultTimeout) if err != nil { println("Couldn't retrieve deployed WiFi settings") @@ -629,7 +790,7 @@ func actionUpdateWifiState(store *mvuex.Store, context *mvuex.ActionContext, sta func actionUpdateStoredWifiSettingsList(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { - println("Trying to fetch wsList") + println("Trying to fetch stored wifi settings list") //fetch deployed gadget settings wsList, err := RpcClient.GetStoredWifiSettingsList(defaultTimeout) if err != nil { @@ -709,6 +870,7 @@ func actionDeployWifiSettings(store *mvuex.Store, context *mvuex.ActionContext, func actionUpdateRunningHidJobs(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { + println("Trying to fetch data for running HIDScript jobs") //fetch deployed gadget settings jobstates, err := RpcClient.GetRunningHidJobStates(defaultTimeout) if err != nil { @@ -731,7 +893,7 @@ func actionUpdateStoredTriggerActionSetsList(store *mvuex.Store, context *mvuex. //fetch deployed gadget settings tasList, err := RpcClient.ListStoredTriggerActionSets(defaultTimeout) if err != nil { - println("Couldn't retrieve WifiSettingsList") + println("Couldn't retrieve TriggerActions list") return } @@ -746,6 +908,7 @@ func actionUpdateStoredTriggerActionSetsList(store *mvuex.Store, context *mvuex. func actionUpdateCurrentTriggerActionsFromServer(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { go func() { + println("Trying to fetch current TriggerActions from server") tastate, err := RpcClient.GetDeployedTriggerActionSet(defaultTimeout) if err != nil { QuasarNotifyError("Error fetching deployed TriggerActions", err.Error(), QUASAR_NOTIFICATION_POSITION_TOP) @@ -920,7 +1083,7 @@ func actionDeployEthernetInterfaceSettings(store *mvuex.Store, context *mvuex.Ac func initMVuex() *mvuex.Store { state := createGlobalStateStruct() - globalState = &state //make accessible through global var + globalState = &state //make accessible through global var (things like mutexes aren't accessible from JS and thus not externalized/internalized) store := mvuex.NewStore( mvuex.State(state), mvuex.Mutation("setModalEnabled", func(store *mvuex.Store, state *GlobalState, enabled bool) { @@ -947,9 +1110,9 @@ func initMVuex() *mvuex.Store { println("New ws list", wsList) hvue.Set(state, "StoredWifiSettingsList", wsList) }), - mvuex.Mutation(VUEX_MUTATION_SET_STORED_BLUETOOTH_SETTINGS_LIST, func(store *mvuex.Store, state *GlobalState, wsList []interface{}) { - println("New Bluetooth list", wsList) - hvue.Set(state, "StoredBluetoothSettingsList", wsList) + mvuex.Mutation(VUEX_MUTATION_SET_STORED_BLUETOOTH_SETTINGS_LIST, func(store *mvuex.Store, state *GlobalState, btsList []interface{}) { + println("New Bluetooth list", btsList) + hvue.Set(state, "StoredBluetoothSettingsList", btsList) }), mvuex.Mutation(VUEX_MUTATION_SET_STORED_USB_SETTINGS_LIST, func(store *mvuex.Store, state *GlobalState, usbList []interface{}) { println("New USB settings list", usbList) @@ -967,10 +1130,9 @@ func initMVuex() *mvuex.Store { mvuex.Mutation(VUEX_MUTATION_SET_STORED_ETHERNET_INTERFACE_SETTINGS_LIST, func(store *mvuex.Store, state *GlobalState, eisList []interface{}) { hvue.Set(state, "StoredEthernetInterfaceSettingsList", eisList) }), - mvuex.Mutation(VUEX_MUTATION_SET_ALL_ETHERNET_INTERFACE_SETTINGS, func(store *mvuex.Store, state *GlobalState, eifSettings *jsEthernetSettingsList) { + mvuex.Mutation(VUEX_MUTATION_SET_ALL_ETHERNET_INTERFACE_SETTINGS, func(store *mvuex.Store, state *GlobalState, eifSettings *jsEthernetSettingsArray) { println("Updating all ethernet interface settings: ", eifSettings) state.InterfaceSettings = eifSettings - }), mvuex.Mutation(VUEX_MUTATION_SET_SINGLE_ETHERNET_INTERFACE_SETTINGS, func(store *mvuex.Store, state *GlobalState, ifSettings *jsEthernetInterfaceSettings) { println("Updating ethernet interface settings for ", ifSettings.Name) @@ -984,16 +1146,11 @@ func initMVuex() *mvuex.Store { println("Updating bluetooth agent settings for ", agentSettings) state.CurrentBluetoothAgentSettings = agentSettings }), - /* - mvuex.Mutation("startLogListening", func (store *mvuex.Store, state *GlobalState) { - state.EventReceiver.StartListening() - return + mvuex.Mutation(VUEX_MUTATION_SET_EVENT_LISTENER_RUNNING, func(store *mvuex.Store, state *GlobalState, running *js.Object) { + state.EventListenerRunning = running.Bool() }), - mvuex.Mutation("stopLogListening", func (store *mvuex.Store, state *GlobalState) { - state.EventReceiver.StopListening() - return - }), - */ + mvuex.Action(VUEX_ACTION_UPDATE_ALL_STATES, actionUpdateAllStates), + mvuex.Action(VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION, actionUpdateCurrentBluetoothControllerInformation), mvuex.Action(VUEX_ACTION_DEPLOY_CURRENT_BLUETOOTH_CONTROLLER_INFORMATION, actionDeployCurrentBluetoothControllerInformation), mvuex.Action(VUEX_ACTION_UPDATE_CURRENT_BLUETOOTH_AGENT_SETTINGS, actionUpdateCurrentBluetoothAgentSettings), @@ -1048,6 +1205,9 @@ func initMVuex() *mvuex.Store { mvuex.Action(VUEX_ACTION_DELETE_STORED_ETHERNET_INTERFACE_SETTINGS, actionDeleteStoredEthernetInterfaceSettings), + mvuex.Action(VUEX_ACTION_START_EVENT_LISTEN, actionStartEventListen), + mvuex.Action(VUEX_ACTION_STOP_EVENT_LISTEN, actionStopEventListen), + mvuex.Getter("triggerActions", func(state *GlobalState) interface{} { return state.TriggerActionList.TriggerActions }), @@ -1063,6 +1223,9 @@ func initMVuex() *mvuex.Store { }) return filtered }), + mvuex.Getter("isConnected", func(state *GlobalState) interface{} { + return state.EventListenerRunning + }), mvuex.Getter("hidjobsFailed", func(state *GlobalState) interface{} { vJobs := state.HidJobList.Jobs //vue object, no real array --> values have to be extracted to filter @@ -1096,8 +1259,6 @@ func initMVuex() *mvuex.Store { } return selectWS }), - - ) // fetch deployed gadget settings @@ -1119,7 +1280,7 @@ func initMVuex() *mvuex.Store { /* // Start Event Listening - state.EventReceiver.StartListening() + state.EventProcessor.StartListening() */ return store diff --git a/web_client/rpcClient.go b/web_client/rpcClient.go index 8ec781c..a4b013d 100644 --- a/web_client/rpcClient.go +++ b/web_client/rpcClient.go @@ -4,13 +4,12 @@ package main import ( "context" + "errors" "github.com/johanbrandhorst/protobuf/grpcweb" "github.com/mame82/P4wnP1_go/common_web" pb "github.com/mame82/P4wnP1_go/proto/gopherjs" - "io" "sync" "time" - "errors" ) type Rpc struct { @@ -334,7 +333,7 @@ func (rpc *Rpc) GetWifiState(timeout time.Duration) (state *jsWiFiState, err err } -func (rpc *Rpc) GetAllDeployedEthernetInterfaceSettings(timeout time.Duration) (settingsList *jsEthernetSettingsList, err error) { +func (rpc *Rpc) GetAllDeployedEthernetInterfaceSettings(timeout time.Duration) (settingsList *jsEthernetSettingsArray, err error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() @@ -344,7 +343,7 @@ func (rpc *Rpc) GetAllDeployedEthernetInterfaceSettings(timeout time.Duration) ( return nil, err } - settingsList = &jsEthernetSettingsList{Object: O()} + settingsList = &jsEthernetSettingsArray{Object: O()} settingsList.fromGo(deployedSettings) return settingsList, nil @@ -533,9 +532,10 @@ func (rpc *Rpc) ConnectionTest(timeout time.Duration) (err error) { return nil } +/* func (rpc *Rpc) StartListening() { - println("Start listening called", globalState.EventReceiver) + println("Start listening called", globalState.EventProcessor) //Note: This method is responsible for handling server streaming of events // It isn't possible to use the stream for connection watching (heartbeat), for the following reasons @@ -579,7 +579,7 @@ func (rpc *Rpc) StartListening() { } //println("Event: ", event) - globalState.EventReceiver.HandleEvent(event) + globalState.EventProcessor.HandleEvent(event) } // we end here on connection error evStream.CloseSend() // fix for half-open websockets, for which the server wouldn't send a TCP RST after crash/restart, as no active client to server communication takes place @@ -606,3 +606,38 @@ func (rpc *Rpc) StartListening() { func (rpc *Rpc) StopListening() { rpc.eventListeningCancel() } +*/ + +func (rpc *Rpc) StartEventListening(timeout time.Duration) (eventStream pb.P4WNP1_EventListenClient, cancel context.CancelFunc, err error) { + + println("Start listening called", globalState.EventProcessor) + + // Notes: + // - rpc.Client.EventListen doesn't return an error if the gRPC server is not running or not reachable (we can't + // cancel the context based on a timeout, as eventListen is meant to read an endless stream) + // - in contrast, a call to a RPC method which isn't meant for server streaming, could fail after timeout + // - to determine if the server is connectible at all, a connection test RPC method is called upfront + // - additionally it should be noted, that even if the server streaming gRPC call to `EventListen` couldn't + // detect that the server isn't connectible, a call to the `Recv()` method of the resulting stream object errors + // in case an already existing server connection is lost (the server resets the underlying socket, but has to be running to do so) + + + //Check if server is reachable (with timeout) + for RpcClient.ConnectionTest(timeout) != nil { + return eventStream,cancel,errors.New("Server not reachable") + } + + + println("... success") + globalState.IsConnected = true + globalState.FailedConnectionAttempts = 0 + + ctx, cancel := context.WithCancel(context.Background()) + rpc.eventListeningCancel = cancel + + // try RPC call + evStream, err := rpc.Client.EventListen(ctx, &pb.EventRequest{ListenType: common_web.EVT_ANY}) //No error if Websocket connection fails + + return evStream,cancel,err +} +