Compare commits
301 Commits
v1.1.0
..
b28c386c4e
| Author | SHA1 | Date | |
|---|---|---|---|
| b28c386c4e | |||
| 4c59561a99 | |||
| 955e1323ce | |||
| 3b9690103b | |||
| b5328ece92 | |||
| 2396623c73 | |||
| a54ca7afdf | |||
| 673383f795 | |||
| cc6fc3e1dc | |||
| c05d4fe951 | |||
| 87c78566c1 | |||
| 8dd8f3d012 | |||
| bf13b96660 | |||
| 2440cb954c | |||
| 08c8d7e8de | |||
| 1799c072ff | |||
| c5ca30cd0a | |||
| c046c67dbd | |||
| e2bd52b5a0 | |||
| 2c899b4660 | |||
| 083da5b3f0 | |||
| 4333b83ca2 | |||
| d2dbcd8713 | |||
| 8f57a0be8d | |||
| 4389609500 | |||
| 5fa49adee4 | |||
| fe43a608d0 | |||
| c142d97ee8 | |||
| 9b9ab67217 | |||
| a27cc090dd | |||
| ffe9d43cf8 | |||
| ec39e649c5 | |||
| b181785006 | |||
| 4d3bc1ed40 | |||
| 68f6d20719 | |||
| bfb21ea6a9 | |||
| 83726c9427 | |||
| afaa5990c4 | |||
| 1a5970a041 | |||
| 5d71ae245c | |||
| 9d28a2a1f8 | |||
| 82ed906857 | |||
| 9d3fdeb78f | |||
| 85b2145aa5 | |||
| 74afbc7c20 | |||
| 2a8de96773 | |||
| a8dc017a48 | |||
| d04af07dbe | |||
| a5d70e373c | |||
| e4f8d0b551 | |||
| 4a18622d37 | |||
| 5008cdd4f4 | |||
| eb745def04 | |||
| 0e0bfdc1f4 | |||
| b820d6a674 | |||
| 3a8888c003 | |||
| 7010dc6b17 | |||
| 4cdd47311f | |||
| 520c23b75b | |||
| 81840d411d | |||
| 0aa89e18b6 | |||
| c3a61b5893 | |||
| 52686fbad0 | |||
| 547c79f874 | |||
| de3ce406e7 | |||
| 27cd275ddb | |||
| 1ad99fafc4 | |||
| 0cf36f220d | |||
| 1cbc2f86fa | |||
| 87fdb7a30a | |||
| 7e4720ed6a | |||
| d7bd94e164 | |||
| f9ea55910e | |||
| b757af7fed | |||
| 5f5c67f7cc | |||
| 248beffa2f | |||
| 73a679d10b | |||
| d475c6905e | |||
| 0e6e3848d7 | |||
| ceff536e92 | |||
| 5e24e8aafa | |||
| f4da64a8dd | |||
| 76320aa813 | |||
| b64e6d27d4 | |||
| f215e4fd90 | |||
| 1e8c9484d2 | |||
| b6c47b7383 | |||
| e97c1fef48 | |||
| 3f2bccc40c | |||
| d80230b9d4 | |||
| c81ac19dda | |||
| 4a397d4c1e | |||
| c5fb3e1a33 | |||
| 908bd7d5f3 | |||
| c97fcaeefb | |||
| 992eb2e085 | |||
| f33b3d2b56 | |||
| 03f3968fe1 | |||
| dea92c6404 | |||
| 006f245c10 | |||
| d232340edd | |||
| c6458720e9 | |||
| 1e072a3540 | |||
| f639fef992 | |||
| 2d0db1dcf1 | |||
| 4efa4380c4 | |||
| fca64afbf3 | |||
| cf24c5ace8 | |||
| a25b2e3e62 | |||
| 2d0b64d92f | |||
| 5efafe9be7 | |||
| 271510d528 | |||
| 4d72a063b2 | |||
| 643245f16c | |||
| 6f87980d4b | |||
| 851f1975d6 | |||
| 5e66fe82ac | |||
| 645541e079 | |||
| 1012be6e5b | |||
| 5973290d6c | |||
| 19bacf29b2 | |||
| a78650e526 | |||
| 71e9caf0bc | |||
| 1f5a6365bc | |||
| 958f2af516 | |||
| 60f1eedc9a | |||
| c05147518d | |||
| 422f844943 | |||
| 66618e5bf0 | |||
| 0c2e57ced0 | |||
| 6d9f6fc6e6 | |||
| 0cbd6a48ae | |||
| b614138f6b | |||
| 3a0491f069 | |||
| 093a5632c7 | |||
| 91662e6f38 | |||
| 931966bf1e | |||
| ed01700e26 | |||
| e9269e8eb8 | |||
| 52b85ab361 | |||
| bc45943bdc | |||
| 6933f45683 | |||
| 0f22d67395 | |||
| 6da03181a9 | |||
| 44a25625da | |||
| 14a38351e4 | |||
| 4c27f424b2 | |||
| 86fbef2e8a | |||
| 7b8658e072 | |||
| 73c46cfa66 | |||
| 1e0f1c5b76 | |||
| 78b5ca1de8 | |||
| b0c4574481 | |||
| 01975f207c | |||
| 428e7967c1 | |||
| 56dbf0540e | |||
| 240e7a5ee4 | |||
| 625805fe96 | |||
| 4b6f7d408e | |||
| 9034ef7c6b | |||
| 9939f724c4 | |||
| 8dce33f7b1 | |||
| 563009c44d | |||
| d4a8a9f8c9 | |||
| 7fd9af3288 | |||
| 4508559bfd | |||
| 0cdf8a4bed | |||
| 2af6c1887f | |||
| 3a3f95acdf | |||
| d318c584da | |||
| c8c617c10a | |||
| 365414f951 | |||
| 9b04d06560 | |||
| 23e9195e70 | |||
| cd68fbd7f3 | |||
| 205a041758 | |||
| 62597f70ee | |||
| 32bb141244 | |||
| f28c68438a | |||
| aa90e9eb26 | |||
| 553709ce8d | |||
| 2ded0d36b1 | |||
| a885eacc70 | |||
| 9e63401db3 | |||
| 2f14e70721 | |||
| 614d14e399 | |||
| c08ddfd810 | |||
| 4bdb82b1bc | |||
| b4d302caf6 | |||
| 4b2694ee0d | |||
| 4c36144b0b | |||
| e88dea40fb | |||
| 23b9cfe8a3 | |||
| 518fe74e96 | |||
| 27aabdceba | |||
| c019d7523b | |||
| 03c3c6b22f | |||
| 69d1027f01 | |||
| 873df67d1f | |||
| a9ef386883 | |||
| 24cfda82d7 | |||
| 655af5c446 | |||
| b363a20a9d | |||
| f5d326124d | |||
| cb8fb2c0bc | |||
| 38119435f1 | |||
| 034a69c12f | |||
| 70006a3d7b | |||
| 8aada58d64 | |||
| 5d231207cd | |||
| 584d9426e6 | |||
| 7a772a5458 | |||
| 079c733b60 | |||
| e24a8e9088 | |||
| 0b5d777077 | |||
| 75327286ef | |||
| 099b0cd849 | |||
| c9c00e0072 | |||
| b2ffb2062a | |||
| 2e8c825fff | |||
| 7b870950d1 | |||
| 3a877c41a4 | |||
| 04fb390bee | |||
| 50b17d3266 | |||
| 763d408405 | |||
| fbb7cd9bc1 | |||
| f1b7f70313 | |||
| 552f19676b | |||
| 9d58ea0ae7 | |||
| 76875db7ea | |||
| be5bdc625b | |||
| 0d0db949af | |||
| 0d164aef3d | |||
| 28610d9ebb | |||
| dff34b484d | |||
| 2ea9f99db6 | |||
| 44dc5f8e47 | |||
| 4d35912466 | |||
| ef29b9bee4 | |||
| e198b769f9 | |||
| ef4bad94b5 | |||
| 8cf2b47733 | |||
| f20fdcb161 | |||
| eeba9b2964 | |||
| d7057e3f9c | |||
| 80a5867d6b | |||
| f001dd6079 | |||
| b87586ef15 | |||
| 295892c8a8 | |||
| 1492db7566 | |||
| e7de7bd7bb | |||
| 7b849a3fc7 | |||
| 21d4964207 | |||
| 604ea57c5f | |||
| b15cbb6349 | |||
| 843e369bab | |||
| eec7a3db48 | |||
| c23201e18c | |||
| 4bc6eb9d41 | |||
| 2a59e74a2c | |||
| df743cca96 | |||
| 01bf493c77 | |||
| b6e9ad6160 | |||
| c56c0ae198 | |||
| 6b94030b83 | |||
| 2bbd722ecd | |||
| 73f16fcfef | |||
| 9df6531023 | |||
| 1db2ca3395 | |||
| 419b2f5a79 | |||
| 44607ba9e2 | |||
| f4d2f4e6eb | |||
| 0721b7f9d4 | |||
| b7bd385c43 | |||
| cbcefb149e | |||
| cb8d207249 | |||
| 7786ea1d58 | |||
| 6e16aa7a7a | |||
| 91f7132d5e | |||
| b186f77bea | |||
| adb297c6dd | |||
| b4992cb393 | |||
| a5490b8364 | |||
| 44d1f5552b | |||
| 5e34f656b3 | |||
| 560d19860e | |||
| ea1a7fa9f4 | |||
| 81fe634ed8 | |||
| 281e1dcbac | |||
| 4847eee540 | |||
| 19caa3ee83 | |||
| e523a024ec | |||
| 4a3dff646c | |||
| 986d2064a7 | |||
| 95cf5bfe6b | |||
| 0d70dd9b11 | |||
| 3cfcdb7a01 | |||
| bdf5a099d4 | |||
| 4a195f8311 | |||
| 60d2053894 | |||
| 407a6cb3d7 |
+7
-7
@@ -53,8 +53,8 @@ nfpms:
|
||||
{{- else }}{{.Arch}}
|
||||
{{- end }}
|
||||
description: "Companion daemon for the InfiniTime firmware on the PineTime smartwatch"
|
||||
homepage: 'https://gitea.elara.ws/Elara6331/itd'
|
||||
maintainer: 'Elara Musayelyan <elara@elara.ws>'
|
||||
homepage: 'https://gitea.arsenm.dev/Arsen6331/itd'
|
||||
maintainer: 'Arsen Musyaelyan <arsen@arsenm.dev>'
|
||||
license: GPLv3
|
||||
formats:
|
||||
- apk
|
||||
@@ -74,10 +74,10 @@ nfpms:
|
||||
mode: 0755
|
||||
aurs:
|
||||
- name: itd-bin
|
||||
homepage: 'https://gitea.elara.ws/Elara6331/itd'
|
||||
homepage: 'https://gitea.arsenm.dev/Arsen6331/itd'
|
||||
description: "Companion daemon for the InfiniTime firmware on the PineTime smartwatch"
|
||||
maintainers:
|
||||
- 'Elara Musayelyan <elara@elara.ws>'
|
||||
- 'Arsen Musyaelyan <arsen@arsenm.dev>'
|
||||
license: GPLv3
|
||||
private_key: '{{ .Env.AUR_KEY }}'
|
||||
git_url: 'ssh://aur@aur.archlinux.org/itd-bin.git'
|
||||
@@ -105,11 +105,11 @@ aurs:
|
||||
install -Dm644 "./LICENSE" "${pkgdir}/usr/share/licenses/itd/LICENSE"
|
||||
release:
|
||||
gitea:
|
||||
owner: Elara6331
|
||||
owner: Arsen6331
|
||||
name: itd
|
||||
gitea_urls:
|
||||
api: 'https://gitea.elara.ws/api/v1/'
|
||||
download: 'https://gitea.elara.ws'
|
||||
api: 'https://gitea.arsenm.dev/api/v1/'
|
||||
download: 'https://gitea.arsenm.dev'
|
||||
skip_tls_verify: false
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# ITD
|
||||
## InfiniTime Daemon
|
||||
|
||||
`itd` is a daemon that uses my infinitime [library](https://go.elara.ws/infinitime) to interact with the [PineTime](https://www.pine64.org/pinetime/) running [InfiniTime](https://infinitime.io).
|
||||
`itd` is a daemon that uses my infinitime [library](https://go.arsenm.dev/infinitime) to interact with the [PineTime](https://www.pine64.org/pinetime/) running [InfiniTime](https://infinitime.io).
|
||||
|
||||
[](https://ci.elara.ws/Elara6331/itd)
|
||||
[](https://ci.arsenm.dev/Arsen6331/itd)
|
||||
[](https://aur.archlinux.org/packages/itd-git/)
|
||||
[](https://aur.archlinux.org/packages/itd-bin/)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
- Weather
|
||||
- BLE Filesystem
|
||||
- Navigation (PureMaps)
|
||||
- FUSE Filesystem
|
||||
|
||||
---
|
||||
|
||||
@@ -198,4 +197,4 @@ Most of the time, the daemon does not need to be restarted for config changes to
|
||||
|
||||
Location data from OpenStreetMap Nominatim, © [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors
|
||||
|
||||
Weather data from the [Norwegian Meteorological Institute](https://www.met.no/en)
|
||||
Weather data from the [Norwegian Meteorological Institute](https://www.met.no/en)
|
||||
+2
-2
@@ -4,8 +4,8 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"go.elara.ws/drpc/muxconn"
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/drpc/muxconn"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
"storj.io/drpc"
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
type DFUProgress struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
type FSClient struct {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
func (c *Client) HeartRate(ctx context.Context) (uint8, error) {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
func (c *Client) Notify(ctx context.Context, title, body string) error {
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ package api
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
type ResourceOperation uint8
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
func (c *Client) SetTime(ctx context.Context, t time.Time) error {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
func (c *Client) WeatherUpdate(ctx context.Context) error {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
)
|
||||
|
||||
func (c *Client) WatchHeartRate(ctx context.Context) (<-chan uint8, error) {
|
||||
|
||||
@@ -5,12 +5,12 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/internal/utils"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/itd/internal/utils"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
func initCallNotifs(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func initCallNotifs(ctx context.Context, dev *infinitime.Device) error {
|
||||
// Connect to system bus. This connection is for method calls.
|
||||
conn, err := utils.NewSystemBusConn(ctx)
|
||||
if err != nil {
|
||||
@@ -53,66 +53,49 @@ func initCallNotifs(ctx context.Context, wg WaitGroup, dev *infinitime.Device) e
|
||||
var respHandlerOnce sync.Once
|
||||
var callObj dbus.BusObject
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("callNotifs")
|
||||
for {
|
||||
select {
|
||||
case event := <-callCh:
|
||||
// Get path to call object
|
||||
callPath := event.Body[0].(dbus.ObjectPath)
|
||||
// Get call object
|
||||
callObj = conn.Object("org.freedesktop.ModemManager1", callPath)
|
||||
// For every message received
|
||||
for event := range callCh {
|
||||
// Get path to call object
|
||||
callPath := event.Body[0].(dbus.ObjectPath)
|
||||
// Get call object
|
||||
callObj = conn.Object("org.freedesktop.ModemManager1", callPath)
|
||||
|
||||
// Get phone number from call object using method call connection
|
||||
phoneNum, err := getPhoneNum(conn, callObj)
|
||||
if err != nil {
|
||||
log.Error("Error getting phone number").Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
// Get direction of call object using method call connection
|
||||
direction, err := getDirection(conn, callObj)
|
||||
if err != nil {
|
||||
log.Error("Error getting call direction").Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
if direction != MMCallDirectionIncoming {
|
||||
continue
|
||||
}
|
||||
|
||||
// Send call notification to InfiniTime
|
||||
resCh, err := dev.NotifyCall(phoneNum)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
go respHandlerOnce.Do(func() {
|
||||
// Wait for PineTime response
|
||||
for res := range resCh {
|
||||
switch res {
|
||||
case infinitime.CallStatusAccepted:
|
||||
// Attempt to accept call
|
||||
err = acceptCall(ctx, conn, callObj)
|
||||
if err != nil {
|
||||
log.Warn("Error accepting call").Err(err).Send()
|
||||
}
|
||||
case infinitime.CallStatusDeclined:
|
||||
// Attempt to decline call
|
||||
err = declineCall(ctx, conn, callObj)
|
||||
if err != nil {
|
||||
log.Warn("Error declining call").Err(err).Send()
|
||||
}
|
||||
case infinitime.CallStatusMuted:
|
||||
// Warn about unimplemented muting
|
||||
log.Warn("Muting calls is not implemented").Send()
|
||||
}
|
||||
}
|
||||
})
|
||||
case <-ctx.Done():
|
||||
return
|
||||
// Get phone number from call object using method call connection
|
||||
phoneNum, err := getPhoneNum(conn, callObj)
|
||||
if err != nil {
|
||||
log.Error("Error getting phone number").Err(err).Send()
|
||||
continue
|
||||
}
|
||||
|
||||
// Send call notification to InfiniTime
|
||||
resCh, err := dev.NotifyCall(phoneNum)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
go respHandlerOnce.Do(func() {
|
||||
// Wait for PineTime response
|
||||
for res := range resCh {
|
||||
switch res {
|
||||
case infinitime.CallStatusAccepted:
|
||||
// Attempt to accept call
|
||||
err = acceptCall(ctx, conn, callObj)
|
||||
if err != nil {
|
||||
log.Warn("Error accepting call").Err(err).Send()
|
||||
}
|
||||
case infinitime.CallStatusDeclined:
|
||||
// Attempt to decline call
|
||||
err = declineCall(ctx, conn, callObj)
|
||||
if err != nil {
|
||||
log.Warn("Error declining call").Err(err).Send()
|
||||
}
|
||||
case infinitime.CallStatusMuted:
|
||||
// Warn about unimplemented muting
|
||||
log.Warn("Muting calls is not implemented").Send()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -142,25 +125,6 @@ func getPhoneNum(conn *dbus.Conn, callObj dbus.BusObject) (string, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type MMCallDirection int
|
||||
|
||||
const (
|
||||
MMCallDirectionUnknown MMCallDirection = iota
|
||||
MMCallDirectionIncoming
|
||||
MMCallDirectionOutgoing
|
||||
)
|
||||
|
||||
// getDirection gets the direction of a call object using a DBus connection
|
||||
func getDirection(conn *dbus.Conn, callObj dbus.BusObject) (MMCallDirection, error) {
|
||||
var out MMCallDirection
|
||||
// Get number property on DBus object and store return value in out
|
||||
err := callObj.StoreProperty("org.freedesktop.ModemManager1.Call.Direction", &out)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// getPhoneNum accepts a call using a DBus connection
|
||||
func acceptCall(ctx context.Context, conn *dbus.Conn, callObj dbus.BusObject) error {
|
||||
// Call Accept() method on DBus object
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/itd/api"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
func fwUpgrade(c *cli.Context) error {
|
||||
|
||||
+3
-3
@@ -8,9 +8,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.elara.ws/logger"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/itd/api"
|
||||
"go.arsenm.dev/logger"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
var client *api.Client
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.arsenm.dev/infinitime"
|
||||
)
|
||||
|
||||
func resourcesLoad(c *cli.Context) error {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func firmwareTab(ctx context.Context, client *api.Client, w fyne.Window) fyne.CanvasObject {
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ import (
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func fsTab(ctx context.Context, client *api.Client, w fyne.Window, opened chan struct{}) fyne.CanvasObject {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/x/fyne/widget/charts"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func infoTab(ctx context.Context, client *api.Client, w fyne.Window) fyne.CanvasObject {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"fyne.io/fyne/v2/app"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func motionTab(ctx context.Context, client *api.Client, w fyne.Window) fyne.CanvasObject {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func notifyTab(ctx context.Context, client *api.Client, w fyne.Window) fyne.CanvasObject {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import (
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"go.elara.ws/itd/api"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func timeTab(ctx context.Context, client *api.Client, w fyne.Window) fyne.CanvasObject {
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/knadh/koanf/providers/confmap"
|
||||
"github.com/knadh/koanf/providers/env"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
"go.elara.ws/logger"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/logger"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
var cfgDir string
|
||||
@@ -107,7 +107,7 @@ func setCfgDefaults() {
|
||||
|
||||
"music.vol.interval": 5,
|
||||
|
||||
"fuse.enabled": false,
|
||||
"fuse.enabled": false,
|
||||
"fuse.mountpoint": "/tmp/itd/mnt",
|
||||
}, "."), nil)
|
||||
}
|
||||
|
||||
@@ -1,38 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go.arsenm.dev/itd/internal/fusefs"
|
||||
"os"
|
||||
|
||||
"github.com/hanwen/go-fuse/v2/fs"
|
||||
"github.com/hanwen/go-fuse/v2/fuse"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/internal/fusefs"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/logger/log"
|
||||
"context"
|
||||
"go.arsenm.dev/infinitime"
|
||||
)
|
||||
|
||||
func startFUSE(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func startFUSE(ctx context.Context, dev *infinitime.Device) error {
|
||||
// This is where we'll mount the FS
|
||||
err := os.MkdirAll(k.String("fuse.mountpoint"), 0o755)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ignore the error because nothing might be mounted on the mountpoint
|
||||
_ = fusefs.Unmount(k.String("fuse.mountpoint"))
|
||||
|
||||
os.Mkdir(k.String("fuse.mountpoint"), 0755)
|
||||
root, err := fusefs.BuildRootNode(dev)
|
||||
if err != nil {
|
||||
log.Error("Building root node failed").
|
||||
Err(err).
|
||||
Send()
|
||||
return err
|
||||
return err
|
||||
}
|
||||
|
||||
server, err := fs.Mount(k.String("fuse.mountpoint"), root, &fs.Options{
|
||||
MountOptions: fuse.MountOptions{
|
||||
// Set to true to see how the file system works.
|
||||
Debug: false,
|
||||
Debug: false,
|
||||
SingleThreaded: true,
|
||||
},
|
||||
})
|
||||
@@ -41,7 +33,7 @@ func startFUSE(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error
|
||||
Str("target", k.String("fuse.mountpoint")).
|
||||
Err(err).
|
||||
Send()
|
||||
return err
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Mounted on target").
|
||||
@@ -55,12 +47,7 @@ func startFUSE(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error
|
||||
return err
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("fuse")
|
||||
<-ctx.Done()
|
||||
server.Unmount()
|
||||
}()
|
||||
|
||||
// Wait until unmount before exiting
|
||||
go server.Serve()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module go.elara.ws/itd
|
||||
module go.arsenm.dev/itd
|
||||
|
||||
go 1.18
|
||||
|
||||
@@ -10,14 +10,13 @@ require (
|
||||
github.com/cheggaaa/pb/v3 v3.1.0
|
||||
github.com/gen2brain/dlgs v0.0.0-20220603100644-40c77870fa8d
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/hanwen/go-fuse/v2 v2.2.0
|
||||
github.com/knadh/koanf v1.4.4
|
||||
github.com/mattn/go-isatty v0.0.17
|
||||
github.com/mozillazg/go-pinyin v0.19.0
|
||||
github.com/urfave/cli/v2 v2.23.7
|
||||
go.elara.ws/drpc v0.0.0-20230421021209-fe4c05460a3d
|
||||
go.elara.ws/infinitime v0.0.0-20230421025334-f2640203e9e9
|
||||
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090
|
||||
go.arsenm.dev/drpc v0.0.0-20230104221210-aa7525743d98
|
||||
go.arsenm.dev/infinitime v0.0.0-20230104230015-512d48bc2469
|
||||
go.arsenm.dev/logger v0.0.0-20230104225304-d706171ea6df
|
||||
golang.org/x/text v0.5.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
modernc.org/sqlite v1.20.1
|
||||
@@ -46,6 +45,7 @@ require (
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gookit/color v1.5.1 // indirect
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/hanwen/go-fuse/v2 v2.2.0 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
@@ -74,7 +74,7 @@ require (
|
||||
golang.org/x/mobile v0.0.0-20221110043201-43a038452099 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/tools v0.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
honnef.co/go/js/dom v0.0.0-20221001195520-26252dedbe70 // indirect
|
||||
|
||||
@@ -341,8 +341,6 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@@ -529,13 +527,12 @@ github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5ta
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs=
|
||||
github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.arsenm.dev/drpc v0.0.0-20230104221210-aa7525743d98 h1:Tt/05IEOeIEfovj8YLxDaZz+SP8eR1uPLtcgD5Pf4EI=
|
||||
go.arsenm.dev/drpc v0.0.0-20230104221210-aa7525743d98/go.mod h1:K5cFls42m5q1RIphTVojRdXLaoCknq/kBqQt8Ow3XuA=
|
||||
go.arsenm.dev/infinitime v0.0.0-20230104230015-512d48bc2469 h1:LsJHg+8rQSYnTE1sSCjBCACxUUVMZIOQani8J6wF2/E=
|
||||
go.arsenm.dev/infinitime v0.0.0-20230104230015-512d48bc2469/go.mod h1:scUyDmLmCHn6CanGbau8yjTjzyhUbLJcsjmDCCKMIII=
|
||||
go.arsenm.dev/logger v0.0.0-20230104225304-d706171ea6df h1:8mBHvEe7BJmpOeKSMA5YLqrGo9dCpePocTeR0C1+/2w=
|
||||
go.arsenm.dev/logger v0.0.0-20230104225304-d706171ea6df/go.mod h1:RV2qydKDdoyaRkhAq8JEGvojR8eJ6bjq5WnSIlH7gYw=
|
||||
go.elara.ws/drpc v0.0.0-20230421021209-fe4c05460a3d h1:ANb8YPtcxPipwKgmnW688e5PGpNaLh+22nO2LBpIPOU=
|
||||
go.elara.ws/drpc v0.0.0-20230421021209-fe4c05460a3d/go.mod h1:NDprjiVqKXQKVGzX7jp2g/jctsUbvOxz1nN15QOBEGk=
|
||||
go.elara.ws/infinitime v0.0.0-20230421025334-f2640203e9e9 h1:HczkQCAHHmOHHdzTxFC1tEGzBJ7F/fuOWNUGrYQhMOg=
|
||||
go.elara.ws/infinitime v0.0.0-20230421025334-f2640203e9e9/go.mod h1:fu3+jGNBBtRQ1lcywtdZzoQgDFtqvvxBHvLw+XgPrFg=
|
||||
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090 h1:RVC8XvWo6Yw4HUshqx4TSzuBDScDghafU6QFRJ4xPZg=
|
||||
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090/go.mod h1:qng49owViqsW5Aey93lwBXONw20oGbJIoLVscB16mPM=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
@@ -757,8 +754,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package fusefs
|
||||
|
||||
import (
|
||||
"go.arsenm.dev/infinitime"
|
||||
"context"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func converterU8(ctx context.Context, in <-chan uint8) <-chan []byte {
|
||||
out := make(chan []byte, 2)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <- ctx.Done():
|
||||
return
|
||||
case event := <-in:
|
||||
out <- []byte(strconv.Itoa(int(event)) + "\n")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func converterU32(ctx context.Context, in <-chan uint32) <-chan []byte {
|
||||
out := make(chan []byte, 2)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <- ctx.Done():
|
||||
return
|
||||
case event := <-in:
|
||||
out <- []byte(strconv.Itoa(int(event)) + "\n")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func converterMotionValues(ctx context.Context, in <-chan infinitime.MotionValues) <-chan []byte {
|
||||
out := make(chan []byte, 2)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <- ctx.Done():
|
||||
return
|
||||
case event := <-in:
|
||||
out <- []byte(strconv.Itoa(int(event.X)) + " " + strconv.Itoa(int(event.Y)) + " " + strconv.Itoa(int(event.Z)) + "\n")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func converter1String(ctx context.Context, in string) <-chan []byte {
|
||||
out := make(chan []byte, 2)
|
||||
out <- []byte(in + "\n")
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
+101
-144
@@ -1,55 +1,43 @@
|
||||
package fusefs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/infinitime/blefs"
|
||||
"go.arsenm.dev/logger/log"
|
||||
"context"
|
||||
"io"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/hanwen/go-fuse/v2/fs"
|
||||
"github.com/hanwen/go-fuse/v2/fuse"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/infinitime/blefs"
|
||||
"go.elara.ws/logger/log"
|
||||
"io"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type ITProperty struct {
|
||||
name string
|
||||
Ino uint64
|
||||
gen func() ([]byte, error)
|
||||
Ino uint64
|
||||
gen func(context.Context) (<-chan []byte, error)
|
||||
}
|
||||
|
||||
|
||||
type DirEntry struct {
|
||||
isDir bool
|
||||
modtime uint64
|
||||
size uint32
|
||||
path string
|
||||
isDir bool
|
||||
modtime uint64
|
||||
size uint32
|
||||
path string
|
||||
}
|
||||
|
||||
type ITNode struct {
|
||||
fs.Inode
|
||||
kind nodeKind
|
||||
Ino uint64
|
||||
kind int
|
||||
Ino uint64
|
||||
|
||||
lst []DirEntry
|
||||
lst []DirEntry
|
||||
self DirEntry
|
||||
path string
|
||||
}
|
||||
|
||||
type nodeKind uint8
|
||||
|
||||
const (
|
||||
nodeKindRoot = iota
|
||||
nodeKindInfo
|
||||
nodeKindFS
|
||||
nodeKindReadOnly
|
||||
)
|
||||
|
||||
var (
|
||||
myfs *blefs.FS = nil
|
||||
inodemap map[string]uint64 = nil
|
||||
)
|
||||
var myfs *blefs.FS = nil
|
||||
var inodemap map[string]uint64 = nil
|
||||
|
||||
func BuildRootNode(dev *infinitime.Device) (*ITNode, error) {
|
||||
var err error
|
||||
@@ -60,56 +48,46 @@ func BuildRootNode(dev *infinitime.Device) (*ITNode, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ITNode{kind: nodeKindRoot}, nil
|
||||
return &ITNode{kind: 0}, nil
|
||||
}
|
||||
|
||||
var properties = make([]ITProperty, 6)
|
||||
|
||||
func BuildProperties(dev *infinitime.Device) {
|
||||
properties[0] = ITProperty{
|
||||
"heartrate", 2,
|
||||
func() ([]byte, error) {
|
||||
ans, err := dev.HeartRate()
|
||||
return []byte(strconv.Itoa(int(ans)) + "\n"), err
|
||||
},
|
||||
}
|
||||
properties[1] = ITProperty{
|
||||
"battery", 3,
|
||||
func() ([]byte, error) {
|
||||
ans, err := dev.BatteryLevel()
|
||||
return []byte(strconv.Itoa(int(ans)) + "\n"), err
|
||||
},
|
||||
}
|
||||
properties[2] = ITProperty{
|
||||
"motion", 4,
|
||||
func() ([]byte, error) {
|
||||
ans, err := dev.Motion()
|
||||
return []byte(strconv.Itoa(int(ans.X)) + " " + strconv.Itoa(int(ans.Y)) + " " + strconv.Itoa(int(ans.Z)) + "\n"), err
|
||||
},
|
||||
}
|
||||
properties[3] = ITProperty{
|
||||
"stepcount", 6,
|
||||
func() ([]byte, error) {
|
||||
ans, err := dev.StepCount()
|
||||
return []byte(strconv.Itoa(int(ans)) + "\n"), err
|
||||
},
|
||||
}
|
||||
properties[4] = ITProperty{
|
||||
"version", 7,
|
||||
func() ([]byte, error) {
|
||||
properties[0] = ITProperty{"heartrate", 2,
|
||||
func(ctx context.Context) (<-chan []byte, error) {
|
||||
ans, err := dev.WatchHeartRate(ctx)
|
||||
return converterU8(ctx, ans), err
|
||||
}}
|
||||
properties[1] = ITProperty{"battery", 3,
|
||||
func(ctx context.Context) (<-chan []byte, error) {
|
||||
ans, err := dev.WatchBatteryLevel(ctx)
|
||||
return converterU8(ctx, ans), err
|
||||
}}
|
||||
properties[2] = ITProperty{"motion", 4,
|
||||
func(ctx context.Context) (<-chan []byte, error) {
|
||||
ans, err := dev.WatchMotion(ctx)
|
||||
return converterMotionValues(ctx, ans), err
|
||||
}}
|
||||
properties[3] = ITProperty{"stepcount", 5,
|
||||
func(ctx context.Context) (<-chan []byte, error) {
|
||||
ans, err := dev.WatchStepCount(ctx)
|
||||
return converterU32(ctx, ans), err
|
||||
}}
|
||||
properties[4] = ITProperty{"version", 6,
|
||||
func(ctx context.Context) (<-chan []byte, error) {
|
||||
ans, err := dev.Version()
|
||||
return []byte(ans + "\n"), err
|
||||
},
|
||||
}
|
||||
properties[5] = ITProperty{
|
||||
"address", 8,
|
||||
func() ([]byte, error) {
|
||||
return converter1String(ctx, ans), err
|
||||
}}
|
||||
properties[5] = ITProperty{"address", 7,
|
||||
func(ctx context.Context) (<-chan []byte, error) {
|
||||
ans := dev.Address()
|
||||
return []byte(ans + "\n"), nil
|
||||
},
|
||||
}
|
||||
return converter1String(ctx, ans), nil
|
||||
}}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var _ fs.NodeReaddirer = (*ITNode)(nil)
|
||||
|
||||
// Readdir is part of the NodeReaddirer interface
|
||||
@@ -119,7 +97,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
// root folder
|
||||
r := make([]fuse.DirEntry, 2)
|
||||
r[0] = fuse.DirEntry{
|
||||
Name: "info",
|
||||
Name: "device",
|
||||
Ino: 0,
|
||||
Mode: fuse.S_IFDIR,
|
||||
}
|
||||
@@ -131,7 +109,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
return fs.NewListDirStream(r), 0
|
||||
|
||||
case 1:
|
||||
// info folder
|
||||
// device folder
|
||||
r := make([]fuse.DirEntry, 6)
|
||||
for ind, value := range properties {
|
||||
r[ind] = fuse.DirEntry{
|
||||
@@ -144,7 +122,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
return fs.NewListDirStream(r), 0
|
||||
|
||||
case 2:
|
||||
// on info
|
||||
// on device
|
||||
files, err := myfs.ReadDir(n.path)
|
||||
if err != nil {
|
||||
log.Error("FUSE ReadDir failed").Str("path", n.path).Err(err).Send()
|
||||
@@ -163,10 +141,10 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
name := info.Name()
|
||||
|
||||
file := DirEntry{
|
||||
path: n.path + "/" + name,
|
||||
size: uint32(info.Size()),
|
||||
path: n.path + "/" + name,
|
||||
size: uint32(info.Size()),
|
||||
modtime: uint64(info.ModTime().Unix()),
|
||||
isDir: info.IsDir(),
|
||||
isDir: info.IsDir(),
|
||||
}
|
||||
n.lst[ind] = file
|
||||
|
||||
@@ -180,13 +158,13 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
r[ind] = fuse.DirEntry{
|
||||
Name: name,
|
||||
Mode: fuse.S_IFDIR,
|
||||
Ino: ino + 10,
|
||||
Ino : ino + 10,
|
||||
}
|
||||
} else {
|
||||
r[ind] = fuse.DirEntry{
|
||||
Name: name,
|
||||
Mode: fuse.S_IFREG,
|
||||
Ino: ino + 10,
|
||||
Ino : ino + 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,37 +175,36 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
}
|
||||
|
||||
var _ fs.NodeLookuper = (*ITNode)(nil)
|
||||
|
||||
func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
|
||||
switch n.kind {
|
||||
case 0:
|
||||
// root folder
|
||||
if name == "info" {
|
||||
if name == "device" {
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFDIR,
|
||||
Ino: uint64(0),
|
||||
Ino: uint64(0),
|
||||
}
|
||||
operations := &ITNode{kind: nodeKindInfo, Ino: 0}
|
||||
operations := &ITNode{kind: 1, Ino: 0}
|
||||
child := n.NewInode(ctx, operations, stable)
|
||||
return child, 0
|
||||
} else if name == "fs" {
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFDIR,
|
||||
Ino: uint64(1),
|
||||
Ino: uint64(1),
|
||||
}
|
||||
operations := &ITNode{kind: nodeKindFS, Ino: 1, path: ""}
|
||||
operations := &ITNode{kind: 2, Ino: 1, path : ""}
|
||||
child := n.NewInode(ctx, operations, stable)
|
||||
return child, 0
|
||||
}
|
||||
case 1:
|
||||
// info folder
|
||||
// device folder
|
||||
for _, value := range properties {
|
||||
if value.name == name {
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFREG,
|
||||
Ino: uint64(value.Ino),
|
||||
Ino: uint64(value.Ino),
|
||||
}
|
||||
operations := &ITNode{kind: nodeKindReadOnly, Ino: value.Ino}
|
||||
operations := &ITNode{kind: 3, Ino: value.Ino}
|
||||
child := n.NewInode(ctx, operations, stable)
|
||||
return child, 0
|
||||
}
|
||||
@@ -240,7 +217,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*
|
||||
}
|
||||
|
||||
for _, file := range n.lst {
|
||||
if file.path != n.path+"/"+name {
|
||||
if file.path != n.path + "/" + name {
|
||||
continue
|
||||
}
|
||||
log.Debug("FUSE Lookup successful").Str("path", file.path).Send()
|
||||
@@ -248,25 +225,26 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*
|
||||
if file.isDir {
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFDIR,
|
||||
Ino: inodemap[file.path],
|
||||
Ino: inodemap[file.path],
|
||||
}
|
||||
operations := &ITNode{kind: nodeKindFS, path: file.path}
|
||||
operations := &ITNode{kind: 2, path: file.path}
|
||||
child := n.NewInode(ctx, operations, stable)
|
||||
return child, 0
|
||||
} else {
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFREG,
|
||||
Ino: inodemap[file.path],
|
||||
Ino: inodemap[file.path],
|
||||
}
|
||||
operations := &ITNode{
|
||||
kind: nodeKindFS, path: file.path,
|
||||
kind: 2, path: file.path,
|
||||
self: file,
|
||||
}
|
||||
child := n.NewInode(ctx, operations, stable)
|
||||
return child, 0
|
||||
}
|
||||
break
|
||||
}
|
||||
log.Warn("FUSE Lookup failed").Str("path", n.path+"/"+name).Send()
|
||||
log.Warn("FUSE Lookup failed").Str("path", n.path + "/" + name).Send()
|
||||
}
|
||||
return nil, syscall.ENOENT
|
||||
}
|
||||
@@ -276,7 +254,6 @@ type bytesFileReadHandle struct {
|
||||
}
|
||||
|
||||
var _ fs.FileReader = (*bytesFileReadHandle)(nil)
|
||||
|
||||
func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
|
||||
log.Debug("FUSE Executing Read").Int("size", len(fh.content)).Send()
|
||||
end := off + int64(len(dest))
|
||||
@@ -287,35 +264,30 @@ func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64)
|
||||
}
|
||||
|
||||
type sensorFileReadHandle struct {
|
||||
content []byte
|
||||
ch <-chan []byte
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
var _ fs.FileReader = (*sensorFileReadHandle)(nil)
|
||||
|
||||
func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
|
||||
log.Debug("FUSE Executing Read").Int("size", len(fh.content)).Send()
|
||||
end := off + int64(len(dest))
|
||||
if end > int64(len(fh.content)) {
|
||||
end = int64(len(fh.content))
|
||||
}
|
||||
return fuse.ReadResultData(fh.content[off:end]), 0
|
||||
content := <-fh.ch
|
||||
return fuse.ReadResultData(content), 0
|
||||
}
|
||||
|
||||
var _ fs.FileFlusher = (*sensorFileReadHandle)(nil)
|
||||
|
||||
func (fh *sensorFileReadHandle) Flush(ctx context.Context) (errno syscall.Errno) {
|
||||
fh.cancel()
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
type bytesFileWriteHandle struct {
|
||||
content []byte
|
||||
path string
|
||||
path string
|
||||
}
|
||||
|
||||
var _ fs.FileWriter = (*bytesFileWriteHandle)(nil)
|
||||
|
||||
func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) {
|
||||
log.Debug("FUSE Executing Write").Str("path", fh.path).Int("prev_size", len(fh.content)).Int("next_size", len(data)).Send()
|
||||
log.Info("Executing Write").Str("path", fh.path).Int("prev_size", len(fh.content)).Int("next_size", len(data)).Send()
|
||||
if off != int64(len(fh.content)) {
|
||||
log.Error("FUSE Write file size changed unexpectedly").Int("expect", int(off)).Int("received", len(fh.content)).Send()
|
||||
return 0, syscall.ENXIO
|
||||
@@ -325,8 +297,11 @@ func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int6
|
||||
}
|
||||
|
||||
var _ fs.FileFlusher = (*bytesFileWriteHandle)(nil)
|
||||
|
||||
func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) {
|
||||
if len(fh.content) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
log.Debug("FUSE Attempting flush").Str("path", fh.path).Send()
|
||||
fp, err := myfs.Create(fh.path, uint32(len(fh.content)))
|
||||
if err != nil {
|
||||
@@ -334,16 +309,6 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno)
|
||||
return syscallErr(err)
|
||||
}
|
||||
|
||||
if len(fh.content) == 0 {
|
||||
log.Debug("FUSE Flush no data to write").Str("path", fh.path).Send()
|
||||
err = fp.Close()
|
||||
if err != nil {
|
||||
log.Error("FUSE Flush failed during close").Str("path", fh.path).Err(err).Send()
|
||||
return syscallErr(err)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
go func() {
|
||||
// For every progress event
|
||||
for sent := range fp.Progress() {
|
||||
@@ -372,15 +337,12 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno)
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
var _ fs.FileFsyncer = (*bytesFileWriteHandle)(nil)
|
||||
|
||||
func (fh *bytesFileWriteHandle) Fsync(ctx context.Context, flags uint32) (errno syscall.Errno) {
|
||||
return fh.Flush(ctx)
|
||||
}
|
||||
|
||||
var _ fs.NodeGetattrer = (*ITNode)(nil)
|
||||
|
||||
func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
||||
log.Debug("FUSE getattr").Str("path", bn.path).Send()
|
||||
out.Ino = bn.Ino
|
||||
@@ -392,7 +354,6 @@ func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOu
|
||||
}
|
||||
|
||||
var _ fs.NodeSetattrer = (*ITNode)(nil)
|
||||
|
||||
func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno {
|
||||
log.Debug("FUSE setattr").Str("path", bn.path).Send()
|
||||
out.Size = 0
|
||||
@@ -401,7 +362,6 @@ func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAtt
|
||||
}
|
||||
|
||||
var _ fs.NodeOpener = (*ITNode)(nil)
|
||||
|
||||
func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||
switch f.kind {
|
||||
case 2:
|
||||
@@ -411,11 +371,11 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle,
|
||||
return nil, 0, syscall.EROFS
|
||||
}
|
||||
|
||||
if openFlags&syscall.O_WRONLY != 0 {
|
||||
if openFlags & syscall.O_WRONLY != 0 {
|
||||
log.Debug("FUSE Opening for write").Str("path", f.path).Send()
|
||||
fh = &bytesFileWriteHandle{
|
||||
path: f.path,
|
||||
content: make([]byte, 0),
|
||||
path : f.path,
|
||||
content : make([]byte, 0),
|
||||
}
|
||||
return fh, fuse.FOPEN_DIRECT_IO, 0
|
||||
} else {
|
||||
@@ -460,13 +420,15 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle,
|
||||
|
||||
for _, value := range properties {
|
||||
if value.Ino == f.Ino {
|
||||
ans, err := value.gen()
|
||||
sub_ctx, cancel := context.WithCancel(ctx)
|
||||
ans, err := value.gen(sub_ctx)
|
||||
if err != nil {
|
||||
return nil, 0, syscallErr(err)
|
||||
}
|
||||
|
||||
fh = &sensorFileReadHandle{
|
||||
content: ans,
|
||||
ch: ans,
|
||||
cancel : cancel,
|
||||
}
|
||||
return fh, fuse.FOPEN_DIRECT_IO, 0
|
||||
}
|
||||
@@ -476,7 +438,6 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle,
|
||||
}
|
||||
|
||||
var _ fs.NodeCreater = (*ITNode)(nil)
|
||||
|
||||
func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (node *fs.Inode, fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||
if f.kind != 2 {
|
||||
return nil, nil, 0, syscall.EROFS
|
||||
@@ -488,17 +449,17 @@ func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uin
|
||||
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFREG,
|
||||
Ino: ino,
|
||||
Ino: ino,
|
||||
}
|
||||
operations := &ITNode{
|
||||
kind: nodeKindFS, Ino: ino,
|
||||
path: path,
|
||||
kind: 2, Ino: ino,
|
||||
path : path,
|
||||
}
|
||||
node = f.NewInode(ctx, operations, stable)
|
||||
|
||||
fh = &bytesFileWriteHandle{
|
||||
path: path,
|
||||
content: make([]byte, 0),
|
||||
path : path,
|
||||
content : make([]byte, 0),
|
||||
}
|
||||
|
||||
log.Debug("FUSE Creating file").Str("path", path).Send()
|
||||
@@ -508,7 +469,6 @@ func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uin
|
||||
}
|
||||
|
||||
var _ fs.NodeMkdirer = (*ITNode)(nil)
|
||||
|
||||
func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
|
||||
if f.kind != 2 {
|
||||
return nil, syscall.EROFS
|
||||
@@ -529,11 +489,11 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.
|
||||
|
||||
stable := fs.StableAttr{
|
||||
Mode: fuse.S_IFDIR,
|
||||
Ino: ino,
|
||||
Ino: ino,
|
||||
}
|
||||
operations := &ITNode{
|
||||
kind: nodeKindFS, Ino: ino,
|
||||
path: path,
|
||||
kind: 2, Ino: ino,
|
||||
path : path,
|
||||
}
|
||||
node := f.NewInode(ctx, operations, stable)
|
||||
|
||||
@@ -545,7 +505,6 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.
|
||||
}
|
||||
|
||||
var _ fs.NodeRenamer = (*ITNode)(nil)
|
||||
|
||||
func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbedder, newName string, flags uint32) syscall.Errno {
|
||||
if f.kind != 2 {
|
||||
return syscall.EROFS
|
||||
@@ -577,17 +536,16 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe
|
||||
}
|
||||
|
||||
var _ fs.NodeUnlinker = (*ITNode)(nil)
|
||||
|
||||
func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno {
|
||||
if f.kind != 2 {
|
||||
return syscall.EROFS
|
||||
}
|
||||
|
||||
delete(inodemap, f.path+"/"+name)
|
||||
delete(inodemap, f.path + "/" + name)
|
||||
err := myfs.Remove(f.path + "/" + name)
|
||||
if err != nil {
|
||||
log.Error("FUSE Unlink failed").
|
||||
Str("file", f.path+"/"+name).
|
||||
Str("file", f.path + "/" + name).
|
||||
Err(err).
|
||||
Send()
|
||||
|
||||
@@ -595,13 +553,12 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno {
|
||||
}
|
||||
|
||||
log.Debug("FUSE Unlink success").
|
||||
Str("file", f.path+"/"+name).
|
||||
Str("file", f.path + "/" + name).
|
||||
Send()
|
||||
return 0
|
||||
}
|
||||
|
||||
var _ fs.NodeRmdirer = (*ITNode)(nil)
|
||||
|
||||
func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno {
|
||||
return f.Unlink(ctx, name)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package fusefs
|
||||
|
||||
import (
|
||||
"go.arsenm.dev/infinitime/blefs"
|
||||
"syscall"
|
||||
|
||||
"go.elara.ws/infinitime/blefs"
|
||||
)
|
||||
|
||||
func syscallErr(err error) syscall.Errno {
|
||||
@@ -11,64 +9,59 @@ func syscallErr(err error) syscall.Errno {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch err := err.(type) {
|
||||
case blefs.FSError:
|
||||
switch err.Code {
|
||||
case 0x02: // filesystem error
|
||||
return syscall.EIO // TODO
|
||||
case 0x05: // read-only filesystem
|
||||
return syscall.EROFS
|
||||
case 0x03: // no such file
|
||||
return syscall.ENOENT
|
||||
case 0x04: // protocol error
|
||||
return syscall.EPROTO
|
||||
case -5: // input/output error
|
||||
return syscall.EIO
|
||||
case -84: // filesystem is corrupted
|
||||
return syscall.ENOTRECOVERABLE // TODO
|
||||
case -2: // no such directory entry
|
||||
return syscall.ENOENT
|
||||
case -17: // entry already exists
|
||||
return syscall.EEXIST
|
||||
case -20: // entry is not a directory
|
||||
return syscall.ENOTDIR
|
||||
case -39: // directory is not empty
|
||||
return syscall.ENOTEMPTY
|
||||
case -9: // bad file number
|
||||
return syscall.EBADF
|
||||
case -27: // file is too large
|
||||
return syscall.EFBIG
|
||||
case -22: // invalid parameter
|
||||
return syscall.EINVAL
|
||||
case -28: // no space left on device
|
||||
return syscall.ENOSPC
|
||||
case -12: // no more memory available
|
||||
return syscall.ENOMEM
|
||||
case -61: // no attr available
|
||||
return syscall.ENODATA // TODO
|
||||
case -36: // file name is too long
|
||||
return syscall.ENAMETOOLONG
|
||||
}
|
||||
default:
|
||||
switch err {
|
||||
case blefs.ErrFileNotExists: // file does not exist
|
||||
return syscall.ENOENT
|
||||
case blefs.ErrFileReadOnly: // file is read only
|
||||
return syscall.EACCES
|
||||
case blefs.ErrFileWriteOnly: // file is write only
|
||||
return syscall.EACCES
|
||||
case blefs.ErrInvalidOffset: // invalid file offset
|
||||
return syscall.EINVAL
|
||||
case blefs.ErrOffsetChanged: // offset has already been changed
|
||||
return syscall.ESPIPE
|
||||
case blefs.ErrReadOpen: // only one file can be opened for reading at a time
|
||||
return syscall.ENFILE
|
||||
case blefs.ErrWriteOpen: // only one file can be opened for writing at a time
|
||||
return syscall.ENFILE
|
||||
case blefs.ErrNoRemoveRoot: // refusing to remove root directory
|
||||
return syscall.EPERM
|
||||
}
|
||||
switch err {
|
||||
case blefs.FSError{0x02}: // filesystem error
|
||||
return syscall.EIO // TODO
|
||||
case blefs.FSError{0x05}: // read-only filesystem
|
||||
return syscall.EROFS
|
||||
case blefs.FSError{0x03}: // no such file
|
||||
return syscall.ENOENT
|
||||
case blefs.FSError{0x04}: // protocol error
|
||||
return syscall.EPROTO
|
||||
case blefs.FSError{-5}: // input/output error
|
||||
return syscall.EIO
|
||||
case blefs.FSError{-84}: // filesystem is corrupted
|
||||
return syscall.ENOTRECOVERABLE // TODO
|
||||
case blefs.FSError{-2}: // no such directory entry
|
||||
return syscall.ENOENT
|
||||
case blefs.FSError{-17}: // entry already exists
|
||||
return syscall.EEXIST
|
||||
case blefs.FSError{-20}: // entry is not a directory
|
||||
return syscall.ENOTDIR
|
||||
case blefs.FSError{-39}: // directory is not empty
|
||||
return syscall.ENOTEMPTY
|
||||
case blefs.FSError{-9}: // bad file number
|
||||
return syscall.EBADF
|
||||
case blefs.FSError{-27}: // file is too large
|
||||
return syscall.EFBIG
|
||||
case blefs.FSError{-22}: // invalid parameter
|
||||
return syscall.EINVAL
|
||||
case blefs.FSError{-28}: // no space left on device
|
||||
return syscall.ENOSPC
|
||||
case blefs.FSError{-12}: // no more memory available
|
||||
return syscall.ENOMEM
|
||||
case blefs.FSError{-61}: // no attr available
|
||||
return syscall.ENODATA // TODO
|
||||
case blefs.FSError{-36}: // file name is too long
|
||||
return syscall.ENAMETOOLONG
|
||||
case blefs.ErrFileNotExists: // file does not exist
|
||||
return syscall.ENOENT
|
||||
case blefs.ErrFileReadOnly: // file is read only
|
||||
return syscall.EACCES
|
||||
case blefs.ErrFileWriteOnly: // file is write only
|
||||
return syscall.EACCES
|
||||
case blefs.ErrInvalidOffset: // invalid file offset
|
||||
return syscall.EFAULT // TODO
|
||||
case blefs.ErrOffsetChanged: // offset has already been changed
|
||||
return syscall.ESPIPE
|
||||
case blefs.ErrReadOpen: // only one file can be opened for reading at a time
|
||||
return syscall.ENFILE
|
||||
case blefs.ErrWriteOpen: // only one file can be opened for writing at a time
|
||||
return syscall.ENFILE
|
||||
case blefs.ErrNoRemoveRoot: // refusing to remove root directory
|
||||
return syscall.EPERM
|
||||
}
|
||||
|
||||
return syscall.EIO
|
||||
return syscall.EIO // TODO
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package fusefs
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/hanwen/go-fuse/v2/fuse"
|
||||
)
|
||||
|
||||
func Unmount(mountPoint string) error {
|
||||
return unmount(mountPoint, &fuse.MountOptions{DirectMount: false})
|
||||
}
|
||||
|
||||
// Unfortunately, the FUSE library does not export its unmount function,
|
||||
// so this is required until that changes
|
||||
//
|
||||
//go:linkname unmount github.com/hanwen/go-fuse/v2/fuse.unmount
|
||||
func unmount(mountPoint string, opts *fuse.MountOptions) error
|
||||
@@ -26,17 +26,15 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gen2brain/dlgs"
|
||||
"github.com/knadh/koanf"
|
||||
"github.com/mattn/go-isatty"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/logger"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/logger"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
var k = koanf.New(".")
|
||||
@@ -76,7 +74,21 @@ func main() {
|
||||
LogLevel: level,
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
go func() {
|
||||
<-sigCh
|
||||
cancel()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
os.Exit(0)
|
||||
}()
|
||||
signal.Notify(
|
||||
sigCh,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGTERM,
|
||||
)
|
||||
|
||||
// Connect to InfiniTime with default options
|
||||
dev, err := infinitime.Connect(ctx, opts)
|
||||
@@ -133,88 +145,57 @@ func main() {
|
||||
log.Error("Error setting current time on connected InfiniTime").Err(err).Send()
|
||||
}
|
||||
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
sig := <-sigCh
|
||||
log.Warn("Signal received, shutting down").Stringer("signal", sig).Send()
|
||||
cancel()
|
||||
}()
|
||||
|
||||
wg := WaitGroup{&sync.WaitGroup{}}
|
||||
|
||||
// Initialize music controls
|
||||
err = initMusicCtrl(ctx, wg, dev)
|
||||
err = initMusicCtrl(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error initializing music control").Err(err).Send()
|
||||
}
|
||||
|
||||
// Start control socket
|
||||
err = initCallNotifs(ctx, wg, dev)
|
||||
err = initCallNotifs(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error initializing call notifications").Err(err).Send()
|
||||
}
|
||||
|
||||
// Initialize notification relay
|
||||
err = initNotifRelay(ctx, wg, dev)
|
||||
err = initNotifRelay(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error initializing notification relay").Err(err).Send()
|
||||
}
|
||||
|
||||
// Initializa weather
|
||||
err = initWeather(ctx, wg, dev)
|
||||
err = initWeather(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error initializing weather").Err(err).Send()
|
||||
}
|
||||
|
||||
// Initialize metrics collection
|
||||
err = initMetrics(ctx, wg, dev)
|
||||
err = initMetrics(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error intializing metrics collection").Err(err).Send()
|
||||
}
|
||||
|
||||
// Initialize puremaps integration
|
||||
err = initPureMaps(ctx, wg, dev)
|
||||
// Initialize metrics collection
|
||||
err = initPureMaps(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error intializing puremaps integration").Err(err).Send()
|
||||
}
|
||||
|
||||
// Start fuse socket
|
||||
if k.Bool("fuse.enabled") {
|
||||
err = startFUSE(ctx, wg, dev)
|
||||
err = startFUSE(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error starting fuse socket").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
// Start control socket
|
||||
err = startSocket(ctx, wg, dev)
|
||||
err = startSocket(ctx, dev)
|
||||
if err != nil {
|
||||
log.Error("Error starting socket").Err(err).Send()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
type x struct {
|
||||
n int
|
||||
*sync.WaitGroup
|
||||
}
|
||||
|
||||
func (xy *x) Add(i int) {
|
||||
xy.n += i
|
||||
xy.WaitGroup.Add(i)
|
||||
fmt.Println("add: counter:", xy.n)
|
||||
}
|
||||
|
||||
func (xy *x) Done() {
|
||||
xy.n -= 1
|
||||
xy.WaitGroup.Done()
|
||||
fmt.Println("done: counter:", xy.n)
|
||||
// Block forever
|
||||
select {}
|
||||
}
|
||||
|
||||
func onReqPasskey() (uint32, error) {
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/internal/utils"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/itd/internal/utils"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
progressProperty = interfaceName + ".progress"
|
||||
)
|
||||
|
||||
func initPureMaps(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func initPureMaps(ctx context.Context, dev *infinitime.Device) error {
|
||||
// Connect to session bus. This connection is for method calls.
|
||||
conn, err := utils.NewSessionBusConn(ctx)
|
||||
if err != nil {
|
||||
@@ -59,10 +59,7 @@ func initPureMaps(ctx context.Context, wg WaitGroup, dev *infinitime.Device) err
|
||||
}
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("pureMaps")
|
||||
|
||||
signalCh := make(chan *dbus.Message, 10)
|
||||
monitorConn.Eavesdrop(signalCh)
|
||||
|
||||
|
||||
+3
-11
@@ -4,15 +4,14 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"path/filepath"
|
||||
|
||||
"time"
|
||||
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/logger/log"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
func initMetrics(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func initMetrics(ctx context.Context, dev *infinitime.Device) error {
|
||||
// If metrics disabled, return nil
|
||||
if !k.Bool("metrics.enabled") {
|
||||
return nil
|
||||
@@ -126,13 +125,6 @@ func initMetrics(ctx context.Context, wg WaitGroup, dev *infinitime.Device) erro
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("metrics")
|
||||
<-ctx.Done()
|
||||
db.Close()
|
||||
}()
|
||||
|
||||
log.Info("Initialized metrics collection").Send()
|
||||
|
||||
return nil
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"go.elara.ws/itd/internal/utils"
|
||||
"go.arsenm.dev/itd/internal/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -20,15 +20,14 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/mpris"
|
||||
"go.elara.ws/itd/translit"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/itd/mpris"
|
||||
"go.arsenm.dev/itd/translit"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
func initMusicCtrl(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func initMusicCtrl(ctx context.Context, dev *infinitime.Device) error {
|
||||
mpris.Init(ctx)
|
||||
|
||||
maps := k.Strings("notifs.translit.use")
|
||||
@@ -55,31 +54,23 @@ func initMusicCtrl(ctx context.Context, wg WaitGroup, dev *infinitime.Device) er
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("musicCtrl")
|
||||
// For every music event received
|
||||
for {
|
||||
select {
|
||||
case musicEvt := <-musicEvtCh:
|
||||
// Perform appropriate action based on event
|
||||
switch musicEvt {
|
||||
case infinitime.MusicEventPlay:
|
||||
mpris.Play()
|
||||
case infinitime.MusicEventPause:
|
||||
mpris.Pause()
|
||||
case infinitime.MusicEventNext:
|
||||
mpris.Next()
|
||||
case infinitime.MusicEventPrev:
|
||||
mpris.Prev()
|
||||
case infinitime.MusicEventVolUp:
|
||||
mpris.VolUp(uint(k.Int("music.vol.interval")))
|
||||
case infinitime.MusicEventVolDown:
|
||||
mpris.VolDown(uint(k.Int("music.vol.interval")))
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
for musicEvt := range musicEvtCh {
|
||||
// Perform appropriate action based on event
|
||||
switch musicEvt {
|
||||
case infinitime.MusicEventPlay:
|
||||
mpris.Play()
|
||||
case infinitime.MusicEventPause:
|
||||
mpris.Pause()
|
||||
case infinitime.MusicEventNext:
|
||||
mpris.Next()
|
||||
case infinitime.MusicEventPrev:
|
||||
mpris.Prev()
|
||||
case infinitime.MusicEventVolUp:
|
||||
mpris.VolUp(uint(k.Int("music.vol.interval")))
|
||||
case infinitime.MusicEventVolDown:
|
||||
mpris.VolDown(uint(k.Int("music.vol.interval")))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -23,13 +23,13 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/itd/internal/utils"
|
||||
"go.elara.ws/itd/translit"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/itd/internal/utils"
|
||||
"go.arsenm.dev/itd/translit"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
func initNotifRelay(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func initNotifRelay(ctx context.Context, dev *infinitime.Device) error {
|
||||
// Connect to dbus session bus
|
||||
bus, err := utils.NewSessionBusConn(ctx)
|
||||
if err != nil {
|
||||
@@ -54,51 +54,43 @@ func initNotifRelay(ctx context.Context, wg WaitGroup, dev *infinitime.Device) e
|
||||
// Send events to channel
|
||||
bus.Eavesdrop(notifCh)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("notifRelay")
|
||||
// For every event sent to channel
|
||||
for {
|
||||
select {
|
||||
case v := <-notifCh:
|
||||
// If firmware is updating, skip
|
||||
if firmwareUpdating {
|
||||
continue
|
||||
}
|
||||
|
||||
// If body does not contain 5 elements, skip
|
||||
if len(v.Body) < 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get requred fields
|
||||
sender, summary, body := v.Body[0].(string), v.Body[3].(string), v.Body[4].(string)
|
||||
|
||||
// If fields are ignored in config, skip
|
||||
if ignored(sender, summary, body) {
|
||||
continue
|
||||
}
|
||||
|
||||
maps := k.Strings("notifs.translit.use")
|
||||
translit.Transliterators["custom"] = translit.Map(k.Strings("notifs.translit.custom"))
|
||||
sender = translit.Transliterate(sender, maps...)
|
||||
summary = translit.Transliterate(summary, maps...)
|
||||
body = translit.Transliterate(body, maps...)
|
||||
|
||||
var msg string
|
||||
// If summary does not exist, set message to body.
|
||||
// If it does, set message to summary, two newlines, and then body
|
||||
if summary == "" {
|
||||
msg = body
|
||||
} else {
|
||||
msg = fmt.Sprintf("%s\n\n%s", summary, body)
|
||||
}
|
||||
|
||||
dev.Notify(sender, msg)
|
||||
case <-ctx.Done():
|
||||
bus.Close()
|
||||
return
|
||||
for v := range notifCh {
|
||||
// If firmware is updating, skip
|
||||
if firmwareUpdating {
|
||||
continue
|
||||
}
|
||||
|
||||
// If body does not contain 5 elements, skip
|
||||
if len(v.Body) < 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get requred fields
|
||||
sender, summary, body := v.Body[0].(string), v.Body[3].(string), v.Body[4].(string)
|
||||
|
||||
// If fields are ignored in config, skip
|
||||
if ignored(sender, summary, body) {
|
||||
continue
|
||||
}
|
||||
|
||||
maps := k.Strings("notifs.translit.use")
|
||||
translit.Transliterators["custom"] = translit.Map(k.Strings("notifs.translit.custom"))
|
||||
sender = translit.Transliterate(sender, maps...)
|
||||
summary = translit.Transliterate(summary, maps...)
|
||||
body = translit.Transliterate(body, maps...)
|
||||
|
||||
var msg string
|
||||
// If summary does not exist, set message to body.
|
||||
// If it does, set message to summary, two newlines, and then body
|
||||
if summary == "" {
|
||||
msg = body
|
||||
} else {
|
||||
msg = fmt.Sprintf("%s\n\n%s", summary, body)
|
||||
}
|
||||
|
||||
dev.Notify(sender, msg)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -25,14 +25,13 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"time"
|
||||
|
||||
"go.elara.ws/drpc/muxserver"
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/infinitime/blefs"
|
||||
"go.elara.ws/itd/internal/rpc"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/drpc/muxserver"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/infinitime/blefs"
|
||||
"go.arsenm.dev/itd/internal/rpc"
|
||||
"go.arsenm.dev/logger/log"
|
||||
"storj.io/drpc/drpcmux"
|
||||
)
|
||||
|
||||
@@ -42,7 +41,7 @@ var (
|
||||
ErrDFUInvalidUpgType = errors.New("invalid upgrade type")
|
||||
)
|
||||
|
||||
func startSocket(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func startSocket(ctx context.Context, dev *infinitime.Device) error {
|
||||
// Make socket directory if non-existant
|
||||
err := os.MkdirAll(filepath.Dir(k.String("socket.path")), 0o755)
|
||||
if err != nil {
|
||||
@@ -78,13 +77,10 @@ func startSocket(ctx context.Context, wg WaitGroup, dev *infinitime.Device) erro
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Starting control socket").Str("path", k.String("socket.path")).Send()
|
||||
go muxserver.New(mux).Serve(ctx, ln)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("socket")
|
||||
muxserver.New(mux).Serve(ctx, ln)
|
||||
}()
|
||||
// Log socket start
|
||||
log.Info("Started control socket").Str("path", k.String("socket.path")).Send()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"go.elara.ws/logger/log"
|
||||
)
|
||||
|
||||
type WaitGroup struct {
|
||||
*sync.WaitGroup
|
||||
}
|
||||
|
||||
func (wg WaitGroup) Done(c string) {
|
||||
log.Info("Component stopped").Str("name", c).Send()
|
||||
wg.WaitGroup.Done()
|
||||
}
|
||||
+5
-22
@@ -9,12 +9,11 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"time"
|
||||
|
||||
"go.elara.ws/infinitime"
|
||||
"go.elara.ws/infinitime/weather"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.arsenm.dev/infinitime"
|
||||
"go.arsenm.dev/infinitime/weather"
|
||||
"go.arsenm.dev/logger/log"
|
||||
)
|
||||
|
||||
// METResponse represents a response from
|
||||
@@ -62,14 +61,7 @@ type OSMData []struct {
|
||||
|
||||
var sendWeatherCh = make(chan struct{}, 1)
|
||||
|
||||
func sleepCtx(ctx context.Context, d time.Duration) {
|
||||
select {
|
||||
case <-time.After(d):
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
|
||||
func initWeather(ctx context.Context, wg WaitGroup, dev *infinitime.Device) error {
|
||||
func initWeather(ctx context.Context, dev *infinitime.Device) error {
|
||||
if !k.Bool("weather.enabled") {
|
||||
return nil
|
||||
}
|
||||
@@ -82,21 +74,14 @@ func initWeather(ctx context.Context, wg WaitGroup, dev *infinitime.Device) erro
|
||||
|
||||
timer := time.NewTimer(time.Hour)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done("weather")
|
||||
for {
|
||||
_, ok := <-ctx.Done()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Attempt to get weather
|
||||
data, err := getWeather(ctx, lat, lon)
|
||||
if err != nil {
|
||||
log.Warn("Error getting weather data").Err(err).Send()
|
||||
// Wait 15 minutes before retrying
|
||||
sleepCtx(ctx, 15*time.Minute)
|
||||
time.Sleep(15 * time.Minute)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -189,8 +174,6 @@ func initWeather(ctx context.Context, wg WaitGroup, dev *infinitime.Device) erro
|
||||
select {
|
||||
case <-timer.C:
|
||||
case <-sendWeatherCh:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user