diff --git a/service/Event.go b/service/Event.go index 1fdc3b3..ff1f378 100644 --- a/service/Event.go +++ b/service/Event.go @@ -7,13 +7,16 @@ import ( "context" "sync" "time" + "log" + "strconv" ) +/* var ( EvMgr *EventManager evmMutex = &sync.Mutex{} ) - +*/ func pDEBUG(message string) { fmt.Println("EVENT DEBUG: " + message) } @@ -30,6 +33,31 @@ type EventManager struct { receiverRegListMutex *sync.Mutex } +func NewEventManager(queueSize int) *EventManager { + EvMgr := &EventManager{ + eventQueue: make(chan *pb.Event, queueSize), + receiverDelListMutex: &sync.Mutex{}, + receiverRegListMutex: &sync.Mutex{}, + receiverRegisterList: make(map[*EventReceiver]bool), + registeredReceivers: make(map[*EventReceiver]bool), + receiverDeleteList: make(map[*EventReceiver]bool), + } + EvMgr.ctx, EvMgr.cancel = context.WithCancel(context.Background()) + return EvMgr +} + +func (evm *EventManager) Start() { + log.Println("Event Manager: Starting event dispatcher") + go evm.dispatch() +} + +func (evm *EventManager) Stop() { + log.Println("Event Manager: Stopping ...") + evm.cancel() + close(evm.eventQueue) +} + +/* func StartEventManager(queueSize int) *EventManager { if EvMgr != nil { StopEventManager() } @@ -61,10 +89,11 @@ func StopEventManager() { close(EvMgr.eventQueue) } +*/ func (em *EventManager) Emit(event *pb.Event) { em.eventQueue <-event -// fmt.Println("Event enqueued") + //fmt.Println("Event enqueued") } func (em *EventManager) Write(p []byte) (n int, err error) { @@ -75,6 +104,8 @@ func (em *EventManager) Write(p []byte) (n int, err error) { func (em *EventManager) RegisterReceiver(filterEventType int64) *EventReceiver { + fmt.Println("!!!Event listener registered for " + strconv.Itoa(int(filterEventType))) + ctx,cancel := context.WithCancel(context.Background()) er := &EventReceiver{ EventQueue: make(chan *pb.Event, 10), //allow buffering 10 events per receiver diff --git a/service/defaults.go b/service/defaults.go index 2b716d7..6289058 100644 --- a/service/defaults.go +++ b/service/defaults.go @@ -4,6 +4,15 @@ import ( pb "../proto" ) +const ( + DEFAULT_CDC_ECM_HOST_ADDR = "42:63:66:12:34:56" + DEFAULT_CDC_ECM_DEV_ADDR = "42:63:66:56:34:12" + DEFAULT_RNDIS_HOST_ADDR = "42:63:65:12:34:56" + DEFAULT_RNDIS_DEV_ADDR = "42:63:65:56:34:12" + USB_ETHERNET_BRIDGE_MAC = "24:22:26:12:14:16" + USB_ETHERNET_BRIDGE_NAME = "usbeth" +) + func GetDefaultNetworkSettingsUSB() (*pb.EthernetInterfaceSettings) { //configure 172.24.0.1/255.255.255.252 for usbeth ifSettings := &pb.EthernetInterfaceSettings { @@ -70,8 +79,8 @@ func GetDefaultDHCPConfigWiFi() (settings *pb.DHCPServerSettings) { return } -func GetDefaultLEDSettings() (res pb.LEDSettings) { - return pb.LEDSettings{ +func GetDefaultLEDSettings() (res *pb.LEDSettings) { + return &pb.LEDSettings{ BlinkCount: 254, } } @@ -93,12 +102,12 @@ func GetDefaultGadgetSettings() (res pb.GadgetSettings) { Use_UMS: false, Use_SERIAL: false, RndisSettings: &pb.GadgetSettingsEthernet{ - HostAddr: "42:63:65:12:34:56", - DevAddr: "42:63:65:56:34:12", + HostAddr: DEFAULT_RNDIS_HOST_ADDR, + DevAddr: DEFAULT_RNDIS_DEV_ADDR, }, CdcEcmSettings: &pb.GadgetSettingsEthernet{ - HostAddr: "42:63:66:12:34:56", - DevAddr: "42:63:66:56:34:12", + HostAddr: DEFAULT_CDC_ECM_HOST_ADDR, + DevAddr: DEFAULT_CDC_ECM_DEV_ADDR, }, UmsSettings: &pb.GadgetSettingsUMS{ File:"", //we don't supply an image file, which is no problem as it could be applied later on (removable media) diff --git a/service/led.go b/service/led.go index b6a12ed..d6881c4 100644 --- a/service/led.go +++ b/service/led.go @@ -21,11 +21,19 @@ const ( LED_DELAY_PAUSE = 500 * time.Millisecond ) + +type LedState struct { + blink_count *uint32 +} +/* var ( blink_count uint32 = 0 ) +*/ +func NewLed(led_on bool) (ledState *LedState, err error) { + blinkCount := uint32(0) + ledState = &LedState{ &blinkCount } -func InitLed(led_on bool) (error) { //set trigger of LED to manual log.Println("Setting LED to manual trigger ...") ioutil.WriteFile(LED_TRIGGER_PATH, []byte(LED_TRIGGER_MANUAL), os.ModePerm) @@ -36,22 +44,22 @@ func InitLed(led_on bool) (error) { log.Println("Setting LED to OFF ...") ioutil.WriteFile(LED_BRIGHTNESS_PATH, []byte(LED_OFF), os.ModePerm) } - atomic.StoreUint32(&blink_count, 0) - - go led_loop() - - return nil + + go ledState.led_loop() // watcher loop + + ledState.SetLed(GetDefaultLEDSettings()) //set default setting + return ledState,nil } -func led_loop() { +func (leds *LedState) led_loop() { for { - for i := uint32(0); i < atomic.LoadUint32(&blink_count); i++ { + for i := uint32(0); i < atomic.LoadUint32(leds.blink_count); i++ { ioutil.WriteFile(LED_BRIGHTNESS_PATH, []byte(LED_ON), os.ModePerm) time.Sleep(LED_DELAY_ON) //Don't turn off led if blink_count >= 255 (solid) - if 255 > atomic.LoadUint32(&blink_count) { + if 255 > atomic.LoadUint32(leds.blink_count) { ioutil.WriteFile(LED_BRIGHTNESS_PATH, []byte(LED_OFF), os.ModePerm) time.Sleep(LED_DELAY_OFF) } @@ -60,18 +68,15 @@ func led_loop() { } } -func SetLed(s pb.LEDSettings) (error) { +func (leds *LedState) SetLed(s *pb.LEDSettings) (error) { //log.Printf("setLED called with %+v", s) - atomic.StoreUint32(&blink_count, s.BlinkCount) + atomic.StoreUint32(leds.blink_count, s.BlinkCount) return nil } -func GetLed() (res *pb.LEDSettings, err error) { - return &pb.LEDSettings{BlinkCount: atomic.LoadUint32(&blink_count)}, nil +func (leds *LedState) GetLed() (res *pb.LEDSettings, err error) { + return &pb.LEDSettings{BlinkCount: atomic.LoadUint32(leds.blink_count)}, nil } -func InitDefaultLEDSettings() { - SetLed(GetDefaultLEDSettings()) -} \ No newline at end of file diff --git a/service/network.go b/service/network.go index e4781fa..49795ab 100644 --- a/service/network.go +++ b/service/network.go @@ -13,18 +13,10 @@ import ( "errors" ) -var ( - StoredNetworkSetting map[string]*pb.EthernetInterfaceSettings = make(map[string]*pb.EthernetInterfaceSettings) -) -func init() { - //preinitialize Default settings for "wlan0" and USB_ETHERNET_BRIDGE_NAME ("usbeth") - StoredNetworkSetting[USB_ETHERNET_BRIDGE_NAME] = GetDefaultNetworkSettingsUSB() - StoredNetworkSetting["wlan0"] = GetDefaultNetworkSettingsWiFi() -} func ReInitNetworkInterface(ifName string) (err error) { - if settings, existing := StoredNetworkSetting[ifName]; existing { + if settings, existing := ServiceState.StoredNetworkSetting[ifName]; existing { log.Printf("Redeploying stored Network settings for interface '%s' ...\n", ifName) return ConfigureInterface(settings) } else { @@ -208,7 +200,7 @@ func ConfigureInterface(settings *pb.EthernetInterfaceSettings) (err error) { } //Store latest settings - StoredNetworkSetting[settings.Name] = settings + ServiceState.StoredNetworkSetting[settings.Name] = settings return nil } \ No newline at end of file diff --git a/service/rpc_server.go b/service/rpc_server.go index 70221ba..542152c 100644 --- a/service/rpc_server.go +++ b/service/rpc_server.go @@ -30,7 +30,8 @@ var ( type server struct {} func (s *server) EventListen(eReq *pb.EventRequest, eStream pb.P4WNP1_EventListenServer) (err error) { - rcv := EvMgr.RegisterReceiver(eReq.ListenType) + //ToDo: check dependency from state (EvMgr initialized) + rcv := ServiceState.EvMgr.RegisterReceiver(eReq.ListenType) for { @@ -96,9 +97,9 @@ func (s *server) FSCreateTempDirOrFile(ctx context.Context, req *pb.TempDirOrFil } func (s *server) HIDGetRunningScriptJobs(ctx context.Context, rEmpty *pb.Empty) (jobs *pb.HIDScriptJobList, err error) { - if HidCtl == nil { return nil, rpcErrNoHid} + if ServiceState.HidCtl == nil { return nil, rpcErrNoHid} - retJobs,err := HidCtl.GetAllBackgroundJobs() + retJobs,err := ServiceState.HidCtl.GetAllBackgroundJobs() if err != nil { return nil, err } jobs = &pb.HIDScriptJobList{} jobs.Ids = retJobs @@ -107,10 +108,10 @@ 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) { empty = &pb.Empty{} - if HidCtl == nil { return empty, rpcErrNoHid} + if ServiceState.HidCtl == nil { return empty, rpcErrNoHid} // Try to find script - HidCtl.CancelAllBackgroundJobs() + ServiceState.HidCtl.CancelAllBackgroundJobs() return } @@ -118,10 +119,10 @@ func (s *server) HIDCancelAllScriptJobs(ctx context.Context, rEmpty *pb.Empty) ( func (s *server) HIDCancelScriptJob(ctx context.Context, sJob *pb.HIDScriptJob) (empty *pb.Empty, err error) { empty = &pb.Empty{} - if HidCtl == nil { return empty, rpcErrNoHid} + if ServiceState.HidCtl == nil { return empty, rpcErrNoHid} // Try to find script - job,err := HidCtl.GetBackgroundJobByID(int(sJob.Id)) + job,err := ServiceState.HidCtl.GetBackgroundJobByID(int(sJob.Id)) if err != nil { return empty, err } job.Cancel() @@ -129,7 +130,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) { - if HidCtl == nil { return nil, rpcErrNoHid} + if ServiceState.HidCtl == nil { return nil, rpcErrNoHid} @@ -142,7 +143,7 @@ func (s *server) HIDRunScript(ctx context.Context, scriptReq *pb.HIDScriptReques if scriptReq.TimeoutSeconds > 0 { jobCtx,_ = context.WithTimeout(jobCtx, time.Second * time.Duration(scriptReq.TimeoutSeconds))} - scriptVal,err := HidCtl.RunScript(jobCtx, string(scriptFile)) + scriptVal,err := ServiceState.HidCtl.RunScript(jobCtx, string(scriptFile)) if err != nil { return nil,err } val,_ := scriptVal.Export() //Convert to Go representation, error is always nil jsonVal,err := json.Marshal(val) @@ -159,7 +160,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) { - if HidCtl == nil { return nil, rpcErrNoHid} + if ServiceState.HidCtl == nil { return nil, rpcErrNoHid} if scriptFile, err := ioutil.ReadFile(scriptReq.ScriptPath); err != nil { return nil, errors.New(fmt.Sprintf("Couldn't load HIDScript '%s': %v\n", scriptReq.ScriptPath, err)) @@ -168,7 +169,7 @@ func (s *server) HIDRunScriptJob(ctx context.Context, scriptReq *pb.HIDScriptReq jobCtx := context.Background() // ToDo: we don't retrieve the cancelFunc which should be called to free resources. Solution: use withCancel context and call cancel by go routine on timeout if scriptReq.TimeoutSeconds > 0 { jobCtx,_ = context.WithTimeout(jobCtx, time.Second * time.Duration(scriptReq.TimeoutSeconds))} - job,err := HidCtl.StartScriptAsBackgroundJob(jobCtx, string(scriptFile)) + job,err := ServiceState.HidCtl.StartScriptAsBackgroundJob(jobCtx, string(scriptFile)) if err != nil { return nil,err } rJob = &pb.HIDScriptJob{ @@ -180,15 +181,15 @@ func (s *server) HIDRunScriptJob(ctx context.Context, scriptReq *pb.HIDScriptReq } func (s *server) HIDGetScriptJobResult(ctx context.Context, sJob *pb.HIDScriptJob) (scriptRes *pb.HIDScriptResult, err error) { - if HidCtl == nil { return nil, rpcErrNoHid} + if ServiceState.HidCtl == nil { return nil, rpcErrNoHid} // Try to find script - job,err := HidCtl.GetBackgroundJobByID(int(sJob.Id)) + job,err := ServiceState.HidCtl.GetBackgroundJobByID(int(sJob.Id)) if err != nil { return scriptRes, err } //ToDo: check impact/behavior, because ctx is provided by gRPC server - scriptVal,err := HidCtl.WaitBackgroundJobResult(ctx, job) + scriptVal,err := ServiceState.HidCtl.WaitBackgroundJobResult(ctx, job) if err != nil { return nil,err } val,_ := scriptVal.Export() //Convert to Go representation, error is always nil jsonVal,err := json.Marshal(val) @@ -250,11 +251,11 @@ func (s *server) DeployGadgetSetting(context.Context, *pb.Empty) (gs *pb.GadgetS //ToDo: Former gadgets are destroyed without testing if there're changes, this should be aborted if GadgetSettingsState == GetDeployedGadgetSettings() DestroyGadget(USB_GADGET_NAME) - errg := DeployGadgetSettings(GadgetSettingsState) + errg := ServiceState.UsbGM.DeployGadgetSettings(ServiceState.UsbGM.UndeployedGadgetSettings) err = nil if errg != nil { err = errors.New(fmt.Sprintf("Deploying new gadget settings failed, reverted to old ones: %v", errg)) - DeployGadgetSettings(*gs_backup) //We don't catch the error, as the old settings should have been working + ServiceState.UsbGM.DeployGadgetSettings(gs_backup) //We don't catch the error, as the old settings should have been working } gs, _ = ParseGadgetState(USB_GADGET_NAME) //Return settings from deployed gadget @@ -262,29 +263,29 @@ func (s *server) DeployGadgetSetting(context.Context, *pb.Empty) (gs *pb.GadgetS } func (s *server) GetGadgetSettings(context.Context, *pb.Empty) (*pb.GadgetSettings, error) { - return &GadgetSettingsState, nil + return ServiceState.UsbGM.UndeployedGadgetSettings, nil } func (s *server) SetGadgetSettings(ctx context.Context, gs *pb.GadgetSettings) (res *pb.GadgetSettings, err error) { if err = ValidateGadgetSetting(*gs); err != nil { //We return the validation error and the current (unchanged) GadgetSettingsState - res = &GadgetSettingsState + res = ServiceState.UsbGM.UndeployedGadgetSettings return } - GadgetSettingsState = *gs - res = &GadgetSettingsState + ServiceState.UsbGM.UndeployedGadgetSettings = gs + res = ServiceState.UsbGM.UndeployedGadgetSettings return } func (s *server) GetLEDSettings(context.Context, *pb.Empty) (res *pb.LEDSettings, err error) { - res, err = GetLed() + res, err = ServiceState.Led.GetLed() log.Printf("GetLEDSettings, result: %+v", res) return } func (s *server) SetLEDSettings(ctx context.Context, ls *pb.LEDSettings) (*pb.Empty, error) { log.Printf("SetLEDSettings %+v", ls) - SetLed(*ls) + ServiceState.Led.SetLed(ls) return &pb.Empty{}, nil } diff --git a/service/state.go b/service/state.go new file mode 100644 index 0000000..0f26df7 --- /dev/null +++ b/service/state.go @@ -0,0 +1,47 @@ +package service + +import ( + "../hid" + pb "../proto" +) + +var ServiceState *GlobalServiceState + +type GlobalServiceState struct { + EvMgr *EventManager + HidCtl *hid.HIDController + UsbGM *UsbGadgetManager + Led *LedState + HidDevPath map[string]string //stores device path for HID devices + StoredNetworkSetting map[string]*pb.EthernetInterfaceSettings +} + +func InitGlobalServiceState() (err error) { + state := &GlobalServiceState{} + ServiceState = state // store state in global variable + + state.StoredNetworkSetting = make(map[string]*pb.EthernetInterfaceSettings) + //preinitialize Default settings for "wlan0" and USB_ETHERNET_BRIDGE_NAME ("usbeth") + state.StoredNetworkSetting[USB_ETHERNET_BRIDGE_NAME] = GetDefaultNetworkSettingsUSB() + state.StoredNetworkSetting["wlan0"] = GetDefaultNetworkSettingsWiFi() + + + state.HidDevPath = make(map[string]string) //should be initialized BEFORE UsbGadgetManager uses it + state.EvMgr = NewEventManager(20) + state.UsbGM,err = NewUSBGadgetManager() + if err != nil { return } + ledState, err := NewLed(false) + if err != nil { return } + state.Led = ledState + + return nil +} + + +func (state *GlobalServiceState) StartService() { + state.EvMgr.Start() +} + +func (state *GlobalServiceState) StopService() { + state.EvMgr.Stop() +} \ No newline at end of file diff --git a/service/usb.go b/service/usb.go index 6cefee3..caf2a8c 100644 --- a/service/usb.go +++ b/service/usb.go @@ -31,9 +31,6 @@ const ( USB_GADGET_DIR_BASE = "/sys/kernel/config/usb_gadget" USB_GADGET_DIR = USB_GADGET_DIR_BASE + "/" + USB_GADGET_NAME - USB_ETHERNET_BRIDGE_NAME = "usbeth" - USB_ETHERNET_BRIDGE_MAC = "24:22:26:12:14:16" - USB_bcdDevice = "0x0100" //Version 1.00 USB_bcdUSB = "0x0200" //mode: USB 2.0 @@ -77,12 +74,24 @@ const ( ) -var ( - GadgetSettingsState pb.GadgetSettings = pb.GadgetSettings{} - rp_usbHidDevName = regexp.MustCompile("(?m)DEVNAME=(.*)\n") - HidDevPath = make(map[string]string) //stores device path for HID devices - HidCtl *hid.HIDController -) +var rp_usbHidDevName = regexp.MustCompile("(?m)DEVNAME=(.*)\n") + +type UsbGadgetManager struct { + // ToDo: variable, indicating if HIDScript is usable + HidCtl *hid.HIDController // Points to an HID controller instance only if keyboard and/or mouse are enabled, nil otherwise + UndeployedGadgetSettings *pb.GadgetSettings +} + +func NewUSBGadgetManager() (newUGM *UsbGadgetManager, err error) { + newUGM = &UsbGadgetManager{} + defGS := GetDefaultGadgetSettings() + newUGM.UndeployedGadgetSettings = &defGS //preload state with default settings + err = newUGM.DeployGadgetSettings(newUGM.UndeployedGadgetSettings) + if err != nil { return nil, err } + return +} + + func ValidateGadgetSetting(gs pb.GadgetSettings) error { /* ToDo: validations @@ -91,7 +100,7 @@ func ValidateGadgetSetting(gs pb.GadgetSettings) error { - check EP consumption to be not more than 7 (ECM 2 EP, RNDIS 2 EP, HID Mouse 1 EP, HID Keyboard 1 EP, HID Raw 1 EP, Serial 2 EP ??, UMS 2 EP ?) - check serial, product, Manufacturer to not be empty - check Pid, Vid with regex (Note: we don't check if Vid+Pid have been used for another composite function setup, yet) - - If the gadget is enabled, at least one function has to be enabled + - Done: If the gadget is enabled, at least one function has to be enabled */ log.Println("Validating gadget settings ...") @@ -126,6 +135,18 @@ func ValidateGadgetSetting(gs pb.GadgetSettings) error { log.Print(strConsumption) if sum_ep > USB_EP_USAGE_MAX { return errors.New(strConsumption)} + //check if composite gadget is enabled without functions + if gs.Enabled && + !gs.Use_CDC_ECM && + !gs.Use_RNDIS && + !gs.Use_HID_KEYBOARD && + !gs.Use_HID_MOUSE && + !gs.Use_HID_RAW && + !gs.Use_UMS && + !gs.Use_SERIAL { + return errors.New("If the composite gadget isn't disabled, as least one function has to be enabled") + } + return nil } @@ -175,12 +196,6 @@ func pollForUSBEthernet(timeout time.Duration) error { return errors.New(fmt.Sprintf("Timeout %v reached before usb0 or usb1 became ready")) } -func InitDefaultGadgetSettings() (err error) { - err = DeployGadgetSettings(GetDefaultGadgetSettings()) //Deploy default settings to ConfigFS - if err != nil { return } - GadgetSettingsState = GetDefaultGadgetSettings() //populate settings state with same values - return nil -} @@ -291,6 +306,12 @@ func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error) } else { result.RndisSettings.DevAddr = strings.TrimSuffix(string(res), "\000\n") } + } else { + // we provide GadgetSettingsEthernet with default MAC adresses anyway, to have defaults in case RNDIS should be enabled + result.RndisSettings = &pb.GadgetSettingsEthernet{ + HostAddr: DEFAULT_RNDIS_HOST_ADDR, + DevAddr: DEFAULT_RNDIS_DEV_ADDR, + } } //USB CDC ECM @@ -313,6 +334,12 @@ func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error) result.CdcEcmSettings.DevAddr = strings.TrimSuffix(string(res), "\000\n") } + } else { + // we provide GadgetSettingsEthernet with default MAC adresses anyway, to have defaults in case CDC ECM should be enabled + result.CdcEcmSettings = &pb.GadgetSettingsEthernet{ + HostAddr: DEFAULT_CDC_ECM_HOST_ADDR, + DevAddr: DEFAULT_CDC_ECM_DEV_ADDR, + } } //USB serial @@ -388,7 +415,7 @@ func MountUMSFile(filename string) error { return nil } -func DeployGadgetSettings(settings pb.GadgetSettings) error { +func (gm *UsbGadgetManager) DeployGadgetSettings(settings *pb.GadgetSettings) error { var usesUSBEthernet bool //gadget_root := "./test" @@ -576,11 +603,10 @@ func DeployGadgetSettings(settings pb.GadgetSettings) error { } } - //clear device path for HID devices - HidDevPath[USB_FUNCTION_HID_KEYBOARD_name] = "" - HidDevPath[USB_FUNCTION_HID_MOUSE_name] = "" - HidDevPath[USB_FUNCTION_HID_RAW_name] = "" + ServiceState.HidDevPath[USB_FUNCTION_HID_KEYBOARD_name] = "" + ServiceState.HidDevPath[USB_FUNCTION_HID_MOUSE_name] = "" + ServiceState.HidDevPath[USB_FUNCTION_HID_RAW_name] = "" //get UDC driver name and bind to gadget if settings.Enabled { @@ -594,25 +620,25 @@ func DeployGadgetSettings(settings pb.GadgetSettings) error { } //update device path' - if devPath,errF := enumDevicePath(USB_FUNCTION_HID_KEYBOARD_name); errF == nil { HidDevPath[USB_FUNCTION_HID_KEYBOARD_name] = devPath } - if devPath,errF := enumDevicePath(USB_FUNCTION_HID_MOUSE_name); errF == nil { HidDevPath[USB_FUNCTION_HID_MOUSE_name] = devPath } - if devPath,errF := enumDevicePath(USB_FUNCTION_HID_RAW_name); errF == nil { HidDevPath[USB_FUNCTION_HID_RAW_name] = devPath } + if devPath,errF := enumDevicePath(USB_FUNCTION_HID_KEYBOARD_name); errF == nil { ServiceState.HidDevPath[USB_FUNCTION_HID_KEYBOARD_name] = devPath } + if devPath,errF := enumDevicePath(USB_FUNCTION_HID_MOUSE_name); errF == nil { ServiceState.HidDevPath[USB_FUNCTION_HID_MOUSE_name] = devPath } + if devPath,errF := enumDevicePath(USB_FUNCTION_HID_RAW_name); errF == nil { ServiceState.HidDevPath[USB_FUNCTION_HID_RAW_name] = devPath } //if Keyboard or Mouse are deployed, grab a HIDController Instance else set it to nil (the old HIDController object won't be destroyed) if settings.Use_HID_KEYBOARD || settings.Use_HID_MOUSE { - devPathKeyboard := HidDevPath[USB_FUNCTION_HID_KEYBOARD_name] - devPathMouse := HidDevPath[USB_FUNCTION_HID_MOUSE_name] + devPathKeyboard := ServiceState.HidDevPath[USB_FUNCTION_HID_KEYBOARD_name] + devPathMouse := ServiceState.HidDevPath[USB_FUNCTION_HID_MOUSE_name] var errH error - HidCtl, errH = hid.NewHIDController(context.Background(), devPathKeyboard, USB_KEYBOARD_LANGUAGE_MAP_PATH, devPathMouse) + gm.HidCtl, errH = hid.NewHIDController(context.Background(), devPathKeyboard, USB_KEYBOARD_LANGUAGE_MAP_PATH, devPathMouse) if errH != nil { log.Printf("ERROR: Couldn't bring up an instance of HIDController for keyboard: '%s', mouse: '%s' and mapping path '%s'\nReason: %v\n", devPathKeyboard, devPathMouse, USB_KEYBOARD_LANGUAGE_MAP_PATH, errH) } else { log.Printf("HIDController for keyboard: '%s', mouse: '%s' and mapping path '%s' initialized\n", devPathKeyboard, devPathMouse, USB_KEYBOARD_LANGUAGE_MAP_PATH) } } else { - if HidCtl != nil { HidCtl.Abort() } - HidCtl = nil + if gm.HidCtl != nil { gm.HidCtl.Abort() } + gm.HidCtl = nil log.Printf("HIDController for keyboard / mouse disabled\n") } } @@ -667,7 +693,7 @@ func enumDevicePath(funcName string) (devPath string, err error){ return } -func DestroyAllGadgets() error { +func (gm *UsbGadgetManager) DestroyAllGadgets() error { //gadget_root := "./test" gadget_root := USB_GADGET_DIR_BASE @@ -690,8 +716,8 @@ func DestroyAllGadgets() error { } } - if HidCtl != nil { HidCtl.Abort() } - HidCtl = nil + if gm.HidCtl != nil { gm.HidCtl.Abort() } + gm.HidCtl = nil log.Printf("HIDController for keyboard / mouse disabled\n") return nil diff --git a/web_client/hvueCompModal.go b/web_client/hvueCompModal.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/web_client/hvueCompModal.go @@ -0,0 +1 @@ +package main diff --git a/web_client/globalState.go b/web_client/mvuexGlobalState.go similarity index 53% rename from web_client/globalState.go rename to web_client/mvuexGlobalState.go index efa8a73..7a31627 100644 --- a/web_client/globalState.go +++ b/web_client/mvuexGlobalState.go @@ -1,15 +1,19 @@ package main import ( - "./mvuex" "github.com/gopherjs/gopherjs/js" "time" - "context" - pb "../proto/gopherjs" + "./mvuex" ) const ( maxLogEntries = 500 + + VUEX_ACTION_DEPLOY_CURRENT_GADGET_SETTINGS = "deployCurrentGadgetSettings" + VUEX_ACTION_UPDATE_GADGET_SETTINGS_FROM_DEPLOYED = "updateCurrentGadgetSettingsFromDeployed" + VUEX_MUTATION_SET_CURRENT_GADGET_SETTINGS_TO = "setCurrentGadgetSettings" + VUEX_MUTATION_SET_CURRENT_HID_SCRIPT_SOURCE_TO = "setCurrentHIDScriptSource" + initHIDScript = `layout('us'); // US keyboard layout typingSpeed(100,150) // Wait 100ms between key strokes + an additional random value between 0ms and 150ms (natural) @@ -42,15 +46,19 @@ type GlobalState struct { CurrentHIDScriptSource string `js:"currentHIDScriptSource"` CurrentGadgetSettings *jsGadgetSettings `js:"currentGadgetSettings"` EventLog *jsLoggerData `js:"eventLog"` + IsModalEnabled bool `js:"isModalEnabled"` Counter int `js:"count"` Text string `js:"text"` } -func UpdateGadgetSettingsFromDeployed(jsGS *jsGadgetSettings) { +/* +func (state *GlobalState) UpdateGadgetSettingsFromDeployed(jsGS *jsGadgetSettings) { //gs := vue.GetVM(c).Get("gadgetSettings") println("UpdateGadgetSettingsFromDeployed called") + + ctx,cancel := context.WithTimeout(context.Background(), time.Second*3) defer cancel() @@ -61,20 +69,74 @@ func UpdateGadgetSettingsFromDeployed(jsGS *jsGadgetSettings) { jsGS.fromGS(deployedGs) return } +*/ func createGlobalStateStruct() GlobalState { state := GlobalState{Object:O()} state.Title = "P4wnP1 by MaMe82" state.CurrentHIDScriptSource = initHIDScript state.CurrentGadgetSettings = NewUSBGadgetSettings() - UpdateGadgetSettingsFromDeployed(state.CurrentGadgetSettings) + //UpdateGadgetSettingsFromDeployed(state.CurrentGadgetSettings) state.EventLog = NewLogger(maxLogEntries) + state.IsModalEnabled = true state.Counter = 1337 state.Text = "Hi there says MaMe82" return state } +func actionUpdateGadgetSettingsFromDeployed(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { + go func() { + //fetch deployed gadget settings + dGS,err := RpcGetDeployedGadgetSettings(time.Second * 3) + if err != nil { + println("Couldn't retrieve deployed gadget settings") + return + } + //convert to JS version + jsGS := &jsGadgetSettings{Object:O()} + jsGS.fromGS(dGS) + + //commit to current + context.Commit("setCurrentGadgetSettings", jsGS) + }() + + return +} + +func actionDeployCurrentGadgetSettings(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState) { + go func() { + // ToDo: Indicate deployment process via global state + + //get current GadgetSettings + curGS := state.CurrentGadgetSettings.toGS() + + //try to set them via gRPC (the server holds an internal state, setting != deploying) + err := RpcSetRemoteGadgetSettings(curGS, time.Second) + if err != nil { + //ToDo: use global store to return something, or allow actions to return promises (latter is too much JavaScript) + Alert(err) + return + } + + //try to deploy the, now set, remote GadgetSettings via gRPC + _,err = RpcDeployRemoteGadgetSettings(time.Second*10) + if err != nil { + //ToDo: use global store to return something, or allow actions to return promises (latter is too much JavaScript) + Alert(err) + return + } + + + + //ToDo: If we're here, we succeeded and should indicate this via global state + Alert("GadgetSettings deployed successfully") + + }() + + return +} + func initMVuex() { state := createGlobalStateStruct() store := mvuex.NewStore( @@ -90,6 +152,10 @@ func initMVuex() { }() }), + mvuex.Mutation("setModalEnabled", func (store *mvuex.Store, state *GlobalState, enabled bool) { + state.IsModalEnabled = enabled + return + }), mvuex.Mutation("increment", func (store *mvuex.Store, state *GlobalState, add int) { state.Counter += add return @@ -102,18 +168,12 @@ func initMVuex() { state.Text = newText return }), - mvuex.Mutation("setCurrentHIDScriptSource", func (store *mvuex.Store, state *GlobalState, newText string) { + mvuex.Mutation(VUEX_MUTATION_SET_CURRENT_HID_SCRIPT_SOURCE_TO, func (store *mvuex.Store, state *GlobalState, newText string) { state.CurrentHIDScriptSource = newText return }), - mvuex.Mutation("setCurrentGadgetSettings", func (store *mvuex.Store, state *GlobalState, newSettings *jsGadgetSettings) { - state.CurrentGadgetSettings = newSettings - return - }), - mvuex.Mutation("setCurrentGadgetSettingsFromDeployed", func (store *mvuex.Store, state *GlobalState) { - //ToDo: check if this is valid for synchronous run, has to be dispatched to action otherwise - println("Store: commit setCurrentGadgetSettingsFromDeployed") - go UpdateGadgetSettingsFromDeployed(state.CurrentGadgetSettings) + mvuex.Mutation(VUEX_MUTATION_SET_CURRENT_GADGET_SETTINGS_TO, func (store *mvuex.Store, state *GlobalState, settings *jsGadgetSettings) { + state.CurrentGadgetSettings = settings return }), mvuex.Mutation("startLogListening", func (store *mvuex.Store, state *GlobalState) { @@ -124,8 +184,12 @@ func initMVuex() { state.EventLog.StopListening() return }), + mvuex.Action(VUEX_ACTION_UPDATE_GADGET_SETTINGS_FROM_DEPLOYED, actionUpdateGadgetSettingsFromDeployed), + mvuex.Action(VUEX_ACTION_DEPLOY_CURRENT_GADGET_SETTINGS, actionDeployCurrentGadgetSettings), ) + // fetch deployed gadget settings + store.Dispatch("updateCurrentGadgetSettingsFromDeployed") // propagate Vuex store to global scope to allow injecting it to Vue by setting the "store" option js.Global.Set("store", store)