Continued working on global state exposed to Vuex

This commit is contained in:
MaMe82 2018-07-28 04:51:38 +02:00
parent 0a2a826223
commit 04c6f0d397
10 changed files with 823 additions and 590 deletions

View File

@ -51,8 +51,8 @@ func InitCompHIDScript() {
func(vm *hvue.VM) interface{} {
return vm.Store.Get("state").Get("currentHIDScriptSource")
},
func(vm *hvue.VM, newValue *js.Object) {
vm.Store.Call("commit", "setCurrentHIDScriptSource", newValue)
func(vm *hvue.VM, newScriptContent *js.Object) {
vm.Store.Call("commit", VUEX_MUTATION_SET_CURRENT_HID_SCRIPT_SOURCE_TO, newScriptContent)
}),
)
}

View File

@ -1 +1,57 @@
package main
import (
"github.com/mame82/hvue"
)
/*
type CompModalData struct {
*js.Object
ShowModal bool `js:"showModal"`
}
func NewCompModalData(vm *hvue.VM) interface{} {
d:= &CompModalData{Object:O()}
d.ShowModal = false
return d
}
*/
func InitCompModal() {
hvue.NewComponent(
"modal",
// hvue.DataFunc(NewCompModalData),
hvue.Template(compModalTemplate),
)
}
const compModalTemplate = `
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
Modal window header
</slot>
</div>
<div class="modal-body">
<slot name="body">
body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
footer
<button class="modal-default-button" @click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
`

View File

