forked from Elara6331/infinitime
		
	Compare commits
	
		
			21 Commits
		
	
	
		
			f56be08106
			...
			ce90459491
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ce90459491 | |||
| 0c369dc5df | |||
| 
						 | 
					5fb5cf4b92 | ||
| 
						 | 
					76809726d5 | ||
| 72b558707e | |||
| 31f4c51a61 | |||
| 8e5bbafba8 | |||
| e6fb402c0c | |||
| 1f5301f5de | |||
| 0ad671d3f5 | |||
| 54fdd19bec | |||
| a01f1b9d92 | |||
| bb017b471e | |||
| 01970b2bb7 | |||
| b476853dc0 | |||
| 3e9957d419 | |||
| b5d345cdec | |||
| 0eead333b7 | |||
| e4c12d32a1 | |||
| 5af53d1dc6 | |||
| d199fba93c | 
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@@ -15,24 +15,24 @@ This library's import path is `go.arsenm.dev/infinitime`.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Dependencies
 | 
					### Dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This library requires `dbus`, `bluez`, and `pactl` to function. These allow the library to use bluetooth, control media, control volume, etc.
 | 
					This library requires `dbus`, and `bluez` to function. These allow the library to use bluetooth, control media, control volume, etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Arch
 | 
					#### Arch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
sudo pacman -S dbus bluez libpulse --needed
 | 
					sudo pacman -S dbus bluez --needed
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Debian/Ubuntu
 | 
					#### Debian/Ubuntu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
sudo apt install dbus bluez pulseaudio-utils
 | 
					sudo apt install dbus bluez
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Fedora
 | 
					#### Fedora
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
sudo dnf install dbus bluez pulseaudio-utils
 | 
					sudo dnf install dbus bluez
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
@@ -47,9 +47,10 @@ This library currently supports the following features:
 | 
				
			|||||||
- Battery level
 | 
					- Battery level
 | 
				
			||||||
- Music control
 | 
					- Music control
 | 
				
			||||||
