sort.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package nat
  2. import (
  3. "sort"
  4. "strconv"
  5. "strings"
  6. )
  7. type portSorter struct {
  8. ports []Port
  9. by func(i, j Port) bool
  10. }
  11. func (s *portSorter) Len() int {
  12. return len(s.ports)
  13. }
  14. func (s *portSorter) Swap(i, j int) {
  15. s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
  16. }
  17. func (s *portSorter) Less(i, j int) bool {
  18. ip := s.ports[i]
  19. jp := s.ports[j]
  20. return s.by(ip, jp)
  21. }
  22. func Sort(ports []Port, predicate func(i, j Port) bool) {
  23. s := &portSorter{ports, predicate}
  24. sort.Sort(s)
  25. }
  26. type portMapEntry struct {
  27. port Port
  28. binding PortBinding
  29. }
  30. type portMapSorter []portMapEntry
  31. func (s portMapSorter) Len() int { return len(s) }
  32. func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  33. // sort the port so that the order is:
  34. // 1. port with larger specified bindings
  35. // 2. larger port
  36. // 3. port with tcp protocol
  37. func (s portMapSorter) Less(i, j int) bool {
  38. pi, pj := s[i].port, s[j].port
  39. hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
  40. return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
  41. }
  42. // SortPortMap sorts the list of ports and their respected mapping. The ports
  43. // will explicit HostPort will be placed first.
  44. func SortPortMap(ports []Port, bindings PortMap) {
  45. s := portMapSorter{}
  46. for _, p := range ports {
  47. if binding, ok := bindings[p]; ok {
  48. for _, b := range binding {
  49. s = append(s, portMapEntry{port: p, binding: b})
  50. }
  51. bindings[p] = []PortBinding{}
  52. } else {
  53. s = append(s, portMapEntry{port: p})
  54. }
  55. }
  56. sort.Sort(s)
  57. var (
  58. i int
  59. pm = make(map[Port]struct{})
  60. )
  61. // reorder ports
  62. for _, entry := range s {
  63. if _, ok := pm[entry.port]; !ok {
  64. ports[i] = entry.port
  65. pm[entry.port] = struct{}{}
  66. i++
  67. }
  68. // reorder bindings for this port
  69. if _, ok := bindings[entry.port]; ok {
  70. bindings[entry.port] = append(bindings[entry.port], entry.binding)
  71. }
  72. }
  73. }
  74. func toInt(s string) int64 {
  75. i, err := strconv.ParseInt(s, 10, 64)
  76. if err != nil {
  77. i = 0
  78. }
  79. return i
  80. }