package cast import ( "context" "time" "forge.cadoles.com/arcad/edge/pkg/app" "forge.cadoles.com/arcad/edge/pkg/module" "github.com/dop251/goja" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) const ( defaultTimeout = 30 * time.Second ) type Module struct{} func (m *Module) Name() string { return "cast" } func (m *Module) Export(export *goja.Object) { if err := export.Set("refreshDevices", m.refreshDevices); err != nil { panic(errors.Wrap(err, "could not set 'refreshDevices' function")) } if err := export.Set("getDevices", m.getDevices); err != nil { panic(errors.Wrap(err, "could not set 'getDevices' function")) } if err := export.Set("loadUrl", m.loadUrl); err != nil { panic(errors.Wrap(err, "could not set 'loadUrl' function")) } if err := export.Set("stopCast", m.stopCast); err != nil { panic(errors.Wrap(err, "could not set 'stopCast' function")) } if err := export.Set("getStatus", m.getStatus); err != nil { panic(errors.Wrap(err, "could not set 'getStatus' function")) } } func (m *Module) refreshDevices(call goja.FunctionCall, rt *goja.Runtime) goja.Value { rawTimeout := call.Argument(0).String() timeout, err := m.parseTimeout(rawTimeout) if err != nil { panic(rt.ToValue(errors.WithStack(err))) } promise := app.NewPromiseProxyFrom(rt) go func() { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() devices, err := ListDevices(ctx, true) if err != nil { err = errors.WithStack(err) logger.Error(ctx, "error refreshing casting devices list", logger.CapturedE(errors.WithStack(err))) promise.Reject(err) return } promise.Resolve(devices) }() return rt.ToValue(promise) } func (m *Module) getDevices(call goja.FunctionCall, rt *goja.Runtime) goja.Value { ctx := context.Background() devices, err := ListDevices(ctx, false) if err != nil { panic(rt.ToValue(errors.WithStack(err))) } return rt.ToValue(devices) } func (m *Module) loadUrl(call goja.FunctionCall, rt *goja.Runtime) goja.Value { if len(call.Arguments) < 2 { panic(rt.ToValue(errors.WithStack(module.ErrUnexpectedArgumentsNumber))) } deviceUUID := call.Argument(0).String() url := call.Argument(1).String() rawTimeout := call.Argument(2).String() timeout, err := m.parseTimeout(rawTimeout) if err != nil { panic(rt.ToValue(errors.WithStack(err))) } promise := app.NewPromiseProxyFrom(rt) go func() { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() err := LoadURL(ctx, deviceUUID, url) if err != nil { err = errors.WithStack(err) logger.Error(ctx, "error while casting url", logger.CapturedE(err)) promise.Reject(err) return } promise.Resolve(nil) }() return rt.ToValue(promise) } func (m *Module) stopCast(call goja.FunctionCall, rt *goja.Runtime) goja.Value { if len(call.Arguments) < 1 { panic(rt.ToValue(errors.WithStack(module.ErrUnexpectedArgumentsNumber))) } deviceUUID := call.Argument(0).String() rawTimeout := call.Argument(1).String() timeout, err := m.parseTimeout(rawTimeout) if err != nil { panic(rt.ToValue(errors.WithStack(err))) } promise := app.NewPromiseProxyFrom(rt) go func() { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() err := StopCast(ctx, deviceUUID) if err != nil { err = errors.WithStack(err) logger.Error(ctx, "error while quitting casting device app", logger.CapturedE(errors.WithStack(err))) promise.Reject(err) return } promise.Resolve(nil) }() return rt.ToValue(promise) } func (m *Module) getStatus(call goja.FunctionCall, rt *goja.Runtime) goja.Value { if len(call.Arguments) < 1 { panic(rt.ToValue(errors.WithStack(module.ErrUnexpectedArgumentsNumber))) } deviceUUID := call.Argument(0).String() rawTimeout := call.Argument(1).String() timeout, err := m.parseTimeout(rawTimeout) if err != nil { panic(rt.ToValue(errors.WithStack(err))) } promise := app.NewPromiseProxyFrom(rt) go func() { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() status, err := getStatus(ctx, deviceUUID) if err != nil { err = errors.WithStack(err) logger.Error(ctx, "error while getting casting device status", logger.CapturedE(err)) promise.Reject(err) return } promise.Resolve(status) }() return rt.ToValue(promise) } func (m *Module) parseTimeout(rawTimeout string) (time.Duration, error) { var ( timeout time.Duration err error ) if rawTimeout == "undefined" { timeout = defaultTimeout } else { timeout, err = time.ParseDuration(rawTimeout) if err != nil { return defaultTimeout, errors.Wrapf(err, "invalid duration format '%s'", rawTimeout) } } return timeout, nil } func CastModuleFactory() app.ServerModuleFactory { return func(server *app.Server) app.ServerModule { return &Module{} } }