github.com/polarismesh/polaris@v1.17.8/common/eventhub/eventhub.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package eventhub
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"sync"
    24  )
    25  
    26  var (
    27  	initOnce       sync.Once
    28  	globalEventHub *eventHub
    29  )
    30  
    31  var (
    32  	ErrorEventhubNotInitialize = errors.New("eventhub not initialize")
    33  )
    34  
    35  // InitEventHub initialize event hub
    36  func InitEventHub() {
    37  	initOnce.Do(func() {
    38  		globalEventHub = createEventhub()
    39  	})
    40  }
    41  
    42  func createEventhub() *eventHub {
    43  	ctx, cancel := context.WithCancel(context.Background())
    44  	return &eventHub{
    45  		ctx:    ctx,
    46  		cancel: cancel,
    47  		topics: make(map[string]*topic),
    48  	}
    49  }
    50  
    51  // Event evnt type
    52  type Event interface{}
    53  
    54  // eventHub event hub
    55  type eventHub struct {
    56  	ctx    context.Context
    57  	cancel context.CancelFunc
    58  	topics map[string]*topic
    59  	mu     sync.RWMutex
    60  }
    61  
    62  // Publish pushlish event to topic
    63  // @param topic Topic name
    64  // @param event Event object
    65  func Publish(topic string, event Event) error {
    66  	if globalEventHub == nil {
    67  		return ErrorEventhubNotInitialize
    68  	}
    69  	return globalEventHub.Publish(topic, event)
    70  }
    71  
    72  func (eh *eventHub) Publish(topic string, event Event) error {
    73  	t := eh.getTopic(topic)
    74  	t.publish(eh.ctx, event)
    75  	return nil
    76  }
    77  
    78  // Subscribe subscribe topic
    79  // @param topic Topic name
    80  // @param name Subscribe name
    81  // @param handler Message handler
    82  // @param opts Subscription options
    83  // @return error Subscribe failed, return error
    84  func Subscribe(topic string, handler Handler, opts ...SubOption) (*SubscribtionContext, error) {
    85  	if globalEventHub == nil {
    86  		return nil, ErrorEventhubNotInitialize
    87  	}
    88  	return globalEventHub.Subscribe(topic, handler, opts...)
    89  }
    90  
    91  func (e *eventHub) Subscribe(topic string, handler Handler,
    92  	opts ...SubOption) (*SubscribtionContext, error) {
    93  	t := e.getTopic(topic)
    94  	return t.subscribe(e.ctx, handler, opts...)
    95  }
    96  
    97  // Shutdown shutdown event hub
    98  func Shutdown() {
    99  	if globalEventHub == nil {
   100  		return
   101  	}
   102  	globalEventHub.shutdown()
   103  }
   104  
   105  func (e *eventHub) shutdown() {
   106  	e.mu.Lock()
   107  	defer e.mu.Unlock()
   108  
   109  	e.cancel()
   110  	for _, t := range e.topics {
   111  		t.close(e.ctx)
   112  		delete(e.topics, t.name)
   113  	}
   114  }
   115  
   116  func (e *eventHub) createTopic(name string) *topic {
   117  	e.mu.Lock()
   118  	defer e.mu.Unlock()
   119  	if t, ok := e.topics[name]; ok {
   120  		return t
   121  	}
   122  	t := newTopic(name)
   123  	e.topics[name] = t
   124  	go t.run(e.ctx)
   125  	return t
   126  }
   127  
   128  func (e *eventHub) getTopic(name string) *topic {
   129  	e.mu.RLock()
   130  	if t, ok := e.topics[name]; ok {
   131  		e.mu.RUnlock()
   132  		return t
   133  	}
   134  	e.mu.RUnlock()
   135  	return e.createTopic(name)
   136  }