Checkpoint 3
This commit is contained in:
parent
2521a811f5
commit
172dbcc210
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
godoor
|
godoor
|
||||||
|
godoor_server/godoor_server
|
||||||
|
150
godoor.go
150
godoor.go
@ -2,11 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@ -31,17 +33,14 @@ type cardList struct {
|
|||||||
} `json:"allowed_uids"`
|
} `json:"allowed_uids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleUids struct {
|
|
||||||
tokens []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ValidUids map[string]bool // bool has no meaning
|
type ValidUids map[string]bool // bool has no meaning
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
door string
|
door string
|
||||||
uid_salt string
|
uidSalt string
|
||||||
mock string
|
doorOpenTime string
|
||||||
api struct {
|
mock bool
|
||||||
|
api struct {
|
||||||
allowed string
|
allowed string
|
||||||
longpoll string
|
longpoll string
|
||||||
swipe string
|
swipe string
|
||||||
@ -66,26 +65,29 @@ func main() {
|
|||||||
config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL")
|
config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL")
|
||||||
config.api.swipe = os.Getenv("KDOORPI_API_SWIPE")
|
config.api.swipe = os.Getenv("KDOORPI_API_SWIPE")
|
||||||
config.api.key = os.Getenv("KDOORPI_API_KEY")
|
config.api.key = os.Getenv("KDOORPI_API_KEY")
|
||||||
config.uid_salt = os.Getenv("KDOORPI_UID_SALT")
|
config.uidSalt = os.Getenv("KDOORPI_UID_SALT")
|
||||||
config.mock = os.Getenv("KDOORPI_MOCK_HW")
|
config.doorOpenTime = os.Getenv("KDOORPI_OPEN_TIME")
|
||||||
|
_, config.mock = os.LookupEnv("KDOORPI_MOCK_HW")
|
||||||
|
|
||||||
if config.mock == "true" {
|
go func() {
|
||||||
|
setup()
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
log.Printf("Cleanup\n")
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
}
|
||||||
|
func setup() {
|
||||||
|
log.Println("Started Setup")
|
||||||
|
|
||||||
|
if config.mock {
|
||||||
|
log.Println("MOCK mode enabled")
|
||||||
wiegand = &WiegandMock{}
|
wiegand = &WiegandMock{}
|
||||||
} else {
|
} else {
|
||||||
wiegand = WiegandSetup(wiegand_a, wiegand_b, wiegand_bit_timeout, solenoid)
|
wiegand = WiegandSetup(wiegand_a, wiegand_b, wiegand_bit_timeout, solenoid)
|
||||||
}
|
}
|
||||||
|
log.Println("HW Setup done")
|
||||||
http.DefaultClient.Timeout = 120 * time.Second
|
|
||||||
|
|
||||||
for {
|
|
||||||
err := reloadTokens()
|
|
||||||
if err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
go cardRunner(wiegand)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@ -93,12 +95,44 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fmt.Printf("Sleeping\n")
|
log.Println("Initialized longpoll event loop")
|
||||||
|
|
||||||
<-ctx.Done()
|
http.DefaultClient.Timeout = 120 * time.Second
|
||||||
fmt.Printf("Cleanup\n")
|
|
||||||
|
|
||||||
// cleanup
|
for {
|
||||||
|
log.Println("Start initial token population")
|
||||||
|
err := reloadTokens()
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("Initial token population failed. err: %v", err)
|
||||||
|
log.Println("Retrying in 10 seconds...")
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Initial token population success")
|
||||||
|
|
||||||
|
go cardRunner(wiegand)
|
||||||
|
|
||||||
|
log.Println("Setup completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func OpenAndCloseDoor(w Wiegand) error {
|
||||||
|
err := w.OpenDoor()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("Door is now open")
|
||||||
|
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
err = w.CloseDoor()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("Door is now closed")
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cardRunner(w Wiegand) {
|
func cardRunner(w Wiegand) {
|
||||||
@ -110,16 +144,26 @@ func cardRunner(w Wiegand) {
|
|||||||
|
|
||||||
printCardId(card)
|
printCardId(card)
|
||||||
hashedHex := hashCardUid(card)
|
hashedHex := hashCardUid(card)
|
||||||
fmt.Println(hashedHex)
|
log.Println(hashedHex)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := sendSwipeEvent(hashedHex)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to send swipe event: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
globalLock.Lock()
|
globalLock.Lock()
|
||||||
ok := validUids[hashedHex]
|
ok := validUids[hashedHex]
|
||||||
globalLock.Unlock()
|
globalLock.Unlock()
|
||||||
if ok {
|
if ok {
|
||||||
fmt.Println("Opening door")
|
log.Println("Opening door")
|
||||||
w.OpenDoor()
|
err := OpenAndCloseDoor(w)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("There was an error opening and closing the Door")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Unknown card")
|
log.Println("Unknown card")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -159,7 +203,7 @@ func waitEvents() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("%v\n", resp)
|
log.Printf("%v\n", resp)
|
||||||
|
|
||||||
reader := bufio.NewReader(resp.Body)
|
reader := bufio.NewReader(resp.Body)
|
||||||
for {
|
for {
|
||||||
@ -173,9 +217,12 @@ func waitEvents() error {
|
|||||||
if !found_data {
|
if !found_data {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("got server data: %q\n", data)
|
log.Printf("got server data: %q\n", data)
|
||||||
if strings.TrimSpace(data) == config.door {
|
if strings.TrimSpace(data) == config.door {
|
||||||
wiegand.OpenDoor()
|
err := OpenAndCloseDoor(wiegand)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("There was an error opening and closing the Door")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go reloadTokens()
|
go reloadTokens()
|
||||||
@ -183,7 +230,7 @@ func waitEvents() error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%v\n", resp)
|
log.Printf("%v\n", resp)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +244,7 @@ func reloadTokens() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("%v\n", resp)
|
log.Printf("%v\n", resp)
|
||||||
|
|
||||||
var cl cardList
|
var cl cardList
|
||||||
|
|
||||||
@ -215,9 +262,38 @@ func reloadTokens() error {
|
|||||||
defer globalLock.Unlock()
|
defer globalLock.Unlock()
|
||||||
validUids = make(ValidUids)
|
validUids = make(ValidUids)
|
||||||
for i, val := range cl.AllowedUids {
|
for i, val := range cl.AllowedUids {
|
||||||
fmt.Printf("%d: %+v\n", i, val.Token.UidHash)
|
log.Printf("%d: %+v\n", i, val.Token.UidHash)
|
||||||
validUids[val.Token.UidHash] = true
|
validUids[val.Token.UidHash] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendSwipeEvent(cardUidHash string) error {
|
||||||
|
swipeEvent := map[string]string{
|
||||||
|
"uid_hash": cardUidHash,
|
||||||
|
"door": config.door,
|
||||||
|
"timestamp": time.Now().Format(time.DateTime),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(swipeEvent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, config.api.swipe, bytes.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Add("KEY", config.api.key)
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
|
||||||
|
return fmt.Errorf("Server responded with %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -38,7 +38,7 @@ func getAllowed(w http.ResponseWriter, r *http.Request) {
|
|||||||
keys := cardList{
|
keys := cardList{
|
||||||
AllowedUids: []cardToken{
|
AllowedUids: []cardToken{
|
||||||
{card{UidHash: "d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705"}},
|
{card{UidHash: "d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705"}},
|
||||||
{card{UidHash: "112233445566"}},
|
{card{UidHash: "873636abbcf597a4835afc1c9b16a72eb6175b7ab278a8f18ab13c50172c90ea97cc3e258efd9cc1d885d7ea32d87fd006907892793e7cd6c468417bd8b8421a"}},
|
||||||
{card{UidHash: "aabbccddeeff"}},
|
{card{UidHash: "aabbccddeeff"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -114,6 +114,10 @@ func (doobserver *DoorBoyServer) postOpenDoor(w http.ResponseWriter, r *http.Req
|
|||||||
w.Write([]byte("OK"))
|
w.Write([]byte("OK"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func postCardSwipe(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
doorboyserver := DoorBoyServer{longPollers: map[string]chan string{}}
|
doorboyserver := DoorBoyServer{longPollers: map[string]chan string{}}
|
||||||
http.HandleFunc("/", getRoot)
|
http.HandleFunc("/", getRoot)
|
||||||
@ -121,6 +125,7 @@ func main() {
|
|||||||
http.HandleFunc("/longpoll", doorboyserver.getLongPoll)
|
http.HandleFunc("/longpoll", doorboyserver.getLongPoll)
|
||||||
http.HandleFunc("/jspoll", doorboyserver.getLongPollJson)
|
http.HandleFunc("/jspoll", doorboyserver.getLongPollJson)
|
||||||
http.HandleFunc("/open", doorboyserver.postOpenDoor)
|
http.HandleFunc("/open", doorboyserver.postOpenDoor)
|
||||||
|
http.HandleFunc("/cardswipe", postCardSwipe)
|
||||||
|
|
||||||
err := http.ListenAndServe(":3333", nil)
|
err := http.ListenAndServe(":3333", nil)
|
||||||
|
|
||||||
|
30
wiegand.go
30
wiegand.go
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/crypto/scrypt"
|
"golang.org/x/crypto/scrypt"
|
||||||
|
"log"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,7 +15,9 @@ import (
|
|||||||
|
|
||||||
type Wiegand interface {
|
type Wiegand interface {
|
||||||
GetCardUid() (uint64, error)
|
GetCardUid() (uint64, error)
|
||||||
OpenDoor()
|
OpenDoor() error
|
||||||
|
CloseDoor() error
|
||||||
|
IsDoorOpen() (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type WiegandHW struct {
|
type WiegandHW struct {
|
||||||
@ -28,15 +31,21 @@ type WiegandHW struct {
|
|||||||
solenoidLine *gpiod.Line
|
solenoidLine *gpiod.Line
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiegandHW) OpenDoor() {
|
func (w *WiegandHW) OpenDoor() error {
|
||||||
fmt.Println("Open")
|
return w.solenoidLine.SetValue(1)
|
||||||
w.solenoidLine.SetValue(1)
|
|
||||||
d, _ := time.ParseDuration("500ms")
|
|
||||||
time.Sleep(d)
|
|
||||||
w.solenoidLine.SetValue(0)
|
|
||||||
fmt.Println("Close")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WiegandHW) CloseDoor() error {
|
||||||
|
return w.solenoidLine.SetValue(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WiegandHW) IsDoorOpen() (bool, error) {
|
||||||
|
i, err := w.solenoidLine.Value()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return i == 1, nil
|
||||||
|
}
|
||||||
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)
|
||||||
@ -47,7 +56,7 @@ func printCardId(card uint64) {
|
|||||||
func hashCardUid(card uint64) string {
|
func hashCardUid(card uint64) string {
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
binary.LittleEndian.PutUint64(b, card)
|
binary.LittleEndian.PutUint64(b, card)
|
||||||
hashed, err := scrypt.Key(b, []byte(config.uid_salt), 16384, 8, 1, 64)
|
hashed, err := scrypt.Key(b, []byte(config.uidSalt), 16384, 8, 1, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // can only happen when scrypt params are garbage
|
panic(err) // can only happen when scrypt params are garbage
|
||||||
}
|
}
|
||||||
@ -58,10 +67,9 @@ func hashCardUid(card uint64) string {
|
|||||||
|
|
||||||
func (w *WiegandHW) GetCardUid() (uint64, error) {
|
func (w *WiegandHW) GetCardUid() (uint64, error) {
|
||||||
// Wait for bit timeout
|
// Wait for bit timeout
|
||||||
fmt.Printf("Waiting for bit timeout\n")
|
log.Printf("Waiting for bit timeout\n")
|
||||||
|
|
||||||
<-w.bitTimeoutTimer.C
|
<-w.bitTimeoutTimer.C
|
||||||
fmt.Printf("\n")
|
|
||||||
|
|
||||||
defer func() { w.bitNr = 0 }()
|
defer func() { w.bitNr = 0 }()
|
||||||
|
|
||||||
|
@ -1,23 +1,32 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WiegandMock struct {
|
type WiegandMock struct {
|
||||||
mockUid uint64
|
mockUid uint64
|
||||||
|
|
||||||
|
openState bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*WiegandMock) OpenDoor() {
|
func (w *WiegandMock) OpenDoor() error {
|
||||||
fmt.Println("Door is now open")
|
w.openState = true
|
||||||
time.Sleep(500 * time.Millisecond)
|
return nil
|
||||||
fmt.Println("Door is now closed")
|
}
|
||||||
|
|
||||||
|
func (w *WiegandMock) CloseDoor() error {
|
||||||
|
w.openState = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WiegandMock) IsDoorOpen() (bool, error) {
|
||||||
|
return w.openState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiegandMock) GetCardUid() (uint64, error) {
|
func (w *WiegandMock) GetCardUid() (uint64, error) {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
return w.mockUid, fmt.Errorf("err")
|
return w.mockUid, nil //fmt.Errorf("err")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiegandMock) SetMockUid(mockUid uint64) {
|
func (w *WiegandMock) SetMockUid(mockUid uint64) {
|
||||||
|
Loading…
Reference in New Issue
Block a user