Skip to content

Commit

Permalink
snes: refactor to remove useless DeviceDriver.Use method; mapping.Det…
Browse files Browse the repository at this point in the history
…ect accepts a UseMemory interface to dynamically require the ReadMemory capability when actual reading memory; moved all capability checks closer to when they are actually used
  • Loading branch information
JamesDunne committed Jun 22, 2021
1 parent ac03e53 commit a1acdbc
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 135 deletions.
23 changes: 11 additions & 12 deletions cmd/sni/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,17 @@ func (s *deviceMemoryService) MappingDetect(gctx context.Context, request *sni.D
return
}

gerr = snes.UseDeviceMemory(
gerr = snes.WithDevice(
gctx,
uri,
// TODO: this capability is optional; validate it in the call itself when it is about to be used:
[]sni.DeviceCapability{sni.DeviceCapability_ReadMemory},
func(mctx context.Context, memory snes.DeviceMemory) (err error) {
nil,
func(mctx context.Context, device snes.Device) (err error) {
var memoryMapping sni.MemoryMapping
var confidence bool
var outHeaderBytes []byte
memoryMapping, confidence, outHeaderBytes, err = mapping.Detect(
mctx,
memory,
device,
request.FallbackMemoryMapping,
request.RomHeader00FFB0,
)
Expand Down Expand Up @@ -117,7 +116,7 @@ func (s *deviceMemoryService) SingleRead(
return
}

gerr = snes.UseDeviceMemory(
gerr = snes.WithDeviceMemory(
rctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_ReadMemory},
Expand Down Expand Up @@ -185,7 +184,7 @@ func (s *deviceMemoryService) SingleWrite(
return
}

gerr = snes.UseDeviceMemory(
gerr = snes.WithDeviceMemory(
rctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_WriteMemory},
Expand Down Expand Up @@ -254,7 +253,7 @@ func (s *deviceMemoryService) MultiRead(
}

var grsps []*sni.ReadMemoryResponse
gerr = snes.UseDeviceMemory(
gerr = snes.WithDeviceMemory(
gctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_ReadMemory},
Expand Down Expand Up @@ -339,7 +338,7 @@ func (s *deviceMemoryService) MultiWrite(
}

var grsps []*sni.WriteMemoryResponse
gerr = snes.UseDeviceMemory(
gerr = snes.WithDeviceMemory(
gctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_WriteMemory},
Expand Down Expand Up @@ -424,7 +423,7 @@ func (d *deviceControlService) ResetSystem(gctx context.Context, request *sni.Re
return
}

gerr = snes.UseDeviceControl(
gerr = snes.WithDeviceControl(
gctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_ResetSystem},
Expand Down Expand Up @@ -456,7 +455,7 @@ func (d *deviceControlService) PauseUnpauseEmulation(gctx context.Context, reque
}

paused := false
gerr = snes.UseDeviceControl(
gerr = snes.WithDeviceControl(
gctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_PauseUnpauseEmulation},
Expand Down Expand Up @@ -489,7 +488,7 @@ func (d *deviceControlService) PauseToggleEmulation(gctx context.Context, reques
return
}

gerr = snes.UseDeviceControl(
gerr = snes.WithDeviceControl(
gctx,
uri,
[]sni.DeviceCapability{sni.DeviceCapability_PauseToggleEmulation},
Expand Down
2 changes: 1 addition & 1 deletion protos/sni/sni.proto
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ message DevicesResponse {
// URI that describes exactly how to connect to the device, e.g.:
// RetroArch: "ra://127.0.0.1:55355"
// FX Pak Pro: "fxpakpro:///dev/cu.usbmodemDEMO000000001" (MacOS)
// "fxpakpro://COM4" (Windows)
// "fxpakpro://./COM4" (Windows)
// uri is used as the unique identifier of the device for clients to refer to
string uri = 1;
// friendly display name of the device
Expand Down
15 changes: 8 additions & 7 deletions snes/basedriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ import (
)

type BaseDeviceDriver struct {
DeviceDriver

// track opened devices by URI
devicesRw sync.RWMutex
devicesMap map[string]Device
}

func (b *BaseDeviceDriver) UseDevice(
ctx context.Context,
deviceKey string,
openDevice func() (Device, error),
use DeviceUser,
) (err error) {
func (b *BaseDeviceDriver) UseDevice(ctx context.Context, deviceKey string, requiredCapabilities []sni.DeviceCapability, openDevice func() (Device, error), use DeviceUser, ) (err error) {
var device Device
var ok bool

if ok, err = b.DeviceDriver.HasCapabilities(requiredCapabilities...); !ok {
return
}

b.devicesRw.RLock()
device, ok = b.devicesMap[deviceKey]
b.devicesRw.RUnlock()
Expand All @@ -41,7 +42,7 @@ func (b *BaseDeviceDriver) UseDevice(
b.devicesRw.Unlock()
}

err = device.Use(ctx, use)
err = use(ctx, device)

if device.IsClosed() {
b.devicesRw.Lock()
Expand Down
10 changes: 9 additions & 1 deletion snes/control.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package snes

import "context"
import (
"context"
"sni/protos/sni"
)

type DeviceControlUser func(ctx context.Context, control DeviceControl) error

Expand All @@ -10,3 +13,8 @@ type DeviceControl interface {
PauseUnpause(ctx context.Context, pausedState bool) (bool, error)
PauseToggle(ctx context.Context) error
}

type UseControl interface {
// UseControl provides exclusive access to only the control subsystem of the device to the user func
UseControl(ctx context.Context, requiredCapabilities []sni.DeviceCapability, user DeviceControlUser) error
}
16 changes: 3 additions & 13 deletions snes/device.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
package snes

import (
"context"
)

// Device acts as an exclusive-access gateway to the subsystems of the SNES device
type Device interface {
IsClosed() bool

// Use provides non-exclusive access to the device's subsystems to the user func
Use(ctx context.Context, user DeviceUser) error
UseControl
UseMemory

// UseMemory provides exclusive access to only the memory subsystem of the device to the user func
UseMemory(ctx context.Context, user DeviceMemoryUser) error

// UseControl provides exclusive access to only the control subsystem of the device to the user func
UseControl(ctx context.Context, user DeviceControlUser) error
IsClosed() bool
}
36 changes: 15 additions & 21 deletions snes/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ type Driver interface {

type DeviceUser func(context.Context, Device) error

type UseDevice interface {
// UseDevice grants non-exclusive access for DeviceUser to a Device uniquely identified by its uri
UseDevice(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user DeviceUser) error
}

// DeviceDriver extends Driver
type DeviceDriver interface {
DeviceKey(uri *url.URL) string
UseDevice

// UseDevice grants non-exclusive access for DeviceUser to a Device uniquely identified by its uri
UseDevice(ctx context.Context, uri *url.URL, user DeviceUser) error
DeviceKey(uri *url.URL) string

HasCapabilities(capabilities ...sni.DeviceCapability) (bool, error)
}
Expand Down Expand Up @@ -138,46 +142,36 @@ func DeviceDriverByUri(uri *url.URL) (drv DeviceDriver, err error) {
return
}

func UseDevice(ctx context.Context, uri *url.URL, user DeviceUser) (err error) {
func WithDevice(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user DeviceUser) (err error) {
var drv DeviceDriver
drv, err = DeviceDriverByUri(uri)
if err != nil {
return
}

return drv.UseDevice(ctx, uri, user)
return drv.UseDevice(ctx, uri, requiredCapabilities, user)
}

func UseDeviceMemory(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user DeviceMemoryUser) (err error) {
func WithDeviceMemory(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user DeviceMemoryUser) (err error) {
var drv DeviceDriver
drv, err = DeviceDriverByUri(uri)
if err != nil {
return
}

var ok bool
if ok, err = drv.HasCapabilities(requiredCapabilities...); !ok {
return
}

return drv.UseDevice(ctx, uri, func(ctx context.Context, device Device) error {
return device.UseMemory(ctx, user)
return drv.UseDevice(ctx, uri, requiredCapabilities, func(ctx context.Context, device Device) error {
return device.UseMemory(ctx, nil, user)
})
}

func UseDeviceControl(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user DeviceControlUser) (err error) {
func WithDeviceControl(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user DeviceControlUser) (err error) {
var drv DeviceDriver
drv, err = DeviceDriverByUri(uri)
if err != nil {
return
}

var ok bool
if ok, err = drv.HasCapabilities(requiredCapabilities...); !ok {
return
}

return drv.UseDevice(ctx, uri, func(ctx context.Context, device Device) error {
return device.UseControl(ctx, user)
return drv.UseDevice(ctx, uri, requiredCapabilities, func(ctx context.Context, device Device) error {
return device.UseControl(ctx, nil, user)
})
}
16 changes: 8 additions & 8 deletions snes/fxpakpro/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@ func (d *Device) IsClosed() bool {
return d.isClosed
}

func (d *Device) Use(ctx context.Context, user snes.DeviceUser) error {
func (d *Device) UseMemory(ctx context.Context, requiredCapabilities []sni.DeviceCapability, user snes.DeviceMemoryUser) error {
if user == nil {
return nil
}

return user(ctx, d)
}

func (d *Device) UseMemory(ctx context.Context, user snes.DeviceMemoryUser) error {
if user == nil {
return nil
if ok, err := driver.HasCapabilities(requiredCapabilities...); !ok {
return err
}

defer d.lock.Unlock()
Expand All @@ -44,11 +40,15 @@ func (d *Device) UseMemory(ctx context.Context, user snes.DeviceMemoryUser) erro
return user(ctx, d)
}

func (d *Device) UseControl(ctx context.Context, user snes.DeviceControlUser) error {
func (d *Device) UseControl(ctx context.Context, requiredCapabilities []sni.DeviceCapability, user snes.DeviceControlUser) error {
if user == nil {
return nil
}

if ok, err := driver.HasCapabilities(requiredCapabilities...); !ok {
return err
}

defer d.lock.Unlock()
d.lock.Lock()

Expand Down
13 changes: 8 additions & 5 deletions snes/fxpakpro/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const (
driverName = "fxpakpro"
)

var driver *Driver

var (
ErrNoFXPakProFound = fmt.Errorf("%s: no device found among serial ports", driverName)

Expand Down Expand Up @@ -186,13 +188,12 @@ func (d *Driver) openAsDevice(uri *url.URL) (device snes.Device, err error) {
return
}

func (d *Driver) UseDevice(ctx context.Context, uri *url.URL, user snes.DeviceUser) error {
func (d *Driver) UseDevice(ctx context.Context, uri *url.URL, requiredCapabilities []sni.DeviceCapability, user snes.DeviceUser) error {
return d.base.UseDevice(
ctx,
d.DeviceKey(uri),
func() (snes.Device, error) {
return d.openAsDevice(uri)
},
requiredCapabilities,
func() (snes.Device, error) { return d.openAsDevice(uri) },
user,
)
}
Expand All @@ -202,5 +203,7 @@ func init() {
log.Printf("disabling fxpakpro snes driver\n")
return
}
snes.Register(driverName, &Driver{})
driver = &Driver{}
driver.base.DeviceDriver = driver
snes.Register(driverName, driver)
}
25 changes: 14 additions & 11 deletions snes/luabridge/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net"
"sni/protos/sni"
"sni/snes"
"strings"
"sync"
Expand All @@ -15,7 +16,6 @@ type Device struct {
lock sync.Mutex
c *net.TCPConn

driver *Driver
deviceKey string

isClosed bool
Expand All @@ -24,10 +24,9 @@ type Device struct {
version string
}

func NewDevice(conn *net.TCPConn, key string, driver *Driver) *Device {
func NewDevice(conn *net.TCPConn, key string) *Device {
d := &Device{
c: conn,
driver: driver,
deviceKey: key,
isClosed: false,
clientName: "Unknown",
Expand Down Expand Up @@ -170,23 +169,27 @@ func (d *Device) Close() (err error) {
err = d.c.Close()

// remove device from driver:
d.driver.devicesRw.Lock()
delete(d.driver.devicesMap, d.deviceKey)
d.driver.devicesRw.Unlock()
driver.devicesRw.Lock()
delete(driver.devicesMap, d.deviceKey)
driver.devicesRw.Unlock()

return
}

func (d *Device) IsClosed() bool { return d.isClosed }

func (d *Device) Use(ctx context.Context, user snes.DeviceUser) error {
return user(ctx, d)
}
func (d *Device) UseMemory(ctx context.Context, requiredCapabilities []sni.DeviceCapability, user snes.DeviceMemoryUser) error {
if ok, err := driver.HasCapabilities(requiredCapabilities...); !ok {
return err
}

func (d *Device) UseMemory(ctx context.Context, user snes.DeviceMemoryUser) error {
return user(ctx, d)
}

func (d *Device) UseControl(ctx context.Context, user snes.DeviceControlUser) error {
func (d *Device) UseControl(ctx context.Context, requiredCapabilities []sni.DeviceCapability, user snes.DeviceControlUser) error {
if ok, err := driver.HasCapabilities(requiredCapabilities...); !ok {
return err
}

return user(ctx, d)
}
Loading

0 comments on commit a1acdbc

Please sign in to comment.