Files

334 lines
13 KiB
Go
Raw Permalink Normal View History

2014-04-26 11:18:56 +02:00
package ICCC
2014-10-19 19:19:11 +02:00
import (
2015-07-07 09:10:03 +02:00
"bytes"
"encoding/base64"
"encoding/binary"
2014-10-19 19:19:11 +02:00
"fmt"
2015-06-21 20:18:23 +02:00
"github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta"
2015-07-07 09:10:03 +02:00
"net/url"
2014-10-19 19:19:11 +02:00
"reflect"
2015-07-07 09:10:03 +02:00
"strings"
2014-10-19 19:19:11 +02:00
)
2014-04-26 11:18:56 +02:00
2015-06-17 17:44:52 +02:00
// Function to convert the HTTP data back to a message.
2014-04-26 11:18:56 +02:00
func Data2Message(target interface{}, data map[string][]string) (channel, command string, obj interface{}) {
2015-06-21 20:18:23 +02:00
defer func() {
if err := recover(); err != nil {
channel = ``
command = ``
obj = nil
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, fmt.Sprintf("Was not able to convert the HTTP values to a message. %s", err))
return
}
}()
2014-04-26 11:18:56 +02:00
if data == nil || len(data) == 0 {
channel = ``
command = ``
obj = nil
return
}
2015-06-21 20:18:23 +02:00
// By using reflection, determine the type:
elementType := reflect.TypeOf(target)
// Is it a pointer?
if elementType.Kind() == reflect.Ptr {
// Get the value behind the pointer:
elementType = elementType.Elem()
}
// ICCC works with structs! If this is not a struct, its an error.
if elementType.Kind() != reflect.Struct {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityMiddle, LM.ImpactMiddle, LM.MessageNamePARSE, `Was not able to transform HTTP data to a message, because the given data was not a struct.`)
return
}
2014-04-26 11:18:56 +02:00
2015-06-21 20:18:23 +02:00
// By using reflection, create a new instance:
element := reflect.New(elementType).Elem()
2014-04-26 11:18:56 +02:00
channel = data[`channel`][0]
command = data[`command`][0]
2015-06-17 17:44:52 +02:00
// Use the order of the destination type's fields:
2014-04-26 11:18:56 +02:00
for i := 0; i < element.NumField(); i++ {
2015-07-07 09:10:03 +02:00
// Read the current field:
2014-04-26 11:18:56 +02:00
field := element.Field(i)
2015-07-07 09:10:03 +02:00
// Choose the right type for this field:
switch field.Kind().String() {
2014-04-26 11:18:56 +02:00
case `int64`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`int:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
2014-04-26 11:18:56 +02:00
mapValue := data[mapName][0]
2015-07-07 09:10:03 +02:00
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// The destination:
var destination int64
// A reader for the bytes:
buffer := bytes.NewReader(bytesArray)
// Try to decode the bytes to an instance of the type:
errBinary := binary.Read(buffer, binary.LittleEndian, &destination)
if errBinary != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the binary data to the type of the ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBinary.Error())
} else {
// Finnaly, store the value in the message:
field.SetInt(destination)
}
}
2014-04-26 11:18:56 +02:00
case `string`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`str:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
2014-04-26 11:18:56 +02:00
mapValue := data[mapName][0]
2015-07-07 09:10:03 +02:00
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// Decode the bytes as string:
text := string(bytesArray)
// Decode the URL encoded string:
textFinal, errURL := url.QueryUnescape(text)
if errURL != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode a URL encoded string.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errURL.Error())
} else {
field.SetString(textFinal)
}
}
2014-04-26 11:18:56 +02:00
case `float64`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`f64:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
2014-04-26 11:18:56 +02:00
mapValue := data[mapName][0]
2015-07-07 09:10:03 +02:00
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// The destination:
var destination float64
// A reader for the bytes:
buffer := bytes.NewReader(bytesArray)
// Try to decode the bytes to an instance of the type:
errBinary := binary.Read(buffer, binary.LittleEndian, &destination)
if errBinary != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the binary data to the type of the ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBinary.Error())
} else {
// Finnaly, store the value in the message:
field.SetFloat(destination)
}
}
2014-04-26 11:18:56 +02:00
case `bool`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`bool:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
2014-04-26 11:18:56 +02:00
mapValue := data[mapName][0]
2015-07-07 09:10:03 +02:00
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// Store the value:
if bytesArray[0] == 0x1 {
field.SetBool(true)
} else {
field.SetBool(false)
}
}
2014-04-26 11:18:56 +02:00
case `uint8`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`ui8:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
2014-04-26 11:18:56 +02:00
mapValue := data[mapName][0]
2015-07-07 09:10:03 +02:00
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// Store the value:
field.SetUint(uint64(bytesArray[0]))
}
2014-04-26 11:18:56 +02:00
2015-06-17 17:44:52 +02:00
// Case: Arrays...
2014-04-26 11:18:56 +02:00
case `slice`:
sliceInterface := field.Interface()
sliceKind := reflect.ValueOf(sliceInterface).Type().String()
switch sliceKind {
2015-07-07 09:10:03 +02:00
case `[]uint8`: // a byte array
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`ui8[]:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
mapValue := data[mapName][0]
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// Store the values in the message:
fieldDataValue := reflect.ValueOf(bytesArray)
field.Set(fieldDataValue)
}
2014-04-26 11:18:56 +02:00
case `[]int64`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`int[]:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
mapValue := data[mapName][0]
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// The destination:
var destination []int64
// A reader for the bytes:
buffer := bytes.NewReader(bytesArray)
// Try to decode the bytes to an instance of the type:
errBinary := binary.Read(buffer, binary.LittleEndian, &destination)
if errBinary != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the binary data to the type of the ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBinary.Error())
} else {
// Finnaly, store the value in the message:
fieldDataValue := reflect.ValueOf(destination)
field.Set(fieldDataValue)
}
}
2014-04-26 11:18:56 +02:00
case `[]bool`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`bool[]:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
mapValue := data[mapName][0]
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
fieldLen := len(bytesArray)
fieldData := make([]bool, fieldLen, fieldLen)
// Convert each byte in a bool:
for n, value := range bytesArray {
if value == 0x1 {
fieldData[n] = true
} else {
fieldData[n] = false
}
}
// Store the values in the message:
fieldDataValue := reflect.ValueOf(fieldData)
field.Set(fieldDataValue)
}
2014-04-26 11:18:56 +02:00
case `[]string`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`str[]:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
mapValue := data[mapName][0]
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// Get the URL encoded string of all values:
allStringsRAW := string(bytesArray)
// Split now the different strings:
allStrings := strings.Split(allStringsRAW, "\n")
// A place where we store the final strings:
data := make([]string, len(allStrings), len(allStrings))
// Loop over all URL encoded strings and decode it:
for n, element := range allStrings {
elementFinal, errURL := url.QueryUnescape(element)
if errURL != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode a base64 string for a string array.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errURL.Error())
} else {
data[n] = elementFinal
}
}
// Store the values in the message:
fieldDataValue := reflect.ValueOf(data)
field.Set(fieldDataValue)
}
2014-04-26 11:18:56 +02:00
case `[]float64`:
2015-07-07 09:10:03 +02:00
// The name of the field:
2014-04-26 11:18:56 +02:00
mapName := fmt.Sprintf(`f64[]:%s`, elementType.Field(i).Name)
2015-07-07 09:10:03 +02:00
// The value of the field as string:
mapValue := data[mapName][0]
// The value of the field as bytes:
bytesArray, errBase64 := base64.StdEncoding.DecodeString(mapValue)
if errBase64 != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the base64 data to an ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBase64.Error())
} else {
// The destination:
var destination []float64
// A reader for the bytes:
buffer := bytes.NewReader(bytesArray)
// Try to decode the bytes to an instance of the type:
errBinary := binary.Read(buffer, binary.LittleEndian, &destination)
if errBinary != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNamePARSE, `Was not able to decode the binary data to the type of the ICCC message.`, fmt.Sprintf("channel='%s'", channel), fmt.Sprintf("command='%s'", command), errBinary.Error())
} else {
// Finnaly, store the value in the message:
fieldDataValue := reflect.ValueOf(destination)
field.Set(fieldDataValue)
}
}
2014-04-26 11:18:56 +02:00
}
}
}
2015-06-21 20:18:23 +02:00
obj = element.Interface()
2014-04-26 11:18:56 +02:00
return
}