mirror of
https://github.com/fhmq/hmq.git
synced 2026-09-01 23:34:52 +00:00
Plugins support (#46)
* modify * update * add acl * add feature * update dockerfile * add deploy * update * update * plugins * plugins * update * update * update * fixed * remove * fixed * add log * update * fixed * update * fix config * add http api * add http api * resp * add config for work chan * update * fixed * update * disable trace * fixed * change acl * fixed * fixed res * dd * dd * ddd * dd * update * fixed * update * add * fixed * update key * add log * update * format * update * update auth * update * update readme * added * update * fixed * fixed * fix * upade * update * update
This commit is contained in:
+413
@@ -0,0 +1,413 @@
|
||||
package ndr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// intFromTag returns an int that is a value in a struct tag key/value pair
|
||||
func intFromTag(tag reflect.StructTag, key string) (int, error) {
|
||||
ndrTag := parseTags(tag)
|
||||
d := 1
|
||||
if n, ok := ndrTag.Map[key]; ok {
|
||||
i, err := strconv.Atoi(n)
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("invalid dimensions tag [%s]: %v", n, err)
|
||||
}
|
||||
d = i
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// parseDimensions returns the a slice of the size of each dimension and type of the member at the deepest level.
|
||||
func parseDimensions(v reflect.Value) (l []int, tb reflect.Type) {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Array && t.Kind() != reflect.Slice {
|
||||
return
|
||||
}
|
||||
l = append(l, v.Len())
|
||||
if t.Elem().Kind() == reflect.Array || t.Elem().Kind() == reflect.Slice {
|
||||
// contains array or slice
|
||||
var m []int
|
||||
m, tb = parseDimensions(v.Index(0))
|
||||
l = append(l, m...)
|
||||
} else {
|
||||
tb = t.Elem()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// sliceDimensions returns the count of dimensions a slice has.
|
||||
func sliceDimensions(t reflect.Type) (d int, tb reflect.Type) {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() == reflect.Slice {
|
||||
d++
|
||||
var n int
|
||||
n, tb = sliceDimensions(t.Elem())
|
||||
d += n
|
||||
} else {
|
||||
tb = t
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// makeSubSlices is a deep recursive creation/initialisation of multi-dimensional slices.
|
||||
// Takes the reflect.Value of the 1st dimension and a slice of the lengths of the sub dimensions
|
||||
func makeSubSlices(v reflect.Value, l []int) {
|
||||
ty := v.Type().Elem()
|
||||
if ty.Kind() != reflect.Slice {
|
||||
return
|
||||
}
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
s := reflect.MakeSlice(ty, l[0], l[0])
|
||||
v.Index(i).Set(s)
|
||||
// Are there more sub dimensions?
|
||||
if len(l) > 1 {
|
||||
makeSubSlices(v.Index(i), l[1:])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// multiDimensionalIndexPermutations returns all the permutations of the indexes of a multi-dimensional slice.
|
||||
// The input is a slice of integers that indicates the max size/length of each dimension
|
||||
func multiDimensionalIndexPermutations(l []int) (ps [][]int) {
|
||||
z := make([]int, len(l), len(l)) // The zeros permutation
|
||||
ps = append(ps, z)
|
||||
// for each dimension, in reverse
|
||||
for i := len(l) - 1; i >= 0; i-- {
|
||||
ws := make([][]int, len(ps))
|
||||
copy(ws, ps)
|
||||
//create a permutation for each of the iterations of the current dimension
|
||||
for j := 1; j <= l[i]-1; j++ {
|
||||
// For each existing permutation
|
||||
for _, p := range ws {
|
||||
np := make([]int, len(p), len(p))
|
||||
copy(np, p)
|
||||
np[i] = j
|
||||
ps = append(ps, np)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// precedingMax reads off the next conformant max value
|
||||
func (dec *Decoder) precedingMax() uint32 {
|
||||
m := dec.conformantMax[0]
|
||||
dec.conformantMax = dec.conformantMax[1:]
|
||||
return m
|
||||
}
|
||||
|
||||
// fillFixedArray establishes if the fixed array is uni or multi dimensional and then fills it.
|
||||
func (dec *Decoder) fillFixedArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
l, t := parseDimensions(v)
|
||||
if t.Kind() == reflect.String {
|
||||
tag = reflect.StructTag(subStringArrayTag)
|
||||
}
|
||||
if len(l) < 1 {
|
||||
return errors.New("could not establish dimensions of fixed array")
|
||||
}
|
||||
if len(l) == 1 {
|
||||
err := dec.fillUniDimensionalFixedArray(v, tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill uni-dimensional fixed array: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// Fixed array is multidimensional
|
||||
ps := multiDimensionalIndexPermutations(l[:len(l)-1])
|
||||
for _, p := range ps {
|
||||
// Get current multi-dimensional index to fill
|
||||
a := v
|
||||
for _, i := range p {
|
||||
a = a.Index(i)
|
||||
}
|
||||
// fill with the last dimension array
|
||||
err := dec.fillUniDimensionalFixedArray(a, tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill dimension %v of multi-dimensional fixed array: %v", p, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readUniDimensionalFixedArray reads an array (not slice) from the byte stream.
|
||||
func (dec *Decoder) fillUniDimensionalFixedArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
err := dec.fill(v.Index(i), tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %d of fixed array: %v", i, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillConformantArray establishes if the conformant array is uni or multi dimensional and then fills the slice.
|
||||
func (dec *Decoder) fillConformantArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
d, _ := sliceDimensions(v.Type())
|
||||
if d > 1 {
|
||||
err := dec.fillMultiDimensionalConformantArray(v, d, tag, def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := dec.fillUniDimensionalConformantArray(v, tag, def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillUniDimensionalConformantArray fills the uni-dimensional slice value.
|
||||
func (dec *Decoder) fillUniDimensionalConformantArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
m := dec.precedingMax()
|
||||
n := int(m)
|
||||
a := reflect.MakeSlice(v.Type(), n, n)
|
||||
for i := 0; i < n; i++ {
|
||||
err := dec.fill(a.Index(i), tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %d of uni-dimensional conformant array: %v", i, err)
|
||||
}
|
||||
}
|
||||
v.Set(a)
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillMultiDimensionalConformantArray fills the multi-dimensional slice value provided from conformant array data.
|
||||
// The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this
|
||||
// method not to panic.
|
||||
func (dec *Decoder) fillMultiDimensionalConformantArray(v reflect.Value, d int, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
// Read the max size of each dimensions from the ndr stream
|
||||
l := make([]int, d, d)
|
||||
for i := range l {
|
||||
l[i] = int(dec.precedingMax())
|
||||
}
|
||||
// Initialise size of slices
|
||||
// Initialise the size of the 1st dimension
|
||||
ty := v.Type()
|
||||
v.Set(reflect.MakeSlice(ty, l[0], l[0]))
|
||||
// Initialise the size of the other dimensions recursively
|
||||
makeSubSlices(v, l[1:])
|
||||
|
||||
// Get all permutations of the indexes and go through each and fill
|
||||
ps := multiDimensionalIndexPermutations(l)
|
||||
for _, p := range ps {
|
||||
// Get current multi-dimensional index to fill
|
||||
a := v
|
||||
for _, i := range p {
|
||||
a = a.Index(i)
|
||||
}
|
||||
err := dec.fill(a, tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %v of slice: %v", p, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillVaryingArray establishes if the varying array is uni or multi dimensional and then fills the slice.
|
||||
func (dec *Decoder) fillVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
d, t := sliceDimensions(v.Type())
|
||||
if d > 1 {
|
||||
err := dec.fillMultiDimensionalVaryingArray(v, t, d, tag, def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := dec.fillUniDimensionalVaryingArray(v, tag, def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillUniDimensionalVaryingArray fills the uni-dimensional slice value.
|
||||
func (dec *Decoder) fillUniDimensionalVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
o, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read offset of uni-dimensional varying array: %v", err)
|
||||
}
|
||||
s, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not establish actual count of uni-dimensional varying array: %v", err)
|
||||
}
|
||||
t := v.Type()
|
||||
// Total size of the array is the offset in the index being passed plus the actual count of elements being passed.
|
||||
n := int(s + o)
|
||||
a := reflect.MakeSlice(t, n, n)
|
||||
// Populate the array starting at the offset specified
|
||||
for i := int(o); i < n; i++ {
|
||||
err := dec.fill(a.Index(i), tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %d of uni-dimensional varying array: %v", i, err)
|
||||
}
|
||||
}
|
||||
v.Set(a)
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillMultiDimensionalVaryingArray fills the multi-dimensional slice value provided from varying array data.
|
||||
// The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this
|
||||
// method not to panic.
|
||||
func (dec *Decoder) fillMultiDimensionalVaryingArray(v reflect.Value, t reflect.Type, d int, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
// Read the offset and actual count of each dimensions from the ndr stream
|
||||
o := make([]int, d, d)
|
||||
l := make([]int, d, d)
|
||||
for i := range l {
|
||||
off, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read offset of dimension %d: %v", i+1, err)
|
||||
}
|
||||
o[i] = int(off)
|
||||
s, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read size of dimension %d: %v", i+1, err)
|
||||
}
|
||||
l[i] = int(s) + int(off)
|
||||
}
|
||||
// Initialise size of slices
|
||||
// Initialise the size of the 1st dimension
|
||||
ty := v.Type()
|
||||
v.Set(reflect.MakeSlice(ty, l[0], l[0]))
|
||||
// Initialise the size of the other dimensions recursively
|
||||
makeSubSlices(v, l[1:])
|
||||
|
||||
// Get all permutations of the indexes and go through each and fill
|
||||
ps := multiDimensionalIndexPermutations(l)
|
||||
for _, p := range ps {
|
||||
// Get current multi-dimensional index to fill
|
||||
a := v
|
||||
var os bool // should this permutation be skipped due to the offset of any of the dimensions?
|
||||
for i, j := range p {
|
||||
if j < o[i] {
|
||||
os = true
|
||||
break
|
||||
}
|
||||
a = a.Index(j)
|
||||
}
|
||||
if os {
|
||||
// This permutation should be skipped as it is less than the offset for one of the dimensions.
|
||||
continue
|
||||
}
|
||||
err := dec.fill(a, tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %v of slice: %v", p, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillConformantVaryingArray establishes if the varying array is uni or multi dimensional and then fills the slice.
|
||||
func (dec *Decoder) fillConformantVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
d, t := sliceDimensions(v.Type())
|
||||
if d > 1 {
|
||||
err := dec.fillMultiDimensionalConformantVaryingArray(v, t, d, tag, def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := dec.fillUniDimensionalConformantVaryingArray(v, tag, def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillUniDimensionalConformantVaryingArray fills the uni-dimensional slice value.
|
||||
func (dec *Decoder) fillUniDimensionalConformantVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
m := dec.precedingMax()
|
||||
o, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read offset of uni-dimensional conformant varying array: %v", err)
|
||||
}
|
||||
s, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not establish actual count of uni-dimensional conformant varying array: %v", err)
|
||||
}
|
||||
if m < o+s {
|
||||
return errors.New("max count is less than the offset plus actual count")
|
||||
}
|
||||
t := v.Type()
|
||||
n := int(s)
|
||||
a := reflect.MakeSlice(t, n, n)
|
||||
for i := int(o); i < n; i++ {
|
||||
err := dec.fill(a.Index(i), tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %d of uni-dimensional conformant varying array: %v", i, err)
|
||||
}
|
||||
}
|
||||
v.Set(a)
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillMultiDimensionalConformantVaryingArray fills the multi-dimensional slice value provided from conformant varying array data.
|
||||
// The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this
|
||||
// method not to panic.
|
||||
func (dec *Decoder) fillMultiDimensionalConformantVaryingArray(v reflect.Value, t reflect.Type, d int, tag reflect.StructTag, def *[]deferedPtr) error {
|
||||
// Read the offset and actual count of each dimensions from the ndr stream
|
||||
m := make([]int, d, d)
|
||||
for i := range m {
|
||||
m[i] = int(dec.precedingMax())
|
||||
}
|
||||
o := make([]int, d, d)
|
||||
l := make([]int, d, d)
|
||||
for i := range l {
|
||||
off, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read offset of dimension %d: %v", i+1, err)
|
||||
}
|
||||
o[i] = int(off)
|
||||
s, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read actual count of dimension %d: %v", i+1, err)
|
||||
}
|
||||
if m[i] < int(s)+int(off) {
|
||||
m[i] = int(s) + int(off)
|
||||
}
|
||||
l[i] = int(s)
|
||||
}
|
||||
// Initialise size of slices
|
||||
// Initialise the size of the 1st dimension
|
||||
ty := v.Type()
|
||||
v.Set(reflect.MakeSlice(ty, m[0], m[0]))
|
||||
// Initialise the size of the other dimensions recursively
|
||||
makeSubSlices(v, m[1:])
|
||||
|
||||
// Get all permutations of the indexes and go through each and fill
|
||||
ps := multiDimensionalIndexPermutations(m)
|
||||
for _, p := range ps {
|
||||
// Get current multi-dimensional index to fill
|
||||
a := v
|
||||
var os bool // should this permutation be skipped due to the offset of any of the dimensions or max is higher than the actual count being passed
|
||||
for i, j := range p {
|
||||
if j < o[i] || j >= l[i] {
|
||||
os = true
|
||||
break
|
||||
}
|
||||
a = a.Index(j)
|
||||
}
|
||||
if os {
|
||||
// This permutation should be skipped as it is less than the offset for one of the dimensions.
|
||||
continue
|
||||
}
|
||||
err := dec.fill(a, tag, def)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not fill index %v of slice: %v", p, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user