mirror of
https://github.com/sascha-hemi/spaceDevices.git
synced 2026-03-21 03:04:20 +01:00
adds more tests, help and some fixes
This commit is contained in:
@@ -1,28 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/ktt-ol/spaceDevices/conf"
|
||||
"github.com/ktt-ol/spaceDevices/db"
|
||||
"github.com/ktt-ol/spaceDevices/mqtt"
|
||||
"github.com/ktt-ol/spaceDevices/webService"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const CONFIG_FILE = "config.toml"
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.TextFormatter{DisableColors: true})
|
||||
|
||||
config := conf.LoadConfig(CONFIG_FILE)
|
||||
|
||||
setupLogging(config.Misc)
|
||||
|
||||
//spaceDevices.EnableMqttDebugLogging()
|
||||
|
||||
userDb := db.NewUserDb(config.MacDb)
|
||||
masterDb := db.NewMasterDb(config.MacDb)
|
||||
|
||||
mqttHandler := mqtt.NewMqttHandler(config.Mqtt)
|
||||
data := mqtt.NewDeviceData(mqttHandler, masterDb, userDb)
|
||||
data := mqtt.NewDeviceData(config.Locations, mqttHandler, masterDb, userDb)
|
||||
|
||||
webService.StartWebService(config.Server, data, userDb)
|
||||
}
|
||||
|
||||
type StdErrLogHook struct {
|
||||
}
|
||||
|
||||
func (h *StdErrLogHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{logrus.WarnLevel, logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}
|
||||
}
|
||||
func (h *StdErrLogHook) Fire(entry *logrus.Entry) error {
|
||||
line, err := entry.String()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, line)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupLogging(config conf.MiscConf) {
|
||||
logrus.SetFormatter(&logrus.TextFormatter{DisableColors: true})
|
||||
if config.DebugLogging {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
} else {
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
|
||||
if config.Logfile == "" {
|
||||
logrus.SetOutput(os.Stdout)
|
||||
} else {
|
||||
// https://github.com/sirupsen/logrus/issues/227
|
||||
file, err := os.OpenFile(config.Logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
|
||||
if err == nil {
|
||||
logrus.SetOutput(file)
|
||||
} else {
|
||||
logrus.Warnf("Failed to log to file '%s', using default stderr.", config.Logfile)
|
||||
}
|
||||
logrus.AddHook(&StdErrLogHook{})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,18 @@ func LoadConfig(configFile string) TomlConfig {
|
||||
}
|
||||
|
||||
type TomlConfig struct {
|
||||
Misc MiscConf
|
||||
Server ServerConf
|
||||
MacDb MacDbConf
|
||||
Mqtt MqttConf
|
||||
Locations []Location `toml:"location"`
|
||||
}
|
||||
|
||||
type MiscConf struct {
|
||||
DebugLogging bool
|
||||
Logfile string
|
||||
}
|
||||
|
||||
type ServerConf struct {
|
||||
Host string
|
||||
Port int
|
||||
|
||||
@@ -11,6 +11,8 @@ func Test_exampleConfig(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
config := conf.LoadConfig("../config.example.toml")
|
||||
assert.Equal(false, config.Misc.DebugLogging)
|
||||
assert.Equal("", config.Misc.Logfile)
|
||||
assert.Equal(2, len(config.Locations))
|
||||
assert.Equal("Bar", config.Locations[0].Name)
|
||||
assert.Equal(2, len(config.Locations[0].Ids))
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# COPY THIS TO config.toml
|
||||
[misc]
|
||||
debugLogging = false
|
||||
# if enabled, all logging goes to the file. Warn and up goes to stderr, too.
|
||||
# logfile = "/var/log/spaceDevices2.log"
|
||||
|
||||
[server]
|
||||
host = "0.0.0.0"
|
||||
|
||||
@@ -9,4 +9,6 @@ func Test_IsMacLocallyAdministered(t *testing.T) {
|
||||
assert.True(t, IsMacLocallyAdministered("06:00:00:00:00:00"))
|
||||
assert.True(t, IsMacLocallyAdministered("62:01:0f:b5:f2:d9"))
|
||||
assert.False(t, IsMacLocallyAdministered("20:c9:d0:7a:fa:31"))
|
||||
|
||||
assert.True(t, IsMacLocallyAdministered("d4:38:9c:01:dd:03"))
|
||||
}
|
||||
|
||||
3
do.sh
3
do.sh
@@ -15,6 +15,9 @@ while (( "$#" )); do
|
||||
build-linux)
|
||||
env GOOS=linux GOARCH=amd64 go build cmd/spaceDevices.go
|
||||
;;
|
||||
test-sync)
|
||||
rsync -n -avzi --delete spaceDevices webUI root@spacegate:/home/status/spaceDevices2/
|
||||
;;
|
||||
sync)
|
||||
rsync -avzi --delete spaceDevices webUI root@spacegate:/home/status/spaceDevices2/
|
||||
;;
|
||||
|
||||
@@ -2,12 +2,15 @@ package mqtt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ktt-ol/spaceDevices/conf"
|
||||
"github.com/ktt-ol/spaceDevices/db"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"sort"
|
||||
)
|
||||
|
||||
var ignoredVisibility = [...]db.Visibility{db.VisibilityCriticalInfrastructure, db.VisibilityImportantInfrastructure,
|
||||
@@ -27,6 +30,9 @@ type DeviceData struct {
|
||||
masterDb db.MasterDb
|
||||
userDb db.UserDb
|
||||
wifiSessionList []WifiSession
|
||||
|
||||
lastSentHash []byte
|
||||
|
||||
// more to come, e.g. LanSessions
|
||||
}
|
||||
|
||||
@@ -44,12 +50,32 @@ func NewDeviceData(locations []conf.Location, mqttHandler *MqttHandler, masterDb
|
||||
}
|
||||
|
||||
func (d *DeviceData) newData(data []byte) {
|
||||
fmt.Println("got data, len ", len(data))
|
||||
sessionsList, peopleAndDevices, ok := d.parseWifiSessions(data)
|
||||
if ok {
|
||||
d.wifiSessionList = sessionsList
|
||||
fmt.Printf("peopleAndDevices: %+v\n", peopleAndDevices)
|
||||
d.mqttHandler.SendPeopleAndDevices(peopleAndDevices)
|
||||
if ddLogger.Logger.Level >= logrus.DebugLevel {
|
||||
people := make(map[string]interface{})
|
||||
for _, p := range peopleAndDevices.People {
|
||||
people[p.Name] = nil
|
||||
}
|
||||
peopleList := make([]string, len(people))
|
||||
for k, _ := range people {
|
||||
peopleList = append(peopleList, k)
|
||||
}
|
||||
sort.Strings(peopleList)
|
||||
ddLogger.Debugf("PeopleCount: %d, DeviceCount: %d, UnknownDevicesCount: %d, Persons: %s",
|
||||
peopleAndDevices.PeopleCount, peopleAndDevices.DeviceCount, peopleAndDevices.UnknownDevicesCount, peopleList)
|
||||
}
|
||||
h := md5.New()
|
||||
s := fmt.Sprintf("%v", peopleAndDevices)
|
||||
hash := h.Sum([]byte(s))
|
||||
if bytes.Equal(hash, d.lastSentHash) {
|
||||
ddLogger.Debug("Nothing changed in people count, skipping mqtt")
|
||||
} else {
|
||||
d.mqttHandler.SendPeopleAndDevices(peopleAndDevices)
|
||||
d.lastSentHash = hash
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,11 +165,13 @@ SESSION_LOOP:
|
||||
var person Person
|
||||
if devicesEntry.showDevices {
|
||||
person = Person{Name: username, Devices: devicesEntry.devices}
|
||||
sort.Sort(DevicesSorter(person.Devices))
|
||||
} else {
|
||||
person = Person{Name: username}
|
||||
}
|
||||
peopleAndDevices.People = append(peopleAndDevices.People, person)
|
||||
}
|
||||
sort.Sort(PersonSorter(peopleAndDevices.People))
|
||||
|
||||
success = true
|
||||
return
|
||||
|
||||
@@ -189,10 +189,21 @@ func Test_peopleCalculation(t *testing.T) {
|
||||
entry.Visibility = db.VisibilityCriticalInfrastructure
|
||||
masterMap["00:00:00:00:00:05"] = entry
|
||||
_, peopleAndDevices, _ = dd.parseWifiSessions(testData)
|
||||
fmt.Printf("peopleAndDevices: %+v\n", peopleAndDevices)
|
||||
assertPeopleAndDevices(assert, 2, 3, 5, 0, peopleAndDevices)
|
||||
|
||||
t.Fail()
|
||||
// add a second device for olaf
|
||||
testData = newSessionTestData(stt("1", "01"), stt("2", "02"), stt("3", "03"), stt("4", "04"), stt("5", "05"), stt("6", "06"))
|
||||
userMap["00:00:00:00:00:06"] = db.UserDbEntry{Name: "olaf", DeviceName: "mac", Visibility: db.VisibilityAll}
|
||||
_, peopleAndDevices, _ = dd.parseWifiSessions(testData)
|
||||
fmt.Printf("peopleAndDevices: %+v\n", peopleAndDevices)
|
||||
assertPeopleAndDevices(assert, 2, 3, 6, 0, peopleAndDevices)
|
||||
for _, p := range peopleAndDevices.People {
|
||||
if p.Name == "olaf" {
|
||||
assert.Equal(2, len(p.Devices))
|
||||
} else {
|
||||
assert.Equal(0, len(p.Devices))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertPeopleAndDevices(assert *assert.Assertions, peopleArrayCount int, peopleCount uint, deviceCount uint, unknownDevicesCount uint, test PeopleAndDevices) {
|
||||
|
||||
13
mqtt/mqtt.go
13
mqtt/mqtt.go
@@ -16,7 +16,8 @@ const CLIENT_ID = "spaceDevices2"
|
||||
const TOPIC_SESSIONS = "/net/wlan-sessions"
|
||||
|
||||
// ATTENTION: test topic!
|
||||
const TOPIC_DEVICES = "/test/net_devices"
|
||||
//const TOPIC_DEVICES = "/test/net_devices"
|
||||
const TOPIC_DEVICES = "/net/devices"
|
||||
|
||||
var mqttLogger = log.WithField("where", "mqtt")
|
||||
|
||||
@@ -108,7 +109,7 @@ func (h *MqttHandler) onConnect(client mqtt.Client) {
|
||||
err := subscribe(client, TOPIC_SESSIONS,
|
||||
func(client mqtt.Client, message mqtt.Message) {
|
||||
mqttLogger.Debug("new wifi sessions")
|
||||
/*
|
||||
///*
|
||||
mock := []byte(`{ "38134": {
|
||||
"last-auth": 1509211121,
|
||||
"vlan": "default",
|
||||
@@ -126,7 +127,7 @@ func (h *MqttHandler) onConnect(client mqtt.Client) {
|
||||
"last-snr": 47,
|
||||
"last-rate-mbits": "6",
|
||||
"ap": 1,
|
||||
"mac": "10:68:3f:bb:bb:bb",
|
||||
"mac": "d4:38:9c:01:dd:03",
|
||||
"radio": 2,
|
||||
"userinfo": {
|
||||
"name": "Holger",
|
||||
@@ -137,10 +138,10 @@ func (h *MqttHandler) onConnect(client mqtt.Client) {
|
||||
"last-rssi-dbm": -48,
|
||||
"last-activity": 1509211584
|
||||
}}`)
|
||||
*/
|
||||
//*/
|
||||
select {
|
||||
// case h.newDataChan <- mock:
|
||||
case h.newDataChan <- message.Payload():
|
||||
case h.newDataChan <- mock:
|
||||
//case h.newDataChan <- message.Payload():
|
||||
break
|
||||
default:
|
||||
mqttLogger.Println("No one receives the message.")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package mqtt
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type WifiSession struct {
|
||||
Ip string
|
||||
Mac string
|
||||
@@ -12,14 +16,38 @@ type Devices struct {
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
type DevicesSorter []Devices
|
||||
|
||||
func (s DevicesSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s DevicesSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
func (s DevicesSorter) Less(i, j int) bool {
|
||||
return strings.Compare(s[i].Name, s[j].Name) < 0
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Devices []Devices `json:"devices"`
|
||||
}
|
||||
|
||||
type PersonSorter []Person
|
||||
|
||||
func (s PersonSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s PersonSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
func (s PersonSorter) Less(i, j int) bool {
|
||||
return strings.Compare(s[i].Name, s[j].Name) < 0
|
||||
}
|
||||
|
||||
type PeopleAndDevices struct {
|
||||
People []Person `json:"people"`
|
||||
PeopleCount uint `json:"peopleCount"`
|
||||
DeviceCount uint `json:"deviceCount"`
|
||||
UnknownDevicesCount uint `json:"unknownDevicesCount"`
|
||||
PeopleCount uint16 `json:"peopleCount"`
|
||||
DeviceCount uint16 `json:"deviceCount"`
|
||||
UnknownDevicesCount uint16 `json:"unknownDevicesCount"`
|
||||
}
|
||||
|
||||
@@ -60,12 +60,12 @@ func overviewPageHandler(c *gin.Context) {
|
||||
isLocallyAdministered := false
|
||||
macNotFound := false
|
||||
if info, ok := devices.GetByIp(ip); ok {
|
||||
mac = info.Mac
|
||||
isLocallyAdministered = db.IsMacLocallyAdministered(mac)
|
||||
if userInfo, ok := macDb.Get(info.Mac); ok {
|
||||
mac = info.Mac
|
||||
name = userInfo.Name
|
||||
deviceName = userInfo.DeviceName
|
||||
visibility = userInfo.Visibility
|
||||
isLocallyAdministered = db.IsMacLocallyAdministered(mac)
|
||||
}
|
||||
} else {
|
||||
macNotFound = true
|
||||
|
||||
BIN
webUI/assets/images/example.jpg
Normal file
BIN
webUI/assets/images/example.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB |
@@ -25,11 +25,12 @@
|
||||
von der <a href="https://status.kreativitaet-trifft-technik.de">Status</a> Seite.
|
||||
|
||||
<div class="img-responsive screenshot">
|
||||
<img src="assets/images/screenshot.png" class="img-thumbnail" />
|
||||
<img src="assets/images/example.jpg" class="img-thumbnail" />
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>Mit "Mit Name/Alias anzeigen." wirst du in <span class="legend">A</span> angezeigt.</li>
|
||||
<li>Mit "Alles anzeigen, d.h. Name/Alias und Gerätename." wirst du in <span class="legend">A1</span> und <span class="legend">A2</span> angezeigt.</li>
|
||||
<li>Mit "Mit Name/Alias anzeigen." wirst du nur in <span class="legend">A1</span> angezeigt.</li>
|
||||
<li>Mit "Als anonyme Person anzeigen." wirst du in <span class="legend">B</span> angezeigt.</li>
|
||||
<li>Wenn du noch gar nichts eingetragen hast oder "Eintrag löschen" gewählt hast, dann wirst du in <span class="legend">C</span> angezeigt.
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user