package main import ( "crypto/aes" "crypto/cipher" "encoding/base64" "encoding/binary" "fmt" "github.com/imroc/req" "net" "time" ) type serverLog struct { ID uint16 `json:"id"` Stamp time.Time `json:"stamp"` Log string `json:"log"` } type serverMsg struct { id uint16 acc uint32 light bool } var serverLogs = []serverLog{{0, time.Now(), "Server started..."}} func sendData(msg *serverMsg) { defer logPanic() c := config.Influx if c == nil { return } var light int if light = 0; msg.light { light = 1 } now := time.Now().UnixNano() data := fmt.Sprintf("accelerometer,board=%d value=%d %d\n", msg.id, msg.acc, now) data += fmt.Sprintf("light,board=%d value=%d %d", msg.id, light, now) auth := base64.StdEncoding.EncodeToString([]byte(c.Username+":"+c.Password)) head := req.Header{ "Authorization": "Basic " + auth, } r, err := req.Post(fmt.Sprintf("http://%s/write?db=%s", c.Domain, c.Database), head, data) if err != nil { errCheckPanic(err, "Failed send to influx server") } if r.Response().StatusCode > 300 { fmt.Printf("Influx server returned code %d\n", r.Response().StatusCode) } } func serveConnection(conn net.Conn) { defer logPanic() defer fmt.Printf("Connection closed %s\n", conn.RemoteAddr().String()) defer conn.Close() fmt.Printf("Connection from %s\n", conn.RemoteAddr().String()) buf := make([]byte, 4) for { _, err := conn.Read(buf) errCheckPanic(err, "Connection failed with %s", conn.RemoteAddr().String()) id := binary.LittleEndian.Uint16(buf[:2]) board, ok := config.Boards[id] if !ok { fmt.Printf("Connection with ID %d is not registerd\n", id) break } board.LastSeen = time.Now() msglen := binary.LittleEndian.Uint16(buf[2:]) fmt.Printf("Connection from ID %d message length %d\n %x\n", id, msglen, buf) payload := make([]byte, msglen) _, err = conn.Read(payload) errCheckPanic(err, "Connection failed %s device #%d", conn.RemoteAddr().String(), id) fmt.Printf("Payload: %x\n", payload) message := make([]byte, msglen-16) block, err := aes.NewCipher(board.KEY) errCheckPanic(err, "Decryption failed %s device #%d", conn.RemoteAddr().String(), id) mode := cipher.NewCBCDecrypter(block, payload[:16]) mode.CryptBlocks(message, payload[16:]) fmt.Printf("Message: %x\n", message) msg := serverMsg{ id, binary.LittleEndian.Uint32(message[:4]), message[4] != 0x00, } sendData(&msg) smessage := fmt.Sprintf("ACC: %d, LIGHT: %t", msg.acc, msg.light) serverLogs = append([]serverLog{{id, board.LastSeen, smessage}}, serverLogs...) if len(serverLogs) > 150 { serverLogs = serverLogs[:len(serverLogs)-1] } fmt.Printf("Message: %x\n%s\n", message, smessage) } } func serve(address string) { ln, err := net.Listen("tcp", address) errCheckExit(err,"Failed accept connection") defer ln.Close() fmt.Printf("Service socket ready at %s\n", address) for { conn, err := ln.Accept() errCheckExit(err,"Failed accept connection %s", conn.RemoteAddr().String()) go serveConnection(conn) } }