Switch to autogenerated DRPC framework

This commit is contained in:
2023-01-02 22:30:17 -08:00
parent 15b5d2888e
commit d41872ab64
21 changed files with 3600 additions and 616 deletions

View File

@@ -4,14 +4,15 @@ import (
"io"
"net"
"go.arsenm.dev/lrpc/client"
"go.arsenm.dev/lrpc/codec"
"go.arsenm.dev/itd/internal/rpc"
"storj.io/drpc/drpcconn"
)
const DefaultAddr = "/tmp/itd/socket"
type Client struct {
client *client.Client
conn *drpcconn.Conn
client rpc.DRPCITDClient
}
func New(sockPath string) (*Client, error) {
@@ -19,19 +20,27 @@ func New(sockPath string) (*Client, error) {
if err != nil {
return nil, err
}
dconn := drpcconn.New(conn)
out := &Client{
client: client.New(conn, codec.Default),
}
return out, nil
return &Client{
conn: dconn,
client: rpc.NewDRPCITDClient(dconn),
}, nil
}
func NewFromConn(conn io.ReadWriteCloser) *Client {
dconn := drpcconn.New(conn)
return &Client{
client: client.New(conn, codec.Default),
conn: dconn,
client: rpc.NewDRPCITDClient(dconn),
}
}
func (c *Client) Close() error {
return c.client.Close()
func (c *Client) FS() *FSClient {
return &FSClient{rpc.NewDRPCFSClient(c.conn)}
}
func (c *Client) Close() error {
return c.conn.Close()
}

View File

@@ -3,24 +3,34 @@ package api
import (
"context"
"go.arsenm.dev/infinitime"
"go.arsenm.dev/itd/internal/rpc"
)
func (c *Client) FirmwareUpgrade(ctx context.Context, upgType UpgradeType, files ...string) (chan infinitime.DFUProgress, error) {
progressCh := make(chan infinitime.DFUProgress, 5)
err := c.client.Call(
ctx,
"ITD",
"FirmwareUpgrade",
FwUpgradeData{
Type: upgType,
Files: files,
},
progressCh,
)
type DFUProgress struct {
Sent int64
Received int64
Total int64
Err error
}
func (c *Client) FirmwareUpgrade(ctx context.Context, upgType UpgradeType, files ...string) (chan DFUProgress, error) {
progressCh := make(chan DFUProgress, 5)
fc, err := c.client.FirmwareUpgrade(ctx, &rpc.FirmwareUpgradeRequest{
Type: rpc.FirmwareUpgradeRequest_Type(upgType),
Files: files,
})
if err != nil {
return nil, err
}
go fsRecvToChannel[rpc.DFUProgress](fc, progressCh, func(evt *rpc.DFUProgress, err error) DFUProgress {
return DFUProgress{
Sent: evt.Sent,
Received: evt.Recieved,
Total: evt.Total,
Err: err,
}
})
return progressCh, nil
}

155
api/fs.go
View File

@@ -1,96 +1,119 @@
package api
import "context"
import (
"context"
"errors"
"io"
func (c *Client) RemoveAll(ctx context.Context, paths ...string) error {
return c.client.Call(
ctx,
"FS",
"RemoveAll",
paths,
nil,
)
"go.arsenm.dev/itd/internal/rpc"
)
type FSClient struct {
client rpc.DRPCFSClient
}
func (c *Client) Remove(ctx context.Context, paths ...string) error {
return c.client.Call(
ctx,
"FS",
"Remove",
paths,
nil,
)
func (c *FSClient) RemoveAll(ctx context.Context, paths ...string) error {
_, err := c.client.RemoveAll(ctx, &rpc.PathsRequest{Paths: paths})
return err
}
func (c *Client) Rename(ctx context.Context, old, new string) error {
return c.client.Call(
ctx,
"FS",
"Rename",
[2]string{old, new},
nil,
)
func (c *FSClient) Remove(ctx context.Context, paths ...string) error {
_, err := c.client.Remove(ctx, &rpc.PathsRequest{Paths: paths})
return err
}
func (c *Client) MkdirAll(ctx context.Context, paths ...string) error {
return c.client.Call(
ctx,
"FS",
"MkdirAll",
paths,
nil,
)
func (c *FSClient) Rename(ctx context.Context, old, new string) error {
_, err := c.client.Rename(ctx, &rpc.RenameRequest{
From: old,
To: new,
})
return err
}
func (c *Client) Mkdir(ctx context.Context, paths ...string) error {
return c.client.Call(
ctx,
"FS",
"Mkdir",
paths,
nil,
)
func (c *FSClient) MkdirAll(ctx context.Context, paths ...string) error {
_, err := c.client.MkdirAll(ctx, &rpc.PathsRequest{Paths: paths})
return err
}
func (c *Client) ReadDir(ctx context.Context, dir string) (out []FileInfo, err error) {
err = c.client.Call(
ctx,
"FS",
"ReadDir",
dir,
&out,
)
return
func (c *FSClient) Mkdir(ctx context.Context, paths ...string) error {
_, err := c.client.Mkdir(ctx, &rpc.PathsRequest{Paths: paths})
return err
}
func (c *Client) Upload(ctx context.Context, dst, src string) (chan FSTransferProgress, error) {
func (c *FSClient) ReadDir(ctx context.Context, dir string) ([]FileInfo, error) {
res, err := c.client.ReadDir(ctx, &rpc.PathRequest{Path: dir})
return convertEntries(res.Entries), err
}
func convertEntries(e []*rpc.FileInfo) []FileInfo {
out := make([]FileInfo, len(e))
for i, fi := range e {
out[i] = FileInfo{
Name: fi.Name,
Size: fi.Size,
IsDir: fi.IsDir,
}
}
return out
}
func (c *FSClient) Upload(ctx context.Context, dst, src string) (chan FSTransferProgress, error) {
progressCh := make(chan FSTransferProgress, 5)
err := c.client.Call(
ctx,
"FS",
"Upload",
[2]string{dst, src},
progressCh,
)
tc, err := c.client.Upload(ctx, &rpc.TransferRequest{Source: src, Destination: dst})
if err != nil {
return nil, err
}
go fsRecvToChannel[rpc.TransferProgress](tc, progressCh, func(evt *rpc.TransferProgress, err error) FSTransferProgress {
return FSTransferProgress{
Sent: evt.Sent,
Total: evt.Total,
Err: err,
}
})
return progressCh, nil
}
func (c *Client) Download(ctx context.Context, dst, src string) (chan FSTransferProgress, error) {
func (c *FSClient) Download(ctx context.Context, dst, src string) (chan FSTransferProgress, error) {
progressCh := make(chan FSTransferProgress, 5)
err := c.client.Call(
ctx,
"FS",
"Download",
[2]string{dst, src},
progressCh,
)
tc, err := c.client.Download(ctx, &rpc.TransferRequest{Source: src, Destination: dst})
if err != nil {
return nil, err
}
go fsRecvToChannel[rpc.TransferProgress](tc, progressCh, func(evt *rpc.TransferProgress, err error) FSTransferProgress {
return FSTransferProgress{
Sent: evt.Sent,
Total: evt.Total,
Err: err,
}
})
return progressCh, nil
}
// fsRecvToChannel converts a DRPC stream client to a Go channel, using cf to convert
// RPC generated types to API response types.
func fsRecvToChannel[R any, A any](s StreamClient[R], ch chan<- A, cf func(evt *R, err error) A) {
defer close(ch)
var err error
var evt *R
for {
select {
case <-s.Context().Done():
return
default:
evt, err = s.Recv()
if errors.Is(err, io.EOF) {
return
} else if err != nil {
ch <- cf(new(R), err)
return
}
ch <- cf(evt, nil)
}
}
}

View File

@@ -3,71 +3,39 @@ package api
import (
"context"
"go.arsenm.dev/infinitime"
"go.arsenm.dev/itd/internal/rpc"
)
func (c *Client) HeartRate(ctx context.Context) (out uint8, err error) {
err = c.client.Call(
ctx,
"ITD",
"HeartRate",
nil,
&out,
)
return
func (c *Client) HeartRate(ctx context.Context) (uint8, error) {
res, err := c.client.HeartRate(ctx, &rpc.Empty{})
return uint8(res.Value), err
}
func (c *Client) BatteryLevel(ctx context.Context) (out uint8, err error) {
err = c.client.Call(
ctx,
"ITD",
"BatteryLevel",
nil,
&out,
)
return
func (c *Client) BatteryLevel(ctx context.Context) (uint8, error) {
res, err := c.client.BatteryLevel(ctx, &rpc.Empty{})
return uint8(res.Value), err
}
func (c *Client) Motion(ctx context.Context) (out infinitime.MotionValues, err error) {
err = c.client.Call(
ctx,
"ITD",
"Motion",
nil,
&out,
)
return
type MotionValues struct {
X, Y, Z int16
}
func (c *Client) Motion(ctx context.Context) (MotionValues, error) {
res, err := c.client.Motion(ctx, &rpc.Empty{})
return MotionValues{int16(res.X), int16(res.Y), int16(res.Z)}, err
}
func (c *Client) StepCount(ctx context.Context) (out uint32, err error) {
err = c.client.Call(
ctx,
"ITD",
"StepCount",
nil,
&out,
)
return
res, err := c.client.StepCount(ctx, &rpc.Empty{})
return res.Value, err
}
func (c *Client) Version(ctx context.Context) (out string, err error) {
err = c.client.Call(
ctx,
"ITD",
"Version",
nil,
&out,
)
return
res, err := c.client.Version(ctx, &rpc.Empty{})
return res.Value, err
}
func (c *Client) Address(ctx context.Context) (out string, err error) {
err = c.client.Call(
ctx,
"ITD",
"Address",
nil,
&out,
)
return
res, err := c.client.Address(ctx, &rpc.Empty{})
return res.Value, err
}

View File

@@ -1,16 +1,15 @@
package api
import "context"
import (
"context"
"go.arsenm.dev/itd/internal/rpc"
)
func (c *Client) Notify(ctx context.Context, title, body string) error {
return c.client.Call(
ctx,
"ITD",
"Notify",
NotifyData{
Title: title,
Body: body,
},
nil,
)
_, err := c.client.Notify(ctx, &rpc.NotifyRequest{
Title: title,
Body: body,
})
return err
}

View File

@@ -4,23 +4,48 @@ import (
"context"
"go.arsenm.dev/infinitime"
"go.arsenm.dev/itd/internal/rpc"
)
type ResourceOperation uint8
const (
ResourceOperationRemoveObsolete = infinitime.ResourceOperationRemoveObsolete
ResourceOperationUpload = infinitime.ResourceOperationUpload
)
type ResourceLoadProgress struct {
Operation ResourceOperation
Name string
Total int64
Sent int64
Err error
}
// LoadResources loads resources onto the watch from the given
// file path to the resources zip
func (c *Client) LoadResources(ctx context.Context, path string) (<-chan infinitime.ResourceLoadProgress, error) {
progCh := make(chan infinitime.ResourceLoadProgress)
func (c *FSClient) LoadResources(ctx context.Context, path string) (<-chan ResourceLoadProgress, error) {
progCh := make(chan ResourceLoadProgress, 2)
err := c.client.Call(
ctx,
"FS",
"LoadResources",
path,
progCh,
)
rc, err := c.client.LoadResources(ctx, &rpc.PathRequest{Path: path})
if err != nil {
return nil, err
}
go fsRecvToChannel[rpc.ResourceLoadProgress](rc, progCh, func(evt *rpc.ResourceLoadProgress, err error) ResourceLoadProgress {
return ResourceLoadProgress{
Operation: ResourceOperation(evt.Operation),
Name: evt.Name,
Sent: evt.Sent,
Total: evt.Total,
Err: err,
}
})
return progCh, nil
}
type StreamClient[T any] interface {
Recv() (*T, error)
Context() context.Context
}

View File

@@ -3,14 +3,11 @@ package api
import (
"context"
"time"
"go.arsenm.dev/itd/internal/rpc"
)
func (c *Client) SetTime(ctx context.Context, t time.Time) error {
return c.client.Call(
ctx,
"ITD",
"SetTime",
t,
nil,
)
_, err := c.client.SetTime(ctx, &rpc.SetTimeRequest{UnixNano: t.UnixNano()})
return err
}

View File

@@ -30,6 +30,7 @@ type NotifyData struct {
type FSTransferProgress struct {
Total uint32
Sent uint32
Err error
}
type FileInfo struct {

View File

@@ -1,13 +1,12 @@
package api
import "context"
import (
"context"
"go.arsenm.dev/itd/internal/rpc"
)
func (c *Client) WeatherUpdate(ctx context.Context) error {
return c.client.Call(
ctx,
"ITD",
"WeatherUpdate",
nil,
nil,
)
_, err := c.client.WeatherUpdate(ctx, &rpc.Empty{})
return err
}

View File

@@ -3,69 +3,133 @@ package api
import (
"context"
"go.arsenm.dev/infinitime"
"go.arsenm.dev/itd/internal/rpc"
)
func (c *Client) WatchHeartRate(ctx context.Context) (<-chan uint8, error) {
outCh := make(chan uint8, 2)
err := c.client.Call(
ctx,
"ITD",
"WatchHeartRate",
nil,
outCh,
)
wc, err := c.client.WatchHeartRate(ctx, &rpc.Empty{})
if err != nil {
return nil, err
}
go func() {
defer close(outCh)
var err error
var evt *rpc.IntResponse
for {
select {
case <-ctx.Done():
wc.Close()
return
default:
evt, err = wc.Recv()
if err != nil {
return
}
}
outCh <- uint8(evt.Value)
}
}()
return outCh, nil
}
func (c *Client) WatchBatteryLevel(ctx context.Context) (<-chan uint8, error) {
outCh := make(chan uint8, 2)
err := c.client.Call(
ctx,
"ITD",
"WatchBatteryLevel",
nil,
outCh,
)
wc, err := c.client.WatchBatteryLevel(ctx, &rpc.Empty{})
if err != nil {
return nil, err
}
go func() {
defer close(outCh)
var err error
var evt *rpc.IntResponse
for {
select {
case <-ctx.Done():
wc.Close()
return
default:
evt, err = wc.Recv()
if err != nil {
return
}
}
outCh <- uint8(evt.Value)
}
}()
return outCh, nil
}
func (c *Client) WatchStepCount(ctx context.Context) (<-chan uint32, error) {
outCh := make(chan uint32, 2)
err := c.client.Call(
ctx,
"ITD",
"WatchStepCount",
nil,
outCh,
)
wc, err := c.client.WatchStepCount(ctx, &rpc.Empty{})
if err != nil {
return nil, err
}
go func() {
defer close(outCh)
var err error
var evt *rpc.IntResponse
for {
select {
case <-ctx.Done():
wc.Close()
return
default:
evt, err = wc.Recv()
if err != nil {
return
}
}
outCh <- evt.Value
}
}()
return outCh, nil
}
func (c *Client) WatchMotion(ctx context.Context) (<-chan infinitime.MotionValues, error) {
outCh := make(chan infinitime.MotionValues, 2)
err := c.client.Call(
ctx,
"ITD",
"WatchMotion",
nil,
outCh,
)
func (c *Client) WatchMotion(ctx context.Context) (<-chan MotionValues, error) {
outCh := make(chan MotionValues, 2)
wc, err := c.client.WatchMotion(ctx, &rpc.Empty{})
if err != nil {
return nil, err
}
go func() {
defer close(outCh)
var err error
var evt *rpc.MotionResponse
for {
select {
case <-ctx.Done():
wc.Close()
return
default:
evt, err = wc.Recv()
if err != nil {
return
}
}
outCh <- MotionValues{int16(evt.X), int16(evt.Y), int16(evt.Z)}
}
}()
return outCh, nil
}