|
| 1 | +package broker |
| 2 | + |
| 3 | +import ( |
| 4 | + "connectrpc.com/connect" |
| 5 | + acv1 "github.com/steady-bytes/draft/api/core/message_broker/actors/v1" |
| 6 | + "github.com/steady-bytes/draft/pkg/chassis" |
| 7 | +) |
| 8 | + |
| 9 | +type ( |
| 10 | + Controller interface { |
| 11 | + Consumer |
| 12 | + Producer |
| 13 | + } |
| 14 | + |
| 15 | + controller struct { |
| 16 | + Producer |
| 17 | + Consumer |
| 18 | + |
| 19 | + logger chassis.Logger |
| 20 | + |
| 21 | + state *atomicMap |
| 22 | + } |
| 23 | + |
| 24 | + register struct { |
| 25 | + *acv1.CloudEvent |
| 26 | + *connect.ServerStream[acv1.ConsumeResponse] |
| 27 | + } |
| 28 | +) |
| 29 | + |
| 30 | +func NewController(logger chassis.Logger) Controller { |
| 31 | + var ( |
| 32 | + producerMsgChan = make(chan *acv1.CloudEvent) |
| 33 | + consumerRegistrationChan = make(chan register) |
| 34 | + ) |
| 35 | + |
| 36 | + ctr := &controller{ |
| 37 | + NewProducer(producerMsgChan), |
| 38 | + NewConsumer(consumerRegistrationChan), |
| 39 | + logger, |
| 40 | + newAtomicMap(), |
| 41 | + } |
| 42 | + |
| 43 | + // TODO: This could contain more configuration. Like maybe reading the number |
| 44 | + // of cpu cores to spread the works over? |
| 45 | + |
| 46 | + go ctr.produce(producerMsgChan) |
| 47 | + go ctr.consume(consumerRegistrationChan) |
| 48 | + |
| 49 | + return ctr |
| 50 | +} |
| 51 | + |
| 52 | +const ( |
| 53 | + LOG_KEY_TO_CH = "key to channel" |
| 54 | +) |
| 55 | + |
| 56 | +func (c *controller) produce(producerMsgChan chan *acv1.CloudEvent) { |
| 57 | + for { |
| 58 | + msg := <-producerMsgChan |
| 59 | + c.logger.WithField("msg: ", msg).Info("produce massage received") |
| 60 | + |
| 61 | + // make hash of <domain><msg.Type.String> |
| 62 | + key := c.state.hash(string(msg.ProtoReflect().Descriptor().FullName())) |
| 63 | + |
| 64 | + // do I save to blueprint? |
| 65 | + // - default config is to be durable |
| 66 | + // - the producer can also add configuration to say not to store |
| 67 | + |
| 68 | + // send the received `Message` to all `Consumers` for the same key |
| 69 | + c.logger.WithField("key", key).Info(LOG_KEY_TO_CH) |
| 70 | + c.state.Broadcast(key, msg) |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +// consume - Will create a hash of the message domain, and typeUrl then save the msg.ServerStream to `atomicMap.m` |
| 75 | +// that can be used to `Broadcast` messages to when a message is produced. Con's to this approach are a `RWMutex` |
| 76 | +// has to be used to `Broadcast` the message so the connected stream. |
| 77 | +// func (c *controller) consume(reg chan register) { |
| 78 | +// for { |
| 79 | +// msg := <-reg |
| 80 | +// fmt.Print("Receive a request to setup a consumer", msg) |
| 81 | + |
| 82 | +// // make hash of <domain><msg.Type.String> |
| 83 | +// key := c.hash(msg.GetDomain(), msg.GetKind().GetTypeUrl()) |
| 84 | + |
| 85 | +// // use hash as key if the hash does not exist, then create a slice of connections |
| 86 | +// // and append the connection to the slice |
| 87 | +// c.state.Insert(key, msg.ServerStream) |
| 88 | +// } |
| 89 | +// } |
| 90 | + |
| 91 | +// consume - Will create a hash of the message domain, and typeUrl to use as a key to a tx, and rx sides of a channel |
| 92 | +// the `tx` or transmitter will be used when a producer produces an event to send the event to each client that is consuming |
| 93 | +// events of the domain, and typeUrl. |
| 94 | +func (c *controller) consume(registerChan chan register) { |
| 95 | + for { |
| 96 | + // create a shared channel that will receive any kind of message of that domain, and typeUrl |
| 97 | + // add the receiver to a go routine that will keep the `ServerStream` open and send any messages |
| 98 | + // received up to the client connect. |
| 99 | + msg := <-registerChan |
| 100 | + c.logger.WithField("msg", msg).Info("consume channel registration") |
| 101 | + |
| 102 | + key := c.state.hash(string(msg.ProtoReflect().Descriptor().FullName())) |
| 103 | + |
| 104 | + // key := c.state.hash(msg.GetDomain(), msg.GetKind().GetTypeUrl()) |
| 105 | + c.logger.WithField("key", key).Info(LOG_KEY_TO_CH) |
| 106 | + c.state.Broker(key, msg.ServerStream) |
| 107 | + } |
| 108 | +} |
0 commit comments