- OTA firmware upgrades
 | 
					- OTA firmware upgrades
 | 
				
			||||||
 | 
					- Navigation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Mentions
 | 
					### Mentions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The DFU process used in this library was created with the help of [siglo](https://github.com/alexr4535/siglo)'s source code. Specifically, this file: [ble_dfu.py](https://github.com/alexr4535/siglo/blob/main/src/ble_dfu.py)
 | 
					The DFU process used in this library was created with the help of [siglo](https://github.com/alexr4535/siglo)'s source code. Specifically, this file: [ble_dfu.py](https://github.com/alexr4535/siglo/blob/main/src/ble_dfu.py)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										95
									
								
								blefs/all.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								blefs/all.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					package blefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (blefs *FS) RemoveAll(path string) error {
 | 
				
			||||||
 | 
						if path == "" {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if filepath.Clean(path) == "/" {
 | 
				
			||||||
 | 
							return ErrNoRemoveRoot
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fi, err := blefs.Stat(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if fi.IsDir() {
 | 
				
			||||||
 | 
							return blefs.removeAllChildren(path)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err = blefs.Remove(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var code int8
 | 
				
			||||||
 | 
							if err, ok := err.(FSError); ok {
 | 
				
			||||||
 | 
								code = err.Code
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil && code != -2 {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (blefs *FS) removeAllChildren(path string) error {
 | 
				
			||||||
 | 
						list, err := blefs.ReadDir(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, entry := range list {
 | 
				
			||||||
 | 
							name := entry.Name()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if name == "." || name == ".." {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							entryPath := filepath.Join(path, name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if entry.IsDir() {
 | 
				
			||||||
 | 
								err = blefs.removeAllChildren(entryPath)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = blefs.Remove(entryPath)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var code int8
 | 
				
			||||||
 | 
							if err, ok := err.(FSError); ok {
 | 
				
			||||||
 | 
								code = err.Code
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil && code != -2 {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (blefs *FS) MkdirAll(path string) error {
 | 
				
			||||||
 | 
						if path == "" || path == "/" {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						splitPath := strings.Split(path, "/")
 | 
				
			||||||
 | 
						for i := 1; i < len(splitPath); i++ {
 | 
				
			||||||
 | 
							curPath := strings.Join(splitPath[0:i+1], "/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err := blefs.Mkdir(curPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var code int8
 | 
				
			||||||
 | 
							if err, ok := err.(FSError); ok {
 | 
				
			||||||
 | 
								code = err.Code
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil && code != -17 {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,29 @@
 | 
				
			|||||||
package blefs
 | 
					package blefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io/fs"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stat does a ReadDir() and finds the current file in the output
 | 
				
			||||||
 | 
					func (blefs *FS) Stat(path string) (fs.FileInfo, error) {
 | 
				
			||||||
 | 
						// Get directory in filepath
 | 
				
			||||||
 | 
						dir := filepath.Dir(path)
 | 
				
			||||||
 | 
						// Read directory
 | 
				
			||||||
 | 
						dirEntries, err := blefs.ReadDir(dir)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, entry := range dirEntries {
 | 
				
			||||||
 | 
							// If file name is base name of path
 | 
				
			||||||
 | 
							if entry.Name() == filepath.Base(path) {
 | 
				
			||||||
 | 
								// Return file info
 | 
				
			||||||
 | 
								return entry.Info()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, ErrFileNotExists
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Rename moves or renames a file or directory
 | 
					// Rename moves or renames a file or directory
 | 
				
			||||||
func (blefs *FS) Rename(old, new string) error {
 | 
					func (blefs *FS) Rename(old, new string) error {
 | 
				
			||||||
	// Create move request
 | 
						// Create move request
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ var (
 | 
				
			|||||||
	ErrOffsetChanged = errors.New("offset has already been changed")
 | 
						ErrOffsetChanged = errors.New("offset has already been changed")
 | 
				
			||||||
	ErrReadOpen      = errors.New("only one file can be opened for reading at a time")
 | 
						ErrReadOpen      = errors.New("only one file can be opened for reading at a time")
 | 
				
			||||||
	ErrWriteOpen     = errors.New("only one file can be opened for writing at a time")
 | 
						ErrWriteOpen     = errors.New("only one file can be opened for writing at a time")
 | 
				
			||||||
 | 
						ErrNoRemoveRoot  = errors.New("refusing to remove root directory")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FSError represents an error returned by BLE FS
 | 
					// FSError represents an error returned by BLE FS
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ package blefs
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/fs"
 | 
						"io/fs"
 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -291,7 +290,7 @@ func (fl *File) Write(b []byte) (n int, err error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	close(fl.offsetCh)
 | 
						close(fl.offsetCh)
 | 
				
			||||||
	return int(fl.offset), nil
 | 
						return int(fl.amtTferd), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WriteString converts the string to []byte and calls Write()
 | 
					// WriteString converts the string to []byte and calls Write()
 | 
				
			||||||
@@ -335,23 +334,9 @@ func (fl *File) Close() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat does a RedDir() and finds the current file in the output
 | 
					// Stat does a ReadDir() and finds the current file in the output
 | 
				
			||||||
func (fl *File) Stat() (fs.FileInfo, error) {
 | 
					func (fl *File) Stat() (fs.FileInfo, error) {
 | 
				
			||||||
	// Get directory in filepath
 | 
						return fl.fs.Stat(fl.path)
 | 
				
			||||||
	dir := filepath.Dir(fl.path)
 | 
					 | 
				
			||||||
	// Read directory
 | 
					 | 
				
			||||||
	dirEntries, err := fl.fs.ReadDir(dir)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, entry := range dirEntries {
 | 
					 | 
				
			||||||
		// If file name is base name of path
 | 
					 | 
				
			||||||
		if entry.Name() == filepath.Base(fl.path) {
 | 
					 | 
				
			||||||
			// Return file info
 | 
					 | 
				
			||||||
			return entry.Info()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil, ErrFileNotExists
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// fileReadResponse represents a response for a read request
 | 
					// fileReadResponse represents a response for a read request
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -199,7 +199,13 @@ func decode(data []byte, vals ...interface{}) error {
 | 
				
			|||||||
// to send in a packet. Subtracting 20 ensures that the MTU
 | 
					// to send in a packet. Subtracting 20 ensures that the MTU
 | 
				
			||||||
// is never exceeded.
 | 
					// is never exceeded.
 | 
				
			||||||
func (blefs *FS) maxData() uint16 {
 | 
					func (blefs *FS) maxData() uint16 {
 | 
				
			||||||
	return blefs.transferChar.Properties.MTU - 20
 | 
						mtu := blefs.transferChar.Properties.MTU
 | 
				
			||||||
 | 
						// If MTU is zero, the current version of BlueZ likely
 | 
				
			||||||
 | 
						// doesn't support the MTU property, so assume 256.
 | 
				
			||||||
 | 
						if mtu == 0 {
 | 
				
			||||||
 | 
							mtu = 256
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mtu - 20
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// padding returns a slice of len amount of 0x00.
 | 
					// padding returns a slice of len amount of 0x00.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,4 +12,4 @@ func (iofs goFS) Open(path string) (fs.File, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (blefs *FS) GoFS() fs.FS {
 | 
					func (blefs *FS) GoFS() fs.FS {
 | 
				
			||||||
	return goFS{blefs}
 | 
						return goFS{blefs}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@@ -5,7 +5,7 @@ go 1.16
 | 
				
			|||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/fxamacker/cbor/v2 v2.4.0
 | 
						github.com/fxamacker/cbor/v2 v2.4.0
 | 
				
			||||||
	github.com/godbus/dbus/v5 v5.0.6
 | 
						github.com/godbus/dbus/v5 v5.0.6
 | 
				
			||||||
	github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a
 | 
						github.com/muka/go-bluetooth v0.0.0-20220819140550-1d8857e3b268
 | 
				
			||||||
	github.com/rs/zerolog v1.26.1
 | 
						github.com/rs/zerolog v1.26.1
 | 
				
			||||||
	golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
 | 
						golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@@ -15,8 +15,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJ
 | 
				
			|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 | 
					github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 | 
				
			||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
					github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
				
			||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
					github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
				
			||||||
github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a h1:fnzS9RRQW8B5AgNCxkN0vJ/AoX+Xfqk3sAYon3iVrzA=
 | 
					github.com/muka/go-bluetooth v0.0.0-20220819140550-1d8857e3b268 h1:kOnq7TfaAO2Vc/MHxPqFIXe00y1qBxJAvhctXdko6vo=
 | 
				
			||||||
github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
 | 
					github.com/muka/go-bluetooth v0.0.0-20220819140550-1d8857e3b268/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
 | 
				
			||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 | 
					github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 | 
				
			||||||
github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf/go.mod h1:+AwQL2mK3Pd3S+TUwg0tYQjid0q1txyNUJuuSmz8Kdk=
 | 
					github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf/go.mod h1:+AwQL2mK3Pd3S+TUwg0tYQjid0q1txyNUJuuSmz8Kdk=
 | 
				
			||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
					github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,18 +42,22 @@ const (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var charNames = map[string]string{
 | 
					var charNames = map[string]string{
 | 
				
			||||||
	NewAlertChar:    "New Alert",
 | 
						NewAlertChar:     "New Alert",
 | 
				
			||||||
	NotifEventChar:  "Notification Event",
 | 
						NotifEventChar:   "Notification Event",
 | 
				
			||||||
	StepCountChar:   "Step Count",
 | 
						StepCountChar:    "Step Count",
 | 
				
			||||||
	MotionValChar:   "Motion Values",
 | 
						MotionValChar:    "Motion Values",
 | 
				
			||||||
	FirmwareVerChar: "Firmware Version",
 | 
						FirmwareVerChar:  "Firmware Version",
 | 
				
			||||||
	CurrentTimeChar: "Current Time",
 | 
						CurrentTimeChar:  "Current Time",
 | 
				
			||||||
	LocalTimeChar:   "Local Time",
 | 
						LocalTimeChar:    "Local Time",
 | 
				
			||||||
	BatteryLvlChar:  "Battery Level",
 | 
						BatteryLvlChar:   "Battery Level",
 | 
				
			||||||
	HeartRateChar:   "Heart Rate",
 | 
						HeartRateChar:    "Heart Rate",
 | 
				
			||||||
	FSTransferChar:  "Filesystem Transfer",
 | 
						FSTransferChar:   "Filesystem Transfer",
 | 
				
			||||||
	FSVersionChar:   "Filesystem Version",
 | 
						FSVersionChar:    "Filesystem Version",
 | 
				
			||||||
	WeatherDataChar: "Weather Data",
 | 
						WeatherDataChar:  "Weather Data",
 | 
				
			||||||
 | 
						NavFlagsChar:     "Navigation Icon",
 | 
				
			||||||
 | 
						NavNarrativeChar: "Navigation Instruction",
 | 
				
			||||||
 | 
						NavManDistChar:   "Navigation Distance to next event",
 | 
				
			||||||
 | 
						NavProgressChar:  "Navigation Progress",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Device struct {
 | 
					type Device struct {
 | 
				
			||||||
@@ -70,9 +74,11 @@ type Device struct {
 | 
				
			|||||||
	fsVersionChar   *gatt.GattCharacteristic1
 | 
						fsVersionChar   *gatt.GattCharacteristic1
 | 
				
			||||||
	fsTransferChar  *gatt.GattCharacteristic1
 | 
						fsTransferChar  *gatt.GattCharacteristic1
 | 
				
			||||||
	weatherDataChar *gatt.GattCharacteristic1
 | 
						weatherDataChar *gatt.GattCharacteristic1
 | 
				
			||||||
 | 
						weatherdataChar *gatt.GattCharacteristic1
 | 
				
			||||||
	notifEventCh    chan uint8
 | 
						notifEventCh    chan uint8
 | 
				
			||||||
	notifEventDone  bool
 | 
						notifEventDone  bool
 | 
				
			||||||
	Music           MusicCtrl
 | 
						Music           MusicCtrl
 | 
				
			||||||
 | 
						Navigation      NavigationService
 | 
				
			||||||
	DFU             DFU
 | 
						DFU             DFU
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,6 +139,7 @@ func Connect(ctx context.Context, opts *Options) (*Device, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Create new device
 | 
						// Create new device
 | 
				
			||||||
	out := &Device{device: btDev}
 | 
						out := &Device{device: btDev}
 | 
				
			||||||
 | 
						out.Navigation = NavigationService{dev: out}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Resolve characteristics
 | 
						// Resolve characteristics
 | 
				
			||||||
	err = out.resolveChars()
 | 
						err = out.resolveChars()
 | 
				
			||||||
@@ -397,6 +404,14 @@ func (i *Device) resolveChars() error {
 | 
				
			|||||||
		charResolved := true
 | 
							charResolved := true
 | 
				
			||||||
		// Set correct characteristics
 | 
							// Set correct characteristics
 | 
				
			||||||
		switch char.Properties.UUID {
 | 
							switch char.Properties.UUID {
 | 
				
			||||||
 | 
							case NavFlagsChar:
 | 
				
			||||||
 | 
								i.Navigation.flagsChar = char
 | 
				
			||||||
 | 
							case NavNarrativeChar:
 | 
				
			||||||
 | 
								i.Navigation.narrativeChar = char
 | 
				
			||||||
 | 
							case NavManDistChar:
 | 
				
			||||||
 | 
								i.Navigation.mandistChar = char
 | 
				
			||||||
 | 
							case NavProgressChar:
 | 
				
			||||||
 | 
								i.Navigation.progressChar = char
 | 
				
			||||||
		case NewAlertChar:
 | 
							case NewAlertChar:
 | 
				
			||||||
			i.newAlertChar = char
 | 
								i.newAlertChar = char
 | 
				
			||||||
		case NotifEventChar:
 | 
							case NotifEventChar:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										151
									
								
								navigation.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								navigation.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					package infinitime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"github.com/muka/go-bluetooth/bluez/profile/gatt"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var ErrNavProgress = errors.New("progress needs to be between 0 and 100")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						NavFlagsChar     = "00010001-78fc-48fe-8e23-433b3a1942d0"
 | 
				
			||||||
 | 
						NavNarrativeChar = "00010002-78fc-48fe-8e23-433b3a1942d0"
 | 
				
			||||||
 | 
						NavManDistChar   = "00010003-78fc-48fe-8e23-433b3a1942d0"
 | 
				
			||||||
 | 
						NavProgressChar  = "00010004-78fc-48fe-8e23-433b3a1942d0"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type NavigationService struct {
 | 
				
			||||||
 | 
						dev           *Device
 | 
				
			||||||
 | 
						flagsChar     *gatt.GattCharacteristic1
 | 
				
			||||||
 | 
						narrativeChar *gatt.GattCharacteristic1
 | 
				
			||||||
 | 
						mandistChar   *gatt.GattCharacteristic1
 | 
				
			||||||
 | 
						progressChar  *gatt.GattCharacteristic1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type NavFlag string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						NavFlagArrive                  NavFlag = "arrive"
 | 
				
			||||||
 | 
						NavFlagArriveLeft              NavFlag = "arrive-left"
 | 
				
			||||||
 | 
						NavFlagArriveRight             NavFlag = "arrive-right"
 | 
				
			||||||
 | 
						NavFlagArriveStraight          NavFlag = "arrive-straight"
 | 
				
			||||||
 | 
						NavFlagClose                   NavFlag = "close"
 | 
				
			||||||
 | 
						NavFlagContinue                NavFlag = "continue"
 | 
				
			||||||
 | 
						NavFlagContinueLeft            NavFlag = "continue-left"
 | 
				
			||||||
 | 
						NavFlagContinueRight           NavFlag = "continue-right"
 | 
				
			||||||
 | 
						NavFlagContinueSlightLeft      NavFlag = "continue-slight-left"
 | 
				
			||||||
 | 
						NavFlagContinueSlightRight     NavFlag = "continue-slight-right"
 | 
				
			||||||
 | 
						NavFlagContinueStraight        NavFlag = "continue-straight"
 | 
				
			||||||
 | 
						NavFlagContinueUturn           NavFlag = "continue-uturn"
 | 
				
			||||||
 | 
						NavFlagDepart                  NavFlag = "depart"
 | 
				
			||||||
 | 
						NavFlagDepartLeft              NavFlag = "depart-left"
 | 
				
			||||||
 | 
						NavFlagDepartRight             NavFlag = "depart-right"
 | 
				
			||||||
 | 
						NavFlagDepartStraight          NavFlag = "depart-straight"
 | 
				
			||||||
 | 
						NavFlagEndOfRoadLeft           NavFlag = "end-of-road-left"
 | 
				
			||||||
 | 
						NavFlagEndOfRoadRight          NavFlag = "end-of-road-right"
 | 
				
			||||||
 | 
						NavFlagFerry                   NavFlag = "ferry"
 | 
				
			||||||
 | 
						NavFlagFlag                    NavFlag = "flag"
 | 
				
			||||||
 | 
						NavFlagFork                    NavFlag = "fork"
 | 
				
			||||||
 | 
						NavFlagForkLeft                NavFlag = "fork-left"
 | 
				
			||||||
 | 
						NavFlagForkRight               NavFlag = "fork-right"
 | 
				
			||||||
 | 
						NavFlagForkSlightLeft          NavFlag = "fork-slight-left"
 | 
				
			||||||
 | 
						NavFlagForkSlightRight         NavFlag = "fork-slight-right"
 | 
				
			||||||
 | 
						NavFlagForkStraight            NavFlag = "fork-straight"
 | 
				
			||||||
 | 
						NavFlagInvalid                 NavFlag = "invalid"
 | 
				
			||||||
 | 
						NavFlagInvalidLeft             NavFlag = "invalid-left"
 | 
				
			||||||
 | 
						NavFlagInvalidRight            NavFlag = "invalid-right"
 | 
				
			||||||
 | 
						NavFlagInvalidSlightLeft       NavFlag = "invalid-slight-left"
 | 
				
			||||||
 | 
						NavFlagInvalidSlightRight      NavFlag = "invalid-slight-right"
 | 
				
			||||||
 | 
						NavFlagInvalidStraight         NavFlag = "invalid-straight"
 | 
				
			||||||
 | 
						NavFlagInvalidUturn            NavFlag = "invalid-uturn"
 | 
				
			||||||
 | 
						NavFlagMergeLeft               NavFlag = "merge-left"
 | 
				
			||||||
 | 
						NavFlagMergeRight              NavFlag = "merge-right"
 | 
				
			||||||
 | 
						NavFlagMergeSlightLeft         NavFlag = "merge-slight-left"
 | 
				
			||||||
 | 
						NavFlagMergeSlightRight        NavFlag = "merge-slight-right"
 | 
				
			||||||
 | 
						NavFlagMergeStraight           NavFlag = "merge-straight"
 | 
				
			||||||
 | 
						NavFlagNewNameLeft             NavFlag = "new-name-left"
 | 
				
			||||||
 | 
						NavFlagNewNameRight            NavFlag = "new-name-right"
 | 
				
			||||||
 | 
						NavFlagNewNameSharpLeft        NavFlag = "new-name-sharp-left"
 | 
				
			||||||
 | 
						NavFlagNewNameSharpRight       NavFlag = "new-name-sharp-right"
 | 
				
			||||||
 | 
						NavFlagNewNameSlightLeft       NavFlag = "new-name-slight-left"
 | 
				
			||||||
 | 
						NavFlagNewNameSlightRight      NavFlag = "new-name-slight-right"
 | 
				
			||||||
 | 
						NavFlagNewNameStraight         NavFlag = "new-name-straight"
 | 
				
			||||||
 | 
						NavFlagNotificationLeft        NavFlag = "notification-left"
 | 
				
			||||||
 | 
						NavFlagNotificationRight       NavFlag = "notification-right"
 | 
				
			||||||
 | 
						NavFlagNotificationSharpLeft   NavFlag = "notification-sharp-left"
 | 
				
			||||||
 | 
						NavFlagNotificationSharpRight  NavFlag = "notification-sharp-right"
 | 
				
			||||||
 | 
						NavFlagNotificationSlightLeft  NavFlag = "notification-slight-left"
 | 
				
			||||||
 | 
						NavFlagNotificationSlightRight NavFlag = "notification-slight-right"
 | 
				
			||||||
 | 
						NavFlagNotificationStraight    NavFlag = "notification-straight"
 | 
				
			||||||
 | 
						NavFlagOffRampLeft             NavFlag = "off-ramp-left"
 | 
				
			||||||
 | 
						NavFlagOffRampRight            NavFlag = "off-ramp-right"
 | 
				
			||||||
 | 
						NavFlagOffRampSharpLeft        NavFlag = "off-ramp-sharp-left"
 | 
				
			||||||
 | 
						NavFlagOffRampSharpRight       NavFlag = "off-ramp-sharp-right"
 | 
				
			||||||
 | 
						NavFlagOffRampSlightLeft       NavFlag = "off-ramp-slight-left"
 | 
				
			||||||
 | 
						NavFlagOffRampSlightRight      NavFlag = "off-ramp-slight-right"
 | 
				
			||||||
 | 
						NavFlagOffRampStraight         NavFlag = "off-ramp-straight"
 | 
				
			||||||
 | 
						NavFlagOnRampLeft              NavFlag = "on-ramp-left"
 | 
				
			||||||
 | 
						NavFlagOnRampRight             NavFlag = "on-ramp-right"
 | 
				
			||||||
 | 
						NavFlagOnRampSharpLeft         NavFlag = "on-ramp-sharp-left"
 | 
				
			||||||
 | 
						NavFlagOnRampSharpRight        NavFlag = "on-ramp-sharp-right"
 | 
				
			||||||
 | 
						NavFlagOnRampSlightLeft        NavFlag = "on-ramp-slight-left"
 | 
				
			||||||
 | 
						NavFlagOnRampSlightRight       NavFlag = "on-ramp-slight-right"
 | 
				
			||||||
 | 
						NavFlagOnRampStraight          NavFlag = "on-ramp-straight"
 | 
				
			||||||
 | 
						NavFlagRotary                  NavFlag = "rotary"
 | 
				
			||||||
 | 
						NavFlagRotaryLeft              NavFlag = "rotary-left"
 | 
				
			||||||
 | 
						NavFlagRotaryRight             NavFlag = "rotary-right"
 | 
				
			||||||
 | 
						NavFlagRotarySharpLeft         NavFlag = "rotary-sharp-left"
 | 
				
			||||||
 | 
						NavFlagRotarySharpRight        NavFlag = "rotary-sharp-right"
 | 
				
			||||||
 | 
						NavFlagRotarySlightLeft        NavFlag = "rotary-slight-left"
 | 
				
			||||||
 | 
						NavFlagRotarySlightRight       NavFlag = "rotary-slight-right"
 | 
				
			||||||
 | 
						NavFlagRotaryStraight          NavFlag = "rotary-straight"
 | 
				
			||||||
 | 
						NavFlagRoundabout              NavFlag = "roundabout"
 | 
				
			||||||
 | 
						NavFlagRoundaboutLeft          NavFlag = "roundabout-left"
 | 
				
			||||||
 | 
						NavFlagRoundaboutRight         NavFlag = "roundabout-right"
 | 
				
			||||||
 | 
						NavFlagRoundaboutSharpLeft     NavFlag = "roundabout-sharp-left"
 | 
				
			||||||
 | 
						NavFlagRoundaboutSharpRight    NavFlag = "roundabout-sharp-right"
 | 
				
			||||||
 | 
						NavFlagRoundaboutSlightLeft    NavFlag = "roundabout-slight-left"
 | 
				
			||||||
 | 
						NavFlagRoundaboutSlightRight   NavFlag = "roundabout-slight-right"
 | 
				
			||||||
 | 
						NavFlagRoundaboutStraight      NavFlag = "roundabout-straight"
 | 
				
			||||||
 | 
						NavFlagTurnLeft                NavFlag = "turn-left"
 | 
				
			||||||
 | 
						NavFlagTurnRight               NavFlag = "turn-right"
 | 
				
			||||||
 | 
						NavFlagTurnSharpLeft           NavFlag = "turn-sharp-left"
 | 
				
			||||||
 | 
						NavFlagTurnSharpRight          NavFlag = "turn-sharp-right"
 | 
				
			||||||
 | 
						NavFlagTurnSlightLeft          NavFlag = "turn-slight-left"
 | 
				
			||||||
 | 
						NavFlagTurnSlightRight         NavFlag = "turn-slight-right"
 | 
				
			||||||
 | 
						NavFlagTurnStright             NavFlag = "turn-stright"
 | 
				
			||||||
 | 
						NavFlagUpdown                  NavFlag = "updown"
 | 
				
			||||||
 | 
						NavFlagUturn                   NavFlag = "uturn"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (n *NavigationService) SetFlag(flag NavFlag) error {
 | 
				
			||||||
 | 
						log.Debug().Str("func", "SetFlag").Msg("Sending flag")
 | 
				
			||||||
 | 
						if err := n.dev.checkStatus(n.flagsChar, NavFlagsChar); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n.flagsChar.WriteValue([]byte(flag), nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (n *NavigationService) SetNarrative(narrative string) error {
 | 
				
			||||||
 | 
						log.Debug().Str("func", "SetNarrative").Msg("Sending narrative")
 | 
				
			||||||
 | 
						if err := n.dev.checkStatus(n.narrativeChar, NavNarrativeChar); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n.narrativeChar.WriteValue([]byte(narrative), nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (n *NavigationService) SetManDist(manDist string) error {
 | 
				
			||||||
 | 
						log.Debug().Str("func", "SetNarrative").Msg("Sending maneuver distance")
 | 
				
			||||||
 | 
						if err := n.dev.checkStatus(n.mandistChar, NavManDistChar); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n.mandistChar.WriteValue([]byte(manDist), nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (n *NavigationService) SetProgress(progress uint8) error {
 | 
				
			||||||
 | 
						log.Debug().Str("func", "SetNarrative").Msg("Sending progress")
 | 
				
			||||||
 | 
						if err := n.dev.checkStatus(n.progressChar, NavProgressChar); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n.progressChar.WriteValue([]byte{progress}, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
package player
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os/exec"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// VolUp uses pactl to increase the volume of the default sink
 | 
					 | 
				
			||||||
func VolUp(percent uint) error {
 | 
					 | 
				
			||||||
	return exec.Command("pactl", "set-sink-volume", "@DEFAULT_SINK@", fmt.Sprintf("+%d%%", percent)).Run()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// VolDown uses pactl to decrease the volume of the default sink
 | 
					 | 
				
			||||||
func VolDown(percent uint) error {
 | 
					 | 
				
			||||||
	return exec.Command("pactl", "set-sink-volume", "@DEFAULT_SINK@", fmt.Sprintf("-%d%%", percent)).Run()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -107,6 +107,46 @@ func Prev() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func VolUp(percent uint) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						player, err := getPlayerObj()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if player != nil {
 | 
				
			||||||
 | 
					                currentVal, err := player.GetProperty("org.mpris.MediaPlayer2.Player.Volume")
 | 
				
			||||||
 | 
					                if err != nil {
 | 
				
			||||||
 | 
					                    return err
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                newVal := currentVal.Value().(float64) + (float64(percent) / 100)
 | 
				
			||||||
 | 
					                err = player.SetProperty("org.mpris.MediaPlayer2.Player.Volume", newVal)
 | 
				
			||||||
 | 
					                if err != nil {
 | 
				
			||||||
 | 
					                    return err
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func VolDown(percent uint) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						player, err := getPlayerObj()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if player != nil {
 | 
				
			||||||
 | 
					                currentVal, err := player.GetProperty("org.mpris.MediaPlayer2.Player.Volume")
 | 
				
			||||||
 | 
					                if err != nil {
 | 
				
			||||||
 | 
					                    return err
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                newVal := currentVal.Value().(float64) - (float64(percent) / 100)
 | 
				
			||||||
 | 
					                err = player.SetProperty("org.mpris.MediaPlayer2.Player.Volume", newVal)
 | 
				
			||||||
 | 
					                if err != nil {
 | 
				
			||||||
 | 
					                    return err
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ChangeType int
 | 
					type ChangeType int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										209
									
								
								resources.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								resources.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					package infinitime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"archive/zip"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"go.arsenm.dev/infinitime/blefs"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ResourceOperation represents an operation performed during
 | 
				
			||||||
 | 
					// resource loading
 | 
				
			||||||
 | 
					type ResourceOperation uint8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// ResourceOperationUpload represents the upload phase
 | 
				
			||||||
 | 
						// of resource loading
 | 
				
			||||||
 | 
						ResourceOperationUpload = iota
 | 
				
			||||||
 | 
						// ResourceOperationRemoveObsolete represents the obsolete
 | 
				
			||||||
 | 
						// file removal phase of resource loading
 | 
				
			||||||
 | 
						ResourceOperationRemoveObsolete
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ResourceManifest is the structure of the resource manifest file
 | 
				
			||||||
 | 
					type ResourceManifest struct {
 | 
				
			||||||
 | 
						Resources []Resource         `json:"resources"`
 | 
				
			||||||
 | 
						Obsolete  []ObsoleteResource `json:"obsolete_files"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resource represents a resource entry in the manifest
 | 
				
			||||||
 | 
					type Resource struct {
 | 
				
			||||||
 | 
						Name string `json:"filename"`
 | 
				
			||||||
 | 
						Path string `json:"path"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ObsoleteResource represents an obsolete file entry in the manifest
 | 
				
			||||||
 | 
					type ObsoleteResource struct {
 | 
				
			||||||
 | 
						Path  string `json:"path"`
 | 
				
			||||||
 | 
						Since string `json:"since"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ResourceLoadProgress contains information on the progress of
 | 
				
			||||||
 | 
					// a resource load
 | 
				
			||||||
 | 
					type ResourceLoadProgress struct {
 | 
				
			||||||
 | 
						Operation ResourceOperation
 | 
				
			||||||
 | 
						Name      string
 | 
				
			||||||
 | 
						Total     int64
 | 
				
			||||||
 | 
						Sent      int64
 | 
				
			||||||
 | 
						Err       error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LoadResources accepts a resources zip file and a BLE FS.
 | 
				
			||||||
 | 
					// It loads the resources from the zip onto the FS.
 | 
				
			||||||
 | 
					func LoadResources(file *os.File, fs *blefs.FS) (<-chan ResourceLoadProgress, error) {
 | 
				
			||||||
 | 
						out := make(chan ResourceLoadProgress, 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fi, err := file.Stat()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r, err := zip.NewReader(file, fi.Size())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m, err := r.Open("resources.json")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer m.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var manifest ResourceManifest
 | 
				
			||||||
 | 
						err = json.NewDecoder(m).Decode(&manifest)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Debug().Msg("Decoded manifest file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer close(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, file := range manifest.Obsolete {
 | 
				
			||||||
 | 
								name := filepath.Base(file.Path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log.Debug().Str("file", file.Path).Msg("Removing file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err := fs.RemoveAll(file.Path)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
										Name:      name,
 | 
				
			||||||
 | 
										Operation: ResourceOperationRemoveObsolete,
 | 
				
			||||||
 | 
										Err:       err,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log.Debug().Str("file", file.Path).Msg("Removed file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
									Name:      name,
 | 
				
			||||||
 | 
									Operation: ResourceOperationRemoveObsolete,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, file := range manifest.Resources {
 | 
				
			||||||
 | 
								src, err := r.Open(file.Name)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
										Name:      file.Name,
 | 
				
			||||||
 | 
										Operation: ResourceOperationUpload,
 | 
				
			||||||
 | 
										Err:       err,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								srcFi, err := src.Stat()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
										Name:      file.Name,
 | 
				
			||||||
 | 
										Operation: ResourceOperationUpload,
 | 
				
			||||||
 | 
										Total:     srcFi.Size(),
 | 
				
			||||||
 | 
										Err:       err,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									src.Close()
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log.Debug().Str("file", file.Path).Msg("Making directories")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = fs.MkdirAll(filepath.Dir(file.Path))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Debug().Err(err).Msg("Error making directories")
 | 
				
			||||||
 | 
									out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
										Name:      file.Name,
 | 
				
			||||||
 | 
										Operation: ResourceOperationUpload,
 | 
				
			||||||
 | 
										Total:     srcFi.Size(),
 | 
				
			||||||
 | 
										Err:       err,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									src.Close()
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log.Debug().
 | 
				
			||||||
 | 
									Str("file", file.Path).
 | 
				
			||||||
 | 
									Int64("size", srcFi.Size()).
 | 
				
			||||||
 | 
									Msg("Creating file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dst, err := fs.Create(file.Path, uint32(srcFi.Size()))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Debug().Err(err).Msg("Error creating file")
 | 
				
			||||||
 | 
									out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
										Name:      file.Name,
 | 
				
			||||||
 | 
										Operation: ResourceOperationUpload,
 | 
				
			||||||
 | 
										Total:     srcFi.Size(),
 | 
				
			||||||
 | 
										Err:       err,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									src.Close()
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								progCh := dst.Progress()
 | 
				
			||||||
 | 
								go func() {
 | 
				
			||||||
 | 
									for sent := range progCh {
 | 
				
			||||||
 | 
										log.Debug().
 | 
				
			||||||
 | 
											Int64("total", srcFi.Size()).
 | 
				
			||||||
 | 
											Uint32("sent", sent).
 | 
				
			||||||
 | 
											Msg("Progress event sent")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
											Name:      file.Name,
 | 
				
			||||||
 | 
											Operation: ResourceOperationUpload,
 | 
				
			||||||
 | 
											Total:     srcFi.Size(),
 | 
				
			||||||
 | 
											Sent:      int64(sent),
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if sent == uint32(srcFi.Size()) {
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								n, err := io.Copy(dst, src)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Debug().Err(err).Msg("Error writing to file")
 | 
				
			||||||
 | 
									out <- ResourceLoadProgress{
 | 
				
			||||||
 | 
										Name:      file.Name,
 | 
				
			||||||
 | 
										Operation: ResourceOperationUpload,
 | 
				
			||||||
 | 
										Total:     srcFi.Size(),
 | 
				
			||||||
 | 
										Sent:      n,
 | 
				
			||||||
 | 
										Err:       err,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									src.Close()
 | 
				
			||||||
 | 
									dst.Close()
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								src.Close()
 | 
				
			||||||
 | 
								dst.Close()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -82,8 +82,12 @@ type TimelineHeader struct {
 | 
				
			|||||||
// NewHeader creates and populates a new timeline header
 | 
					// NewHeader creates and populates a new timeline header
 | 
				
			||||||
// and returns it
 | 
					// and returns it
 | 
				
			||||||
func NewHeader(evtType EventType, expires time.Duration) TimelineHeader {
 | 
					func NewHeader(evtType EventType, expires time.Duration) TimelineHeader {
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
						_, offset := now.Zone()
 | 
				
			||||||
 | 
						now = now.Add(time.Duration(offset) * time.Second)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return TimelineHeader{
 | 
						return TimelineHeader{
 | 
				
			||||||
		Timestamp: uint64(time.Now().Unix()),
 | 
							Timestamp: uint64(now.Unix()),
 | 
				
			||||||
		Expires:   uint32(expires.Seconds()),
 | 
							Expires:   uint32(expires.Seconds()),
 | 
				
			||||||
		EventType: evtType,
 | 
							EventType: evtType,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user