github.com/glide-im/glide@v1.6.0/pkg/gate/gateway.go (about) 1 package gate 2 3 import ( 4 "errors" 5 "github.com/glide-im/glide/pkg/conn" 6 "github.com/glide-im/glide/pkg/logger" 7 "github.com/glide-im/glide/pkg/messages" 8 "github.com/panjf2000/ants/v2" 9 "log" 10 "sync" 11 ) 12 13 // Gateway is the basic and common interface for all gate implementations. 14 // As the basic gate, it is used to provide a common gate interface for other modules to interact with the gate. 15 type Gateway interface { 16 17 // SetClientID sets the client id with the new id. 18 SetClientID(old ID, new_ ID) error 19 20 UpdateClient(id ID, info *ClientSecrets) error 21 22 // ExitClient exits the client with the given id. 23 ExitClient(id ID) error 24 25 // EnqueueMessage enqueues the message to the client with the given id. 26 EnqueueMessage(id ID, message *messages.GlideMessage) error 27 } 28 29 // Server is the interface for the gateway server, which is used to handle and manager client connections. 30 type Server interface { 31 Gateway 32 33 // SetMessageHandler sets the client message handler. 34 SetMessageHandler(h MessageHandler) 35 36 // HandleConnection handles the new client connection and returns the random and temporary id set for the connection. 37 HandleConnection(c conn.Connection) ID 38 39 Run() error 40 } 41 42 // MessageHandler used to handle messages from the gate. 43 type MessageHandler func(cliInfo *Info, message *messages.GlideMessage) 44 45 // DefaultGateway is gateway default implements. 46 type DefaultGateway interface { 47 Gateway 48 49 GetClient(id ID) Client 50 51 GetAll() map[ID]Info 52 53 SetMessageHandler(h MessageHandler) 54 55 AddClient(cs Client) 56 } 57 58 type Options struct { 59 // ID is the gateway id. 60 ID string 61 // SecretKey is the secret key used to encrypt and decrypt authentication token. 62 SecretKey string 63 // MaxMessageConcurrency is the max message concurrency. 64 MaxMessageConcurrency int 65 } 66 67 var _ DefaultGateway = (*Impl)(nil) 68 69 type Impl struct { 70 id string 71 72 // clients is a map of all connected clients 73 clients map[ID]Client 74 mu sync.RWMutex 75 76 // msgHandler client message handler 77 msgHandler MessageHandler 78 79 authenticator *Authenticator 80 81 // pool of ants, used to process messages concurrently. 82 pool *ants.Pool 83 84 emptyInfo *Info 85 } 86 87 func NewServer(options *Options) (*Impl, error) { 88 89 ret := new(Impl) 90 ret.clients = map[ID]Client{} 91 ret.mu = sync.RWMutex{} 92 ret.id = options.ID 93 ret.emptyInfo = &Info{ 94 ID: NewID(ret.id, "", ""), 95 } 96 97 if options.SecretKey != "" { 98 ret.authenticator = NewAuthenticator(ret, options.SecretKey) 99 } 100 101 pool, err := ants.NewPool(options.MaxMessageConcurrency, 102 ants.WithNonblocking(true), 103 ants.WithPanicHandler(func(i interface{}) { 104 log.Printf("panic: %v", i) 105 }), 106 ants.WithPreAlloc(false), 107 ) 108 if err != nil { 109 return nil, err 110 } 111 ret.pool = pool 112 return ret, nil 113 } 114 115 // GetClient returns the client with specified id 116 func (c *Impl) GetClient(id ID) Client { 117 c.mu.RLock() 118 defer c.mu.RUnlock() 119 return c.clients[id] 120 } 121 122 // GetAll returns all clients in the gateway. 123 func (c *Impl) GetAll() map[ID]Info { 124 c.mu.RLock() 125 defer c.mu.RUnlock() 126 127 result := map[ID]Info{} 128 for id, client := range c.clients { 129 result[id] = client.GetInfo() 130 } 131 return result 132 } 133 134 func (c *Impl) SetMessageHandler(h MessageHandler) { 135 c.msgHandler = h 136 } 137 138 func (c *Impl) UpdateClient(id ID, info *ClientSecrets) error { 139 c.mu.Lock() 140 defer c.mu.Unlock() 141 142 id.SetGateway(c.id) 143 144 logger.D("gateway", "update client %s, %v", id, info) 145 146 cli, ok := c.clients[id] 147 if !ok || cli == nil { 148 return errors.New(errClientNotExist) 149 } 150 151 dc, ok := cli.(DefaultClient) 152 if ok { 153 credentials := dc.GetCredentials() 154 credentials.Secrets = info 155 dc.SetCredentials(credentials) 156 } 157 158 return nil 159 } 160 161 func (c *Impl) AddClient(cs Client) { 162 c.mu.Lock() 163 defer c.mu.Unlock() 164 165 id := cs.GetInfo().ID 166 id.SetGateway(c.id) 167 168 dc, ok := cs.(DefaultClient) 169 if ok { 170 dc.AddMessageInterceptor(c.interceptClientMessage) 171 } 172 173 c.clients[id] = cs 174 c.msgHandler(c.emptyInfo, messages.NewMessage(0, messages.ActionInternalOnline, id)) 175 } 176 177 // SetClientID replace the oldID with newID of the client. 178 // If the oldID is not exist, return errClientNotExist. 179 // If the newID is existed, return errClientAlreadyExist. 180 func (c *Impl) SetClientID(oldID, newID ID) error { 181 c.mu.Lock() 182 defer c.mu.Unlock() 183 184 oldID.SetGateway(c.id) 185 newID.SetGateway(c.id) 186 187 cli, ok := c.clients[oldID] 188 if !ok || cli == nil { 189 return errors.New(errClientNotExist) 190 } 191 cliLogged, exist := c.clients[newID] 192 if exist && cliLogged != nil { 193 return errors.New(errClientAlreadyExist) 194 } 195 196 cli.SetID(newID) 197 delete(c.clients, oldID) 198 c.msgHandler(c.emptyInfo, messages.NewMessage(0, messages.ActionInternalOffline, oldID)) 199 c.msgHandler(c.emptyInfo, messages.NewMessage(0, messages.ActionInternalOnline, newID)) 200 201 c.clients[newID] = cli 202 return nil 203 } 204 205 // ExitClient close the client with the specified id. 206 // If the client is not exist, return errClientNotExist. 207 func (c *Impl) ExitClient(id ID) error { 208 c.mu.Lock() 209 defer c.mu.Unlock() 210 211 id.SetGateway(c.id) 212 213 cli, ok := c.clients[id] 214 if !ok || cli == nil { 215 return errors.New(errClientNotExist) 216 } 217 218 cli.SetID("") 219 delete(c.clients, id) 220 c.msgHandler(c.emptyInfo, messages.NewMessage(0, messages.ActionInternalOffline, id)) 221 cli.Exit() 222 223 return nil 224 } 225 226 // EnqueueMessage to the client with the specified id. 227 func (c *Impl) EnqueueMessage(id ID, msg *messages.GlideMessage) error { 228 229 c.mu.RLock() 230 defer c.mu.RUnlock() 231 232 id.SetGateway(c.id) 233 cli, ok := c.clients[id] 234 if !ok || cli == nil { 235 return errors.New(errClientNotExist) 236 } 237 238 return c.enqueueMessage(cli, msg) 239 } 240 241 func (c *Impl) interceptClientMessage(dc DefaultClient, m *messages.GlideMessage) bool { 242 243 if m.Action == messages.ActionAuthenticate { 244 if c.authenticator != nil { 245 return c.authenticator.ClientAuthMessageInterceptor(dc, m) 246 } 247 } 248 249 return c.authenticator.MessageInterceptor(dc, m) 250 } 251 252 func (c *Impl) enqueueMessage(cli Client, msg *messages.GlideMessage) error { 253 if !cli.IsRunning() { 254 return errors.New(errClientClosed) 255 } 256 err := c.pool.Submit(func() { 257 _ = cli.EnqueueMessage(msg) 258 }) 259 if err != nil { 260 return errors.New("enqueue message to client failed") 261 } 262 return nil 263 }