refactor: flatten hash updates
This commit is contained in:
1
.dockerignore
Symbolic link
1
.dockerignore
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
./.gitignore
|
||||||
6
.env
6
.env
@@ -1,6 +0,0 @@
|
|||||||
KDOORPI_DOOR=workshop
|
|
||||||
KDOORPI_API_ALLOWED=http://127.0.0.1:3333/allowed
|
|
||||||
KDOORPI_API_LONGPOLL=http://127.0.0.1:3333/longpoll
|
|
||||||
KDOORPI_API_SWIPE=http://127.0.0.1:3333/cardswipe
|
|
||||||
KDOORPI_API_KEY=keykey
|
|
||||||
KDOORPI_MOCK_HW=true
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,3 +2,6 @@
|
|||||||
godoor
|
godoor
|
||||||
godoor_server/godoor_server
|
godoor_server/godoor_server
|
||||||
godoor_server/keys.json
|
godoor_server/keys.json
|
||||||
|
__debug_bin*
|
||||||
|
.env
|
||||||
|
.vscode
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mirror.gcr.io/library/golang:1.21-alpine as build
|
FROM mirror.gcr.io/library/golang:1.25-alpine AS build
|
||||||
RUN apk add ca-certificates
|
RUN apk add ca-certificates
|
||||||
|
|
||||||
WORKDIR /godoor
|
WORKDIR /godoor
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -1,9 +1,8 @@
|
|||||||
module godoor
|
module godoor
|
||||||
|
|
||||||
go 1.21
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/joho/godotenv v1.5.1
|
|
||||||
github.com/prometheus/client_golang v1.16.0
|
github.com/prometheus/client_golang v1.16.0
|
||||||
github.com/warthog618/gpiod v0.8.2
|
github.com/warthog618/gpiod v0.8.2
|
||||||
golang.org/x/crypto v0.12.0
|
golang.org/x/crypto v0.12.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -11,8 +11,6 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
|||||||
104
godoor.go
104
godoor.go
@@ -18,7 +18,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
@@ -33,18 +32,12 @@ const (
|
|||||||
solenoid_default = 21
|
solenoid_default = 21
|
||||||
)
|
)
|
||||||
|
|
||||||
type card struct {
|
type upstreamUpdate struct {
|
||||||
UidHash string `json:"uid_hash"`
|
AllowedHashes []string `json:"allowed_hashes"`
|
||||||
}
|
|
||||||
|
|
||||||
type cardList struct {
|
|
||||||
AllowedUids []struct {
|
|
||||||
Token card `json:"token"`
|
|
||||||
} `json:"allowed_uids"`
|
|
||||||
KeepOpenUntil *time.Time `json:"keep_open_until,omitempty"`
|
KeepOpenUntil *time.Time `json:"keep_open_until,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidUids map[string]bool // bool has no meaning
|
type ValidHashesT map[string]bool // bool has no meaning
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
door string
|
door string
|
||||||
@@ -90,11 +83,11 @@ var Commit = func() string {
|
|||||||
var Version string
|
var Version string
|
||||||
|
|
||||||
var (
|
var (
|
||||||
config Config
|
config Config
|
||||||
globalLock sync.Mutex
|
VALID_HASHES_LOCK sync.Mutex
|
||||||
validUids ValidUids
|
VALID_HASHES = make(ValidHashesT)
|
||||||
wiegand Wiegand
|
wiegand Wiegand
|
||||||
keepDoorOpen KeepDoorOpen
|
keepDoorOpen KeepDoorOpen
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -130,6 +123,7 @@ func main() {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
loadConfig()
|
loadConfig()
|
||||||
|
log.Printf("Door name: %s\n", config.door)
|
||||||
|
|
||||||
godoorBuildInfo.WithLabelValues(Version, Commit).Set(1)
|
godoorBuildInfo.WithLabelValues(Version, Commit).Set(1)
|
||||||
|
|
||||||
@@ -146,12 +140,6 @@ func main() {
|
|||||||
func loadConfig() {
|
func loadConfig() {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
log.Println("Loading .env config")
|
|
||||||
err = godotenv.Load()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to load .env config, using internal defaults")
|
|
||||||
}
|
|
||||||
|
|
||||||
config.door = os.Getenv("KDOORPI_DOOR")
|
config.door = os.Getenv("KDOORPI_DOOR")
|
||||||
config.api.allowed = os.Getenv("KDOORPI_API_ALLOWED")
|
config.api.allowed = os.Getenv("KDOORPI_API_ALLOWED")
|
||||||
config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL")
|
config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL")
|
||||||
@@ -189,8 +177,6 @@ func loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setup(ctx context.Context) {
|
func setup(ctx context.Context) {
|
||||||
log.Println("Started Setup")
|
|
||||||
|
|
||||||
if config.mock {
|
if config.mock {
|
||||||
log.Println("MOCK mode enabled")
|
log.Println("MOCK mode enabled")
|
||||||
if config.door == "" {
|
if config.door == "" {
|
||||||
@@ -208,7 +194,7 @@ func setup(ctx context.Context) {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
log.Println("Start initial token population")
|
log.Println("Start initial token population")
|
||||||
err := reloadTokens()
|
err := reloadInfo()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -230,9 +216,9 @@ func setup(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
go func() {
|
go func() {
|
||||||
err := reloadTokens()
|
err := reloadInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ReloadTokens failed: %q", err)
|
log.Printf("reloadTokens failed: %q", err)
|
||||||
apiFailuresCount.WithLabelValues("allowed", config.api.allowed).Inc()
|
apiFailuresCount.WithLabelValues("allowed", config.api.allowed).Inc()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -325,9 +311,9 @@ func cardRunner(w Wiegand) {
|
|||||||
hashedHex := hash.HashCardUid(card)
|
hashedHex := hash.HashCardUid(card)
|
||||||
log.Println(hashedHex)
|
log.Println(hashedHex)
|
||||||
|
|
||||||
globalLock.Lock()
|
VALID_HASHES_LOCK.Lock()
|
||||||
ok := validUids[hashedHex]
|
ok := VALID_HASHES[hashedHex]
|
||||||
globalLock.Unlock()
|
VALID_HASHES_LOCK.Unlock()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := sendSwipeEvent(hashedHex, ok)
|
err := sendSwipeEvent(hashedHex, ok)
|
||||||
@@ -416,12 +402,13 @@ func waitEvents() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reloadTokens() error {
|
func reloadInfo() error {
|
||||||
req, err := http.NewRequest(http.MethodGet, config.api.allowed, nil)
|
req, err := http.NewRequest(http.MethodGet, config.api.allowed, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
req.Header.Add("KEY", config.api.key)
|
req.Header.Add("KEY", config.api.key)
|
||||||
|
req.Header.Add("DOOR_NAME", config.door)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -430,32 +417,35 @@ func reloadTokens() error {
|
|||||||
log.Printf("%v\n", resp)
|
log.Printf("%v\n", resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cl cardList
|
var info upstreamUpdate
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(body, &cl)
|
err = json.Unmarshal(body, &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
globalLock.Lock()
|
// Update Allowed hashes
|
||||||
defer globalLock.Unlock()
|
validHashesPre := make(ValidHashesT)
|
||||||
validUids = make(ValidUids)
|
for _, hash := range info.AllowedHashes {
|
||||||
var totalCardCount int = 0
|
validHashesPre[hash] = true
|
||||||
for i, val := range cl.AllowedUids {
|
|
||||||
// log.Printf("%d: %+v\n", i, val.Token.UidHash)
|
|
||||||
validUids[val.Token.UidHash] = true
|
|
||||||
totalCardCount = i
|
|
||||||
}
|
}
|
||||||
log.Printf("Got %d cards from server", totalCardCount)
|
|
||||||
nrCardsInAllowList.Set(float64(totalCardCount))
|
|
||||||
|
|
||||||
if cl.KeepOpenUntil != nil {
|
VALID_HASHES_LOCK.Lock()
|
||||||
updateKeepOpenDoor(*cl.KeepOpenUntil)
|
VALID_HASHES = validHashesPre
|
||||||
|
VALID_HASHES_LOCK.Unlock()
|
||||||
|
|
||||||
|
log.Printf("Got %d cards from server", len(info.AllowedHashes))
|
||||||
|
nrCardsInAllowList.Set(float64(len(info.AllowedHashes)))
|
||||||
|
|
||||||
|
// Update Keep open
|
||||||
|
|
||||||
|
if info.KeepOpenUntil != nil {
|
||||||
|
updateKeepOpenDoor(*info.KeepOpenUntil)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSyncTimestamp.SetToCurrentTime()
|
lastSyncTimestamp.SetToCurrentTime()
|
||||||
@@ -463,32 +453,6 @@ func reloadTokens() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateKeepOpenDoor(newKeepOpenTime time.Time) {
|
|
||||||
// is there one active?
|
|
||||||
if keepDoorOpen.timer != nil {
|
|
||||||
keepDoorOpen.timer.Stop()
|
|
||||||
keepDoorOpen = KeepDoorOpen{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if newKeepOpenTime.After(time.Now()) {
|
|
||||||
log.Printf("Keeping door open until %v", newKeepOpenTime)
|
|
||||||
OpenDoor(wiegand)
|
|
||||||
timer := time.AfterFunc(time.Until(newKeepOpenTime), handleKeepDoorOpenCloseCleanup)
|
|
||||||
keepDoorOpen = KeepDoorOpen{
|
|
||||||
timer: timer,
|
|
||||||
until: newKeepOpenTime,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CloseDoor(wiegand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleKeepDoorOpenCloseCleanup() {
|
|
||||||
fmt.Println("Keep door open time is reached!")
|
|
||||||
CloseDoor(wiegand)
|
|
||||||
keepDoorOpen = KeepDoorOpen{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendSwipeEvent(cardUidHash string, success bool) error {
|
func sendSwipeEvent(cardUidHash string, success bool) error {
|
||||||
swipeEvent := map[string]any{
|
swipeEvent := map[string]any{
|
||||||
"uid_hash": cardUidHash,
|
"uid_hash": cardUidHash,
|
||||||
|
|||||||
33
keepopen.go
Normal file
33
keepopen.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func updateKeepOpenDoor(newKeepOpenTime time.Time) {
|
||||||
|
// is there one active?
|
||||||
|
if keepDoorOpen.timer != nil {
|
||||||
|
keepDoorOpen.timer.Stop()
|
||||||
|
keepDoorOpen = KeepDoorOpen{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if newKeepOpenTime.After(time.Now()) {
|
||||||
|
log.Printf("Keeping door open until %v", newKeepOpenTime)
|
||||||
|
OpenDoor(wiegand)
|
||||||
|
timer := time.AfterFunc(time.Until(newKeepOpenTime), handleKeepDoorOpenCloseCleanup)
|
||||||
|
keepDoorOpen = KeepDoorOpen{
|
||||||
|
timer: timer,
|
||||||
|
until: newKeepOpenTime,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CloseDoor(wiegand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleKeepDoorOpenCloseCleanup() {
|
||||||
|
fmt.Println("Keep door open time is reached!")
|
||||||
|
CloseDoor(wiegand)
|
||||||
|
keepDoorOpen = KeepDoorOpen{}
|
||||||
|
}
|
||||||
18
wiegand.go
18
wiegand.go
@@ -57,6 +57,7 @@ func (w *WiegandHW) IsDoorOpen() (bool, error) {
|
|||||||
defer w.lock.RUnlock()
|
defer w.lock.RUnlock()
|
||||||
return w.isDoorOpen()
|
return w.isDoorOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiegandHW) isDoorOpen() (bool, error) {
|
func (w *WiegandHW) isDoorOpen() (bool, error) {
|
||||||
i, err := w.solenoidLine.Value()
|
i, err := w.solenoidLine.Value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -90,19 +91,18 @@ func (w *WiegandHW) GetCardUid() (uint64, error) {
|
|||||||
func (w *WiegandHW) wiegandAEvent(evt gpiod.LineEvent) {
|
func (w *WiegandHW) wiegandAEvent(evt gpiod.LineEvent) {
|
||||||
w.bitTimeoutTimer.Reset(w.bitTimeout)
|
w.bitTimeoutTimer.Reset(w.bitTimeout)
|
||||||
w.bits[w.bitNr] = true
|
w.bits[w.bitNr] = true
|
||||||
//fmt.Printf("1")
|
// fmt.Printf("1")
|
||||||
w.bitNr += 1
|
w.bitNr += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiegandHW) wiegandBEvent(evt gpiod.LineEvent) {
|
func (w *WiegandHW) wiegandBEvent(evt gpiod.LineEvent) {
|
||||||
w.bitTimeoutTimer.Reset(w.bitTimeout)
|
w.bitTimeoutTimer.Reset(w.bitTimeout)
|
||||||
w.bits[w.bitNr] = false
|
w.bits[w.bitNr] = false
|
||||||
//fmt.Printf("0")
|
// fmt.Printf("0")
|
||||||
w.bitNr += 1
|
w.bitNr += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func WiegandSetup(a int, b int, bitTimeout time.Duration, solenoid int) *WiegandHW {
|
func WiegandSetup(a int, b int, bitTimeout time.Duration, solenoid int) *WiegandHW {
|
||||||
|
|
||||||
log.Printf("Wiegand GPIO-s: A:%d B:%d Solenoid:%d", a, b, solenoid)
|
log.Printf("Wiegand GPIO-s: A:%d B:%d Solenoid:%d", a, b, solenoid)
|
||||||
var wiegand WiegandHW
|
var wiegand WiegandHW
|
||||||
wiegand.bitTimeout = bitTimeout
|
wiegand.bitTimeout = bitTimeout
|
||||||
@@ -141,9 +141,9 @@ func (w *WiegandHW) WiegandClose() {
|
|||||||
w.solenoidLine.Close()
|
w.solenoidLine.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCardId(card uint64) {
|
// func printCardId(card uint64) {
|
||||||
for i := 0; i < 7; i++ {
|
// for i := 0; i < 7; i++ {
|
||||||
fmt.Printf("%02x", (card>>(8*i))&0xff)
|
// fmt.Printf("%02x", (card>>(8*i))&0xff)
|
||||||
}
|
// }
|
||||||
fmt.Printf("\n")
|
// fmt.Printf("\n")
|
||||||
}
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user