diff --git a/.env b/.env new file mode 100644 index 0000000..5eb2fc8 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +KDOORPI_API_ALLOWED=http://127.0.0.1:3333/allowed +KDOORPI_API_LONGPOLL=http://127.0.0.1:3333/longpoll +KDOORPI_API_KEY=keykey diff --git a/go.mod b/go.mod index 4bc03e1..652424c 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module godoor go 1.18 require ( + github.com/joho/godotenv v1.5.1 // indirect github.com/warthog618/gpiod v0.8.0 // indirect golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect diff --git a/go.sum b/go.sum index b809ab9..116fd91 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/warthog618/gpiod v0.8.0 h1:qxH9XVvWHpTxzWFSndBcujFyNH5zVRzHM63tcmm85o4= github.com/warthog618/gpiod v0.8.0/go.mod h1:a7Csa+IJtDBZ39++zC/6Srjo01qWejt/5velrDWuNkY= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= diff --git a/godoor.go b/godoor.go index d844af4..eb6e127 100644 --- a/godoor.go +++ b/godoor.go @@ -1,10 +1,15 @@ package main import ( + "context" "encoding/json" "fmt" + "github.com/joho/godotenv" "io" "net/http" + "os" + "os/signal" + "syscall" ) import "time" @@ -17,27 +22,91 @@ type card struct { UidHash string `json:"uid_hash"` } -type cardToken struct { - Token card `json:"token"` +type cardList struct { + AllowedUids []struct { + Token card `json:"token"` + } `json:"allowed_uids"` } -type cardList struct { - AllowedUids []cardToken `json:"allowed_uids"` +type simpleUids struct { + tokens []string } type ValidUids map[string]bool // bool has no meaning +type Config struct { + door string + uid_salt string + api struct { + allowed string + longpoll string + swipe string + key string + } +} + +var config Config + func main() { - wiegand := WiegandSetup(wiegand_a, wiegand_b, wiegand_bit_timeout, solenoid) + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer cancel() - client := http.Client{} - req, err := http.NewRequest(http.MethodGet, "urlrul", nil) + godotenv.Load() + + config.door = os.Getenv("KDOORPI_DOOR") + config.api.allowed = os.Getenv("KDOORPI_API_ALLOWED") + config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL") + config.api.swipe = os.Getenv("KDOORPI_API_SWIPE") + config.api.key = os.Getenv("KDOORPI_API_KEY") + config.uid_salt = os.Getenv("KDOORPI_UID_SALT") + + //wiegand := WiegandSetup(wiegand_a, wiegand_b, wiegand_bit_timeout, solenoid) + + http.DefaultClient.Timeout = 60 + + reloadTokens() + + //go wiegand.cardRunner(validUids) + + waitEvents() + + fmt.Printf("Sleeping\n") + + <-ctx.Done() + fmt.Printf("Cleanup\n") + + // cleanup +} + +func waitEvents() { + req, err := http.NewRequest(http.MethodGet, config.api.longpoll, nil) if err != nil { panic(err) } - req.Header.Add("KEY", "keykey") - resp, err := client.Do(req) + req.Header.Add("KEY", config.api.key) + resp, err := http.DefaultClient.Do(req) + if err != nil { + panic(err) + } + fmt.Printf("%v\n", resp) + + _, err = io.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + fmt.Printf("%v\n", resp) + +} + +func reloadTokens() { + req, err := http.NewRequest(http.MethodGet, config.api.allowed, nil) + if err != nil { + panic(err) + } + req.Header.Add("KEY", config.api.key) + resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } @@ -60,13 +129,4 @@ func main() { fmt.Printf("%d: %+v\n", i, val.Token.UidHash) validUids[val.Token.UidHash] = false } - - go wiegand.cardRunner(validUids) - - fmt.Printf("Sleeping\n") - - for { - time.Sleep(time.Second) - fmt.Printf(".") - } } diff --git a/godoor_server/godoor_server.go b/godoor_server/godoor_server.go new file mode 100644 index 0000000..558bb29 --- /dev/null +++ b/godoor_server/godoor_server.go @@ -0,0 +1,118 @@ +// really stupid test door server + +package main + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" +) + +type DoorBoyServer struct { + longPollers map[string]chan string +} + +type card struct { + UidHash string `json:"uid_hash"` +} + +type cardToken struct { + Token card `json:"token"` +} + +type cardList struct { + AllowedUids []cardToken `json:"allowed_uids"` +} + +func getRoot(w http.ResponseWriter, r *http.Request) { + fmt.Printf("got / request\n") + io.WriteString(w, "This is my website!\n") +} + +func getAllowed(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + keys := cardList{ + AllowedUids: []cardToken{ + {card{UidHash: "0a0b0c0d0e0f"}}, + {card{UidHash: "112233445566"}}, + {card{UidHash: "aabbccddeeff"}}, + }, + } + respJson, _ := json.Marshal(keys) + _, err := w.Write(respJson) + if err != nil { + return + } +} + +func writeAndFlush(writer http.ResponseWriter, buffer []byte) error { + _, err := writer.Write(buffer) + if err != nil { + return err + } + if f, ok := writer.(http.Flusher); ok { + f.Flush() + } + return nil +} + +func (doorboyserver *DoorBoyServer) getLongPoll(w http.ResponseWriter, r *http.Request) { + err := writeAndFlush(w, []byte("data: response-generator-started\n\n")) + if err != nil { + return + } + events := make(chan string) + doorboyserver.longPollers[r.RemoteAddr] = events + err = writeAndFlush(w, []byte("data: watch-stream-opened\n\n")) + if err != nil { + delete(doorboyserver.longPollers, r.RemoteAddr) + return + } + d := <-events // get door open event + _, err = w.Write([]byte("data: ")) + if err != nil { + delete(doorboyserver.longPollers, r.RemoteAddr) + return + } + _, err = w.Write([]byte(d)) + if err != nil { + delete(doorboyserver.longPollers, r.RemoteAddr) + return + } + err = writeAndFlush(w, []byte("\n\n")) + if err != nil { + delete(doorboyserver.longPollers, r.RemoteAddr) + return + } + delete(doorboyserver.longPollers, r.RemoteAddr) + +} + +func (doobserver *DoorBoyServer) postOpenDoor(w http.ResponseWriter, r *http.Request) { + fmt.Println("longPollers:") + for key, value := range doobserver.longPollers { + fmt.Println(" Key:", key, "Value:", value) + value <- "workshop" + } + w.Write([]byte("OK")) +} + +func main() { + doorboyserver := DoorBoyServer{longPollers: map[string]chan string{}} + http.HandleFunc("/", getRoot) + http.HandleFunc("/allowed", getAllowed) + http.HandleFunc("/longpoll", doorboyserver.getLongPoll) + http.HandleFunc("/open", doorboyserver.postOpenDoor) + + err := http.ListenAndServe(":3333", nil) + + if errors.Is(err, http.ErrServerClosed) { + fmt.Printf("server closed\n") + } else if err != nil { + fmt.Printf("error starting server: %s\n", err) + os.Exit(1) + } +}