Commit ea1708f4 authored by Mikhail Kotelnikov's avatar Mikhail Kotelnikov
Browse files

. Init

parents
# Vim temp files
.*.sw[a-z]
gatekeeper
gatekeeper.conf
BINARY=gatekeeper
SOURCES=main.go lock.go openTime.go gpio.go cfg.go
all: $(BINARY)
./$(BINARY)
$(BINARY): $(SOURCES) clean
go build -o $(BINARY) $(SOURCES)
arm: $(SOURCES) clean
GOOS=linux GOARCH=arm go build -o $(BINARY) $(SOURCES)
scp $(BINARY) gatekeeper:
clean:
rm -f $(BINARY)
package main
import (
"os"
"log"
"encoding/json"
)
type Cfg struct {
Debug bool
DoorOpenTime int
SensorLockDelay int
SensorUnlockDelay int
HttpPort int
Gpio struct {
Lock int
Sensor int
Led int
}
Auth map[string]string
}
func (c *Cfg) init () {
c.DoorOpenTime = 10
c.SensorLockDelay = 300
c.SensorUnlockDelay = 5
c.HttpPort = 8080
var file *os.File
var err error
paths := []string{"/etc", "/usr/local/etc", "/usr/local/gatekeeper/etc", "."}
for _, path := range paths {
file, err = os.Open(path + "/gatekeeper.conf")
if err == nil {
break
}
}
if err != nil {
log.Fatal("Couldn't find config file [/etc/gatekeeper.conf, /usr/local/etc/gatekeeper.conf, /usr/local/gatekeeper/etc/gatekeeper.conf, ./gatekeeper.cfg]")
}
defer file.Close()
decoder := json.NewDecoder(file)
err = decoder.Decode(&cfg)
if err != nil {
log.Fatal(err)
}
}
{
"debug": false,
"httpPort": 8080,
"doorOpenTimeComment": "How long to hold the door opened (seconds)",
"doorOpenTime": 10,
"sensorLockDelayComment": "Delay between sensor locking and door unlocking (milliseconds)",
"sensorLockDelay": 300,
"sensorUnlockDelayComment": "How long to hold the door sensor locked after closing the lock (seconds)",
"sensorUnlockDelay": 5,
"gpioComment": "GPIO addresses (NO DEFAULTS)",
"gpio": {
"lock": 100,
"sensor": 101,
"led": 102
},
"authComment": "Authentication tokens",
"auth": {
"jarOwghopEshCopWuWodOgJikjuNoimWarjabild": "user1",
"LaniarUcShauchevparolyagAtPenOkgeusyart\\": "user2",
"UmugHocabDoBlofuckyajvacidEcFivCejFilvar": "user3",
"KolbOgWozevlekKajfejellaghefElcigTyashot": "user4"
}
}
package main
import (
"os"
"strconv"
"log"
)
type Gpio struct {
gpioPath string
}
func (g *Gpio) init () {
g.gpioPath = "/sys/class/gpio/gpio"
}
func (g *Gpio) Set (num, val int) {
// gpioPath := "test/"
gpioValPath := g.gpioPath + strconv.Itoa(num) + "/value"
file, err := os.OpenFile(gpioValPath, os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// log.Println("Writing", val, "to file", gpioValPath)
bytes := []byte(strconv.Itoa(val))
file.Write(bytes)
// log.Println("Written", written, "bytes.", "err =", err)
}
func (g *Gpio) On (num int) {
g.Set(num, 1)
}
func (g *Gpio) Off (num int) {
g.Set(num, 0)
}
package main
import "sync"
type Lock struct {
sync.Mutex
locked bool
}
func (l *Lock) init () {
l.locked = false
}
func (l *Lock) lock () bool {
l.Lock()
defer l.Unlock()
if l.locked {
return false
}
l.locked = true
return true
}
func (l *Lock) unlock () {
l.Lock()
defer l.Unlock()
l.locked = false
}
package main
import (
"log"
"strconv"
"github.com/gin-gonic/gin"
"time"
"net/http"
)
var cfg Cfg
var lock Lock
var openTime OpenTime
var gpio Gpio
func openDoor () {
if !lock.lock() {
log.Println("Door is unlocked now")
openTime.enlarge()
return
}
defer lock.unlock()
openTime.init()
gpio.On(cfg.Gpio.Sensor)
log.Println("Sensor locked")
time.Sleep(time.Duration(cfg.SensorLockDelay) * time.Millisecond)
for openTime.available() {
gpio.On(cfg.Gpio.Lock)
log.Println("Door unlocked")
for ; openTime.available(); openTime.tick() {
gpio.On(cfg.Gpio.Led)
time.Sleep(500 * time.Millisecond)
gpio.Off(cfg.Gpio.Led)
time.Sleep(500 * time.Millisecond)
}
gpio.Off(cfg.Gpio.Lock)
log.Println("Door locked")
for i := 0; i < cfg.SensorUnlockDelay * 10 && !openTime.available(); i++ {
time.Sleep(100 * time.Millisecond)
}
}
gpio.Off(cfg.Gpio.Sensor)
log.Println("Sensor unlocked")
}
func setupRouter() *gin.Engine {
// Disable Console Color
// gin.DisableConsoleColor()
r := gin.Default()
// Get user value
r.GET("/:token", func(c *gin.Context) {
token := c.Params.ByName("token")
user, ok := cfg.Auth[token]
if ok {
log.Println("User", user, "requested the door opening")
go openDoor()
} else {
if token != "" {
log.Println("Unknown token:", token)
}
c.AbortWithStatus(http.StatusNotFound)
}
})
return r
}
func main () {
lock.init()
gpio.init()
cfg.init()
if !cfg.Debug {
gin.SetMode(gin.ReleaseMode)
}
r := setupRouter()
// Listen and Server in 0.0.0.0:cfg.HttpPort
r.Run(":" + strconv.Itoa(cfg.HttpPort))
}
package main
import "sync"
type OpenTime struct {
sync.Mutex
time, maxTime int
}
func (ot *OpenTime) init () {
ot.Lock()
defer ot.Unlock()
ot.time = 0
ot.maxTime = cfg.DoorOpenTime
}
func (ot *OpenTime) enlarge () {
ot.Lock()
defer ot.Unlock()
if ot.maxTime - ot.time < cfg.DoorOpenTime {
ot.maxTime += cfg.DoorOpenTime
}
}
func (ot *OpenTime) available () bool {
ot.Lock()
defer ot.Unlock()
return ot.time < ot.maxTime
}
func (ot *OpenTime) tick () {
ot.Lock()
defer ot.Unlock()
ot.time += 1
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment