clientset.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ssh
  15. import (
  16. "context"
  17. ssh_util "yunion.io/x/onecloud/pkg/util/ssh"
  18. )
  19. type epClientSet struct {
  20. cc ssh_util.ClientConfig
  21. clients []*Client
  22. mark bool
  23. }
  24. func (epcs *epClientSet) clearMark() {
  25. epcs.mark = false
  26. }
  27. func (epcs *epClientSet) setMark() {
  28. epcs.mark = true
  29. }
  30. func (epcs *epClientSet) getMark() bool {
  31. return epcs.mark
  32. }
  33. func (epcs *epClientSet) stop(ctx context.Context) {
  34. for _, client := range epcs.clients {
  35. client.Stop(ctx)
  36. }
  37. }
  38. type epClients map[string]*epClientSet // key: epKey
  39. type ClientSet struct {
  40. epClients epClients
  41. }
  42. func NewClientSet() *ClientSet {
  43. cs := &ClientSet{
  44. epClients: epClients{},
  45. }
  46. return cs
  47. }
  48. func (cs *ClientSet) ClearAllMark() {
  49. for _, epcs := range cs.epClients {
  50. epcs.clearMark()
  51. }
  52. }
  53. func (cs *ClientSet) ResetIfChanged(ctx context.Context, epKey string, cc ssh_util.ClientConfig) bool {
  54. epcs, ok := cs.epClients[epKey]
  55. if ok {
  56. if epcs.cc != cc {
  57. epcs.stop(ctx)
  58. delete(cs.epClients, epKey)
  59. cs.AddIfNotExist(ctx, epKey, cc)
  60. return true
  61. }
  62. epcs.setMark()
  63. }
  64. return false
  65. }
  66. func (cs *ClientSet) AddIfNotExist(ctx context.Context, epKey string, cc ssh_util.ClientConfig) bool {
  67. epcs, ok := cs.epClients[epKey]
  68. if !ok {
  69. epcs := &epClientSet{
  70. cc: cc,
  71. }
  72. epcs.setMark()
  73. cs.epClients[epKey] = epcs
  74. return true
  75. }
  76. epcs.setMark()
  77. return false
  78. }
  79. func (cs *ClientSet) ResetUnmarked(ctx context.Context) {
  80. for epKey, epcs := range cs.epClients {
  81. if !epcs.getMark() {
  82. epcs.stop(ctx)
  83. delete(cs.epClients, epKey)
  84. }
  85. }
  86. }
  87. func (cs *ClientSet) ForwardKeySet() ForwardKeySet {
  88. fks := ForwardKeySet{}
  89. for epKey, epcs := range cs.epClients {
  90. for _, client := range epcs.clients {
  91. fks.addByPortMap(epKey, ForwardKeyTypeL, client.localForwards)
  92. fks.addByPortMap(epKey, ForwardKeyTypeR, client.remoteForwards)
  93. }
  94. }
  95. return fks
  96. }
  97. func (cs *ClientSet) LocalForward(ctx context.Context, epKey string, req LocalForwardReq) {
  98. client, created := cs.getOrCreateClient(epKey, ForwardKeyTypeL)
  99. if created {
  100. go client.Start(ctx)
  101. }
  102. client.LocalForward(ctx, req)
  103. }
  104. func (cs *ClientSet) RemoteForward(ctx context.Context, epKey string, req RemoteForwardReq) {
  105. client, created := cs.getOrCreateClient(epKey, ForwardKeyTypeR)
  106. if created {
  107. go client.Start(ctx)
  108. }
  109. client.RemoteForward(ctx, req)
  110. }
  111. func (cs *ClientSet) CloseForward(ctx context.Context, fk ForwardKey) {
  112. client := cs.getClient(fk.EpKey, fk.Type)
  113. if client == nil {
  114. return
  115. }
  116. switch fk.Type {
  117. case ForwardKeyTypeL:
  118. client.LocalForwardClose(ctx, LocalForwardReq{
  119. LocalAddr: fk.KeyAddr,
  120. LocalPort: fk.KeyPort,
  121. })
  122. case ForwardKeyTypeR:
  123. client.RemoteForwardClose(ctx, RemoteForwardReq{
  124. RemoteAddr: fk.KeyAddr,
  125. RemotePort: fk.KeyPort,
  126. })
  127. }
  128. }
  129. /*
  130. func (cs *ClientSet) LocalForwardClose(ctx context.Context, epKey string, req LocalForwardReq) {
  131. client := cs.getClient(epKey, ForwardKeyTypeL)
  132. client.LocalForwardClose(ctx, req)
  133. }
  134. func (cs *ClientSet) RemoteForwardClose(ctx context.Context, epKey string, req RemoteForwardReq) {
  135. client := cs.getClient(epKey, ForwardKeyTypeR)
  136. client.RemoteForwardClose(ctx, req)
  137. }
  138. */
  139. func (cs *ClientSet) getOrCreateClient(epKey string, typ string) (*Client, bool) {
  140. return cs.getClient_(epKey, typ, true)
  141. }
  142. func (cs *ClientSet) getClient(epKey string, typ string) *Client {
  143. client, _ := cs.getClient_(epKey, typ, false)
  144. return client
  145. }
  146. func (cs *ClientSet) getClient_(epKey string, typ string, create bool) (*Client, bool) {
  147. var client *Client
  148. clients, ok := cs.epClients[epKey]
  149. if !ok || len(clients.clients) == 0 {
  150. if !ok || !create {
  151. return nil, false
  152. }
  153. client = NewClient(&clients.cc)
  154. clients.clients = append(clients.clients, client)
  155. cs.epClients[epKey] = clients
  156. return client, true
  157. } else {
  158. client = clients.clients[0]
  159. return client, false
  160. }
  161. }