@ -2,10 +2,6 @@ package main
import (
"github.com/gopherjs/gopherjs/js"
pb "../proto/gopherjs"
"time"
"context"
"google.golang.org/grpc/status"
"github.com/mame82/hvue"
)
@ -19,69 +15,28 @@ type CompUSBSettingsData struct {
RndisDetails bool `js:"rndisDetails"`
}
//ToDo: Reimplement with Action on global state
//This becomes a method of the Vue Component and encapsulates dispatching of a Vuex action
func (c *CompUSBSettingsData) UpdateFromDeployedGadgetSettings(vm *hvue.VM) {
vm.Store.Call("commit", "setCurrentGadgetSettingsFromDeployed")
vm.Store.Call("dispatch", VUEX_ACTION_UPDATE_GADGET_SETTINGS_FROM_DEPLOYED)
}
//ToDo: Reimplement with actions on global state
//This becomes a method of the Vue Component and encapsulates dispatching of a Vuex action
func (c *CompUSBSettingsData) ApplyGadgetSettings(vm *hvue.VM) {
//println("Trying to deploy GadgetSettings: " + fmt.Sprintf("%+v",c.GadgetSettings.toGS()))
println("Trying to deploy GadgetSettings...")
//gs:=c.GadgetSettings.toGS()
gs := jsGadgetSettings{Object: vm.Store.Get("state").Get("currentGadgetSettings")}.toGS()
go func() {
c.DeployPending = true
defer func() {c.DeployPending = false}()
ctx,cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
//Set gadget settings
_, err := Client.Client.SetGadgetSettings(ctx, gs)
if err != nil {
js.Global.Call("alert", "Error setting given gadget settings: " + status.Convert(err).Message())
println(err)
c.UpdateFromDeployedGadgetSettings(vm)
return
}
println("New GadgetSettings have been set")
//deploy the settings
deployedGs,err := Client.Client.DeployGadgetSetting(ctx, &pb.Empty{})
if err != nil {
js.Global.Call("alert", "Error deploying gadget settings: " + status.Convert(err).Message())
println(err)
c.UpdateFromDeployedGadgetSettings(vm)
return
}
println("New GadgetSettings have been deployed")
js.Global.Call("alert", "New USB gadget settings deployed ")
newGs := &jsGadgetSettings{
Object: js.Global.Get("Object").New(),
}
newGs.fromGS(deployedGs)
c.GadgetSettings = newGs
}()
vm.Store.Call("dispatch", VUEX_ACTION_DEPLOY_CURRENT_GADGET_SETTINGS)
}
func InitCompUSBSettings() {
hvue.NewComponent(
"usb-settings",
hvue.Template(compUSBSettingsTemplate),
hvue.DataFunc(newCompUSBSettingsData),
hvue.MethodsOf(&CompUSBSettingsData{}),
hvue.MethodsOf(&CompUSBSettingsData{}), // Add the methods of CompUSBSettingsData to the Vue Component instance
hvue.Computed(
"currentGadgetSettings",
func(vm *hvue.VM) interface{} {
return vm.Store.Get("state").Get("currentGadgetSettings")
}),
)
}
@ -90,10 +45,8 @@ func newCompUSBSettingsData(vm *hvue.VM) interface{} {
cc := &CompUSBSettingsData{
Object: js.Global.Get("Object").New(),
}
cc.GadgetSettings = NewUSBGadgetSettings()
cc.UpdateFromDeployedGadgetSettings(vm)
cc.DeployPending = false
cc.RndisDetails = false
cc.CdcEcmDetails = false
@ -177,4 +130,3 @@ const (
</div>
`
)

View File

@ -8,8 +8,11 @@ import (
"sync"
"context"
"io"
"fmt"
)
var eNoLogEvent = errors.New("No log event")
/* USB Gadget types corresponding to gRPC messages */
type jsGadgetSettings struct {
@ -129,8 +132,41 @@ func NewUSBGadgetSettings() *jsGadgetSettings {
/** Events **/
type jsEvent struct {
*js.Object
Type int64 `js:"type"`
Values []interface{}
JSValues *js.Object `js:"values"`
}
func NewJsEventFromNative(event *pb.Event) (res *jsEvent) {
res = &jsEvent{Object:O()}
res.JSValues = js.Global.Get("Array").New()
res.Type = event.Type
res.Values = make([]interface{}, len(event.Values))
for idx,val := range event.Values {
switch valT := val.Val.(type) {
case *pb.EventValue_Tint64:
res.Values[idx] = valT.Tint64
res.JSValues.Call("push", valT.Tint64)
case *pb.EventValue_Tstring:
res.Values[idx] = valT.Tstring
res.JSValues.Call("push", valT.Tstring)
case *pb.EventValue_Tbool:
res.Values[idx] = valT.Tbool
res.JSValues.Call("push", valT.Tbool)
default:
println("error parsing event value", valT)
}
}
println("result",res)
return res
}
//Log event
type jsEventLog struct {
type jsLogEvent struct {
*js.Object
EvLogSource string `js:"source"`
EvLogLevel int `js:"level"`
@ -138,10 +174,32 @@ type jsEventLog struct {
EvLogTime string `js:"time"`
}
func DeconstructEventLog(gRPCEv *pb.Event) (res *jsEventLog, err error) {
func (jsEv *jsEvent) toLogEvent() (res *jsLogEvent, err error) {
if jsEv.Type != common.EVT_LOG || len(jsEv.Values) != 4 { return nil,eNoLogEvent}
res = &jsLogEvent{Object:O()}
var ok bool
res.EvLogSource,ok = jsEv.Values[0].(string)
if !ok { return nil,eNoLogEvent }
ll,ok := jsEv.Values[1].(int64)
if !ok { return nil,eNoLogEvent}
res.EvLogLevel = int(ll)
res.EvLogMessage,ok = jsEv.Values[2].(string)
if !ok { return nil,eNoLogEvent}
res.EvLogTime,ok = jsEv.Values[3].(string)
if !ok { return nil,eNoLogEvent}
return res,nil
}
/*
func DeconstructEventLog(gRPCEv *pb.Event) (res *jsLogEvent, err error) {
if gRPCEv.Type != common.EVT_LOG { return nil,errors.New("No log event")}
res = &jsEventLog{Object:O()}
res = &jsLogEvent{Object:O()}
switch vT := gRPCEv.Values[0].Val.(type) {
case *pb.EventValue_Tstring:
res.EvLogSource = vT.Tstring
@ -169,18 +227,31 @@ func DeconstructEventLog(gRPCEv *pb.Event) (res *jsEventLog, err error) {
return res, nil
}
*/
/* EVENT LOGGER */
type jsLoggerData struct {
*js.Object
LogArray *js.Object `js:"logArray"`
EventArray *js.Object `js:"eventArray"`
cancel context.CancelFunc
*sync.Mutex
MaxEntries int `js:"maxEntries"`
}
func NewLogger(maxEntries int) *jsLoggerData {
loggerVmData := &jsLoggerData{
Object: js.Global.Get("Object").New(),
}
loggerVmData.Mutex = &sync.Mutex{}
loggerVmData.LogArray = js.Global.Get("Array").New()
loggerVmData.EventArray = js.Global.Get("Array").New()
loggerVmData.MaxEntries = maxEntries
return loggerVmData
}
/* This method gets internalized and therefor the mutex won't be accessible*/
func (data *jsLoggerData) AddEntry(ev *pb.Event ) {
@ -191,6 +262,23 @@ func (data *jsLoggerData) AddEntry(ev *pb.Event ) {
defer data.Unlock()
*/
fmt.Println("LOOOOOG ENTRYYYYYYYYYYYYYYYYY")
//if LOG event add to logArray
jsEv := NewJsEventFromNative(ev)
println("JS from native", jsEv)
if jsEv.Type == common.EVT_LOG {
if logEv,err := jsEv.toLogEvent(); err == nil {
data.LogArray.Call("push", logEv)
} else {
println("couldn't convert to LogEvent: ", jsEv)
}
} else {
data.EventArray.Call("push", jsEv)
}
/*
logEv, err := DeconstructEventLog(ev)
if err != nil {
println("Logger: Error adding log entry, provided event couldn't be converted to log event")
@ -198,11 +286,15 @@ func (data *jsLoggerData) AddEntry(ev *pb.Event ) {
}
data.LogArray.Call("push", logEv)
*/
//reduce to length (note: kebab case 'max-entries' is translated to camel case 'maxEntries' by vue)
for data.LogArray.Length() > data.MaxEntries {
data.LogArray.Call("shift") // remove first element
}
for data.EventArray.Length() > data.MaxEntries {
data.EventArray.Call("shift") // remove first element
}
}()
@ -224,6 +316,7 @@ func (data *jsLoggerData) StartListening() {
go func() {
defer cancel()
println("EVENTLISTENING ENTERING LOOP")
for {
event, err := evStream.Recv()
if err == io.EOF { break }
@ -231,8 +324,9 @@ func (data *jsLoggerData) StartListening() {
//println("Event: ", event)
data.AddEntry(event)
println(event)
}
println("EVENTLISTENING ABORTED")
return
}()
}
@ -242,14 +336,3 @@ func (data *jsLoggerData) StopListening() {
data.cancel()
}
func NewLogger(maxEntries int) *jsLoggerData {
loggerVmData := &jsLoggerData{
Object: js.Global.Get("Object").New(),
}
loggerVmData.Mutex = &sync.Mutex{}
loggerVmData.LogArray = js.Global.Get("Array").New()
loggerVmData.MaxEntries = maxEntries
return loggerVmData
}

View File

@ -69,6 +69,7 @@ func main() {
InitGlobalState() //sets Vuex store in JS window.store
InitCompModal()
InitCompEthernetAddresses2()
InitCompToggleSwitch()
InitCompUSBSettings()

View File

@ -52,24 +52,6 @@ type GlobalState struct {
Text string `js:"text"`
}
/*
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()
deployedGs, err := Client.Client.GetDeployedGadgetSetting(ctx, &pb.Empty{})
if err != nil { println(err); return } // ToDo: change to alert with parsed status
jsGS.fromGS(deployedGs)
return
}
*/
func createGlobalStateStruct() GlobalState {
state := GlobalState{Object:O()}
@ -115,7 +97,7 @@ func actionDeployCurrentGadgetSettings(store *mvuex.Store, context *mvuex.Action
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)
Alert(err.Error())
return
}
@ -123,7 +105,7 @@ func actionDeployCurrentGadgetSettings(store *mvuex.Store, context *mvuex.Action
_,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)
Alert(err.Error())
return
}

View File

@ -3,10 +3,9 @@ package main
import (
pb "../proto/gopherjs"
"context"
"io"
"sync"
"errors"
"github.com/johanbrandhorst/protobuf/grpcweb"
"time"
)
type Rpc struct {
@ -17,6 +16,7 @@ type Rpc struct {
eventListeningCancel *context.CancelFunc
}
/*
func (rpc *Rpc) StartListenEvents(evtType int64) (err error) {
rpc.Lock()
if rpc.eventListeningOn {
@ -65,6 +65,7 @@ func (rpc *Rpc) StopEventListening() {
rpc.eventListeningOn = false
rpc.Unlock()
}
*/
func NewRpcClient(addr string) Rpc {
rcl := Rpc{}
@ -73,3 +74,48 @@ func NewRpcClient(addr string) Rpc {
rcl.Client = cl
return rcl
}
func RpcGetDeployedGadgetSettings(timeout time.Duration) (*pb.GadgetSettings, error) {
//gs := vue.GetVM(c).Get("gadgetSettings")
println("RpcGetDeployedGadgetSettings called")
ctx,cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return Client.Client.GetDeployedGadgetSetting(ctx, &pb.Empty{})
}
func RpcSetRemoteGadgetSettings(targetGS *pb.GadgetSettings, timeout time.Duration) (err error) {
//gs := vue.GetVM(c).Get("gadgetSettings")
println("RpcSetRemoteGadgetSettings called")
ctx,cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
//Set gadget settings
_, err = Client.Client.SetGadgetSettings(ctx, targetGS)
if err != nil {
//js.Global.Call("alert", "Error setting given gadget settings: " + status.Convert(err).Message())
//println(err)
//c.UpdateFromDeployedGadgetSettings(vm)
return err
}
return nil
}
func RpcDeployRemoteGadgetSettings(timeout time.Duration) (*pb.GadgetSettings, error) {
//gs := vue.GetVM(c).Get("gadgetSettings")
println("RpcDeployRemoteGadgetSettings called")
ctx,cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return Client.Client.DeployGadgetSetting(ctx, &pb.Empty{})
}

View File

@ -7,8 +7,6 @@
<script src="codemirror/lib/codemirror.js"></script>
<link rel="stylesheet" href="codemirror/lib/codemirror.css">
<script src="codemirror/mode/javascript/javascript.js"></script>
@ -24,6 +22,70 @@
height: 60%;
}
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>
@ -41,6 +103,10 @@
<td><state></state></td>
</tr>
</table>
<modal v-if="$store.state.isModalEnabled" @close="$store.commit('setModalEnabled',false)">
<h3 slot="header">My header</h3>
<p slot="body">Some body text</p>
</modal>
<tabs>
<tab header="USB">

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long