mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 13:21:50 +01:00
Added interface for callback events to HID
This commit is contained in:
parent
286b8b9b46
commit
8f553db5c3
@ -57,13 +57,29 @@ func (job *AsyncOttoJob) ResultJsonString() (string, error) {
|
||||
return string(json),nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
type AsyncOttoVM struct {
|
||||
vm *otto.Otto
|
||||
isWorking bool
|
||||
sync.Mutex
|
||||
Id int
|
||||
eventHandler EventHandler
|
||||
}
|
||||
|
||||
func (avm *AsyncOttoVM) HandleEvent(event Event) {
|
||||
fmt.Printf("!!! AsyncOtto Event: %+v\n", event)
|
||||
}
|
||||
|
||||
func (avm *AsyncOttoVM) SetEventHandler(handler EventHandler) {
|
||||
avm.eventHandler = handler
|
||||
}
|
||||
|
||||
func (avm *AsyncOttoVM) SetDefaultHandler() {
|
||||
avm.SetEventHandler(avm)
|
||||
}
|
||||
|
||||
func (avm *AsyncOttoVM) emitEvent(event Event) {
|
||||
if avm.eventHandler == nil { return }
|
||||
avm.eventHandler.HandleEvent(event)
|
||||
}
|
||||
|
||||
func NewAsyncOttoVM(vm *otto.Otto) *AsyncOttoVM {
|
||||
@ -73,6 +89,7 @@ func NewAsyncOttoVM(vm *otto.Otto) *AsyncOttoVM {
|
||||
vm: vm,
|
||||
Id: vmNum,
|
||||
}
|
||||
res.SetDefaultHandler()
|
||||
vmNum++
|
||||
return res
|
||||
}
|
||||
@ -133,7 +150,7 @@ func (avm *AsyncOttoVM) RunAsync(ctx context.Context, src interface{}) (job *Asy
|
||||
}(avm)
|
||||
|
||||
go func(avm *AsyncOttoVM) {
|
||||
defer func() { //runs after avm.vm.Run() returns (because script finished a was interrupted)
|
||||
defer func() { //runs after avm.vm.Run() returns (because script finished or was interrupted)
|
||||
defer avm.SetWorking(false)
|
||||
if caught := recover(); caught != nil {
|
||||
fmt.Printf("VM %d CAUGHT INTERRUPT, ENDING JOB %d\n", avm.Id, job.Id)
|
||||
@ -157,17 +174,26 @@ func (avm *AsyncOttoVM) RunAsync(ctx context.Context, src interface{}) (job *Asy
|
||||
job.ResultValue, job.ResultErr = avm.vm.Run(job.Source) //store result
|
||||
job.SetFinished() // signal job finished
|
||||
|
||||
//DEBUG
|
||||
//Emit event + print DEBUG
|
||||
evRes := Event{ Vm: avm, Job: job }
|
||||
//evRes.ScriptSource,_ = job.Source.(string) //if string, attach source to event
|
||||
if job.ResultErr == nil {
|
||||
jRes,jErr := job.ResultJsonString()
|
||||
if jErr == nil {
|
||||
fmt.Printf("JOB %d on VM %d SUCCEEDED WITH RESULT: %s\n", job.Id, avm.Id, jRes)
|
||||
evRes.Type = EventType_JOB_SUCCEEDED
|
||||
evRes.Message = fmt.Sprintf("JOB %d on VM %d SUCCEEDED WITH RESULT: %s", job.Id, avm.Id, jRes)
|
||||
fmt.Println(evRes.Message)
|
||||
} else {
|
||||
fmt.Printf("JOB %d on VM %d SUCCEEDED BUT RESULT COULDN'T BE MARSHALED TO JSON: %v\n", job.Id, avm.Id, jErr)
|
||||
evRes.Type = EventType_JOB_SUCCEEDED
|
||||
evRes.Message = fmt.Sprintf("JOB %d on VM %d SUCCEEDED BUT RESULT COULDN'T BE MARSHALED TO JSON: %v", job.Id, avm.Id, jErr)
|
||||
fmt.Println(evRes.Message)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("JOB %d on VM %d FAILED: %v\n", job.Id, avm.Id, job.ResultErr)
|
||||
evRes.Type = EventType_JOB_FAILED
|
||||
evRes.Message = fmt.Sprintf("JOB %d on VM %d FAILED: %v", job.Id, avm.Id, job.ResultErr)
|
||||
fmt.Println(evRes.Message)
|
||||
}
|
||||
avm.emitEvent(evRes)
|
||||
|
||||
}(avm)
|
||||
|
||||
|
46
hid/HIDEvent.go
Normal file
46
hid/HIDEvent.go
Normal file
@ -0,0 +1,46 @@
|
||||
package hid
|
||||
|
||||
type EventType int32
|
||||
|
||||
const (
|
||||
EventType_JOB_STARTED EventType = 0
|
||||
EventType_JOB_STOPPED EventType = 1
|
||||
EventType_CONTROLLER_ABORTED EventType = 2
|
||||
EventType_JOB_CANCELLED EventType = 3
|
||||
EventType_JOB_SUCCEEDED EventType = 4
|
||||
EventType_JOB_SUCCEEDED_NO_RESULT EventType = 5
|
||||
EventType_JOB_FAILED EventType = 6
|
||||
EventType_JOB_WAIT_LED_FINISHED EventType = 7
|
||||
EventType_JOB_WAIT_LED_REPEATED_FINISHED EventType = 8
|
||||
EventType_JOB_NO_FREE_VM EventType = 9
|
||||
|
||||
)
|
||||
|
||||
/*
|
||||
var EventType_name = map[int32]string{
|
||||
0: "JOB_STARTED",
|
||||
1: "JOB_STOPPED",
|
||||
2: "CONTROLLER_ABORTED",
|
||||
3: "JOB_CANCELLED",
|
||||
|
||||
}
|
||||
var EventType_value = map[string]int32{
|
||||
"JOB_STARTED": 0,
|
||||
"JOB_STOPPED": 1,
|
||||
"CONTROLLER_ABORTED": 2,
|
||||
"JOB_CANCELLED": 3,
|
||||
}
|
||||
*/
|
||||
|
||||
type Event struct {
|
||||
Type EventType
|
||||
Job *AsyncOttoJob
|
||||
Vm *AsyncOttoVM
|
||||
Message string
|
||||
//ScriptSource string
|
||||
}
|
||||
|
||||
|
||||
type EventHandler interface {
|
||||
HandleEvent(event Event)
|
||||
}
|
@ -59,6 +59,7 @@ type HIDController struct {
|
||||
vmMaster *otto.Otto
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
eventHandler EventHandler
|
||||
}
|
||||
|
||||
func NewHIDController(ctx context.Context, keyboardDevicePath string, keyboardMapPath string, mouseDevicePath string) (ctl *HIDController, err error) {
|
||||
@ -98,9 +99,30 @@ func NewHIDController(ctx context.Context, keyboardDevicePath string, keyboardMa
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
|
||||
hidControllerReuse.SetDefaultHandler()
|
||||
return hidControllerReuse, nil
|
||||
}
|
||||
|
||||
func (ctl *HIDController) SetEventHandler(handler EventHandler) {
|
||||
ctl.eventHandler = handler
|
||||
// set same handler for all child VMs
|
||||
for _,vm := range ctl.vmPool { vm.SetEventHandler(handler) }
|
||||
}
|
||||
|
||||
func (ctl *HIDController) HandleEvent(event Event) {
|
||||
fmt.Printf("!!! HID Controller Event: %+v\n", event)
|
||||
}
|
||||
|
||||
func (ctl *HIDController) SetDefaultHandler() {
|
||||
ctl.SetEventHandler(ctl)
|
||||
}
|
||||
|
||||
func (ctl *HIDController) emitEvent(event Event) {
|
||||
if ctl.eventHandler == nil { return }
|
||||
ctl.eventHandler.HandleEvent(event)
|
||||
|
||||
}
|
||||
|
||||
func (ctl *HIDController) Abort() {
|
||||
// stop the old LED reader if present
|
||||
// !! Keyboard.Close() has to be called before sending IRQ to VMs (there're JS function which register
|
||||
@ -113,6 +135,13 @@ func (ctl *HIDController) Abort() {
|
||||
// Interrupt all VMs already running
|
||||
//hidControllerReuse.CancelAllBackgroundJobs()
|
||||
hidControllerReuse.CancelAllBackgroundJobs()
|
||||
|
||||
ctl.emitEvent(Event{
|
||||
Type: EventType_CONTROLLER_ABORTED,
|
||||
Message: "Called abort on HID Controller",
|
||||
Job: nil,
|
||||
Vm: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func (ctl *HIDController) NextUnusedVM() (vm *AsyncOttoVM, err error) {
|
||||
@ -161,15 +190,52 @@ func (ctl *HIDController) GetBackgroundJobByID(id int) (job *AsyncOttoJob, err e
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (ctl *HIDController) retrieveJobFromOtto(vm *otto.Otto) (job *AsyncOttoJob, runVM *AsyncOttoVM, err error) {
|
||||
found := false
|
||||
globalJobListMutex.Lock()
|
||||
for cJob,_ := range globalJobList {
|
||||
vme := cJob.executingVM
|
||||
if vme == nil { continue }
|
||||
if vme.vm == vm {
|
||||
found = true
|
||||
job = cJob
|
||||
runVM = vme
|
||||
}
|
||||
|
||||
}
|
||||
globalJobListMutex.Unlock()
|
||||
if found {
|
||||
return
|
||||
} else {
|
||||
return nil,nil,errors.New("Couldn't retrieve job of this Otto VM")
|
||||
}
|
||||
}
|
||||
|
||||
func (ctl *HIDController) StartScriptAsBackgroundJob(ctx context.Context,script string) (job *AsyncOttoJob, err error) {
|
||||
//fetch next free vm from pool
|
||||
avm,err := ctl.NextUnusedVM()
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
ctl.emitEvent(Event{
|
||||
Job:job,
|
||||
Message:"No free Java VM available to run the script",
|
||||
Type:EventType_JOB_NO_FREE_VM,
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//try to run script async
|
||||
job,err = avm.RunAsync(ctx,script)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
ctl.emitEvent(Event{
|
||||
Job:job,
|
||||
Vm:avm,
|
||||
Type:EventType_JOB_STARTED,
|
||||
Message:"Script started",
|
||||
//ScriptSource:script,
|
||||
})
|
||||
|
||||
//add job to global list
|
||||
globalJobListMutex.Lock()
|
||||
globalJobList[job] = true
|
||||
@ -177,11 +243,19 @@ func (ctl *HIDController) StartScriptAsBackgroundJob(ctx context.Context,script
|
||||
|
||||
//ad go routine which monitors context of the job, to remove it from global list, once done or interrupted
|
||||
go func() {
|
||||
fmt.Printf("StartScriptAsBackgroundJob: started finish watcher for job %d\n",job.Id)
|
||||
//fmt.Printf("StartScriptAsBackgroundJob: started finish watcher for job %d\n",job.Id)
|
||||
select {
|
||||
case <- job.ctx.Done():
|
||||
fmt.Printf("StartScriptAsBackgroundJob: Job %d finished or interrupted, removing from global list\n",job.Id)
|
||||
|
||||
ctl.emitEvent(Event{
|
||||
Job:job,
|
||||
Vm:avm,
|
||||
Type:EventType_JOB_STOPPED,
|
||||
Message:"Script stopped",
|
||||
//ScriptSource:script,
|
||||
})
|
||||
|
||||
//remove job from global list after result has been retrieved
|
||||
globalJobListMutex.Lock()
|
||||
delete(globalJobList,job)
|
||||
@ -223,6 +297,12 @@ func (ctl *HIDController) CancelAllBackgroundJobs() {
|
||||
for job,_ := range oldList {
|
||||
fmt.Printf("Cancelling Job %d\n", job.Id)
|
||||
job.Cancel()
|
||||
ctl.emitEvent(Event{
|
||||
Job:job,
|
||||
Vm:job.executingVM,
|
||||
Type:EventType_JOB_CANCELLED,
|
||||
Message:"Script execution cancelled",
|
||||
})
|
||||
}
|
||||
globalJobList = make(map[*AsyncOttoJob]bool) //Create new empty list
|
||||
globalJobListMutex.Unlock()
|
||||
@ -419,7 +499,7 @@ func (ctl *HIDController) jsWaitLED(call otto.FunctionCall) (res otto.Value) {
|
||||
|
||||
errStr := ""
|
||||
if err != nil {errStr = fmt.Sprintf("%v",err)}
|
||||
res,_ = call.Otto.ToValue(struct{
|
||||
resStruct := struct{
|
||||
ERROR bool
|
||||
ERRORTEXT string
|
||||
TIMEOUT bool
|
||||
@ -437,7 +517,32 @@ func (ctl *HIDController) jsWaitLED(call otto.FunctionCall) (res otto.Value) {
|
||||
SCROLL: err == nil && changed.ScrollLock,
|
||||
COMPOSE: err == nil && changed.Compose,
|
||||
KANA: err == nil && changed.Kana,
|
||||
})
|
||||
}
|
||||
res,_ = call.Otto.ToValue(resStruct)
|
||||
|
||||
//Event generation
|
||||
resText := "WaitLED ended:"
|
||||
if resStruct.ERROR { resText = " ERROR " + errStr} else {
|
||||
if resStruct.NUM { resText += " NUM" }
|
||||
if resStruct.CAPS { resText += " CAPS" }
|
||||
if resStruct.SCROLL { resText += " SCROLL" }
|
||||
if resStruct.COMPOSE { resText += " COMPOSE" }
|
||||
if resStruct.KANA { resText += " KANA" }
|
||||
}
|
||||
sJob, sVM, err := ctl.retrieveJobFromOtto(call.Otto)
|
||||
if err == nil {
|
||||
ctl.emitEvent(Event{
|
||||
Type: EventType_JOB_WAIT_LED_FINISHED,
|
||||
Job: sJob,
|
||||
Vm: sVM,
|
||||
Message: resText,
|
||||
})
|
||||
} else {
|
||||
ctl.emitEvent(Event{
|
||||
Type: EventType_JOB_WAIT_LED_FINISHED,
|
||||
Message: resText + " (unknown Job)",
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -530,7 +635,7 @@ func (ctl *HIDController) jsWaitLEDRepeat(call otto.FunctionCall) (res otto.Valu
|
||||
|
||||
errStr := ""
|
||||
if err != nil {errStr = fmt.Sprintf("%v",err)}
|
||||
res,_ = call.Otto.ToValue(struct{
|
||||
resStruct := struct{
|
||||
ERROR bool
|
||||
ERRORTEXT string
|
||||
TIMEOUT bool
|
||||
@ -548,7 +653,32 @@ func (ctl *HIDController) jsWaitLEDRepeat(call otto.FunctionCall) (res otto.Valu
|
||||
SCROLL: err == nil && changed.ScrollLock,
|
||||
COMPOSE: err == nil && changed.Compose,
|
||||
KANA: err == nil && changed.Kana,
|
||||
})
|
||||
}
|
||||
res,_ = call.Otto.ToValue(resStruct)
|
||||
|
||||
//Event generation
|
||||
resText := "WaitLED ended:"
|
||||
if resStruct.ERROR { resText = " ERROR " + errStr} else {
|
||||
if resStruct.NUM { resText += " NUM" }
|
||||
if resStruct.CAPS { resText += " CAPS" }
|
||||
if resStruct.SCROLL { resText += " SCROLL" }
|
||||
if resStruct.COMPOSE { resText += " COMPOSE" }
|
||||
if resStruct.KANA { resText += " KANA" }
|
||||
}
|
||||
sJob, sVM, err := ctl.retrieveJobFromOtto(call.Otto)
|
||||
if err == nil {
|
||||
ctl.emitEvent(Event{
|
||||
Type: EventType_JOB_WAIT_LED_REPEATED_FINISHED,
|
||||
Job: sJob,
|
||||
Vm: sVM,
|
||||
Message: resText,
|
||||
})
|
||||
} else {
|
||||
ctl.emitEvent(Event{
|
||||
Type: EventType_JOB_WAIT_LED_REPEATED_FINISHED,
|
||||
Message: resText + " (unknown Job)",
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user