package message import ( "encoding/json" "fmt" "strings" lib "git.sr.ht/~cco/go-scopes" "git.sr.ht/~cco/go-scopes/logging" "git.sr.ht/~cco/go-scopes/logging/log" ) // message head type head struct { domain, action, class, item string } func (h *head) String() string { return strings.Join(h.Slice(), "/") } func (h *head) Slice() []string { return []string{h.domain, h.action, h.class, h.item} } func (h *head) Domain() string { return h.domain } func (h *head) Action() string { return h.action } func (h *head) Class() string { return h.class } func (h *head) Item() string { return h.item } // message type message struct { *head sender lib.Addressable payload lib.Payload } func (msg *message) Head() lib.MsgHead { return msg } func (msg *message) Sender() lib.Addressable { return msg.sender } func (msg *message) Payload() lib.Payload { return msg.payload } func (msg *message) WithSender(s lib.Addressable) lib.Message { msg.sender = s return msg } func (msg *message) WithPayload(p lib.Payload) lib.Message { msg.payload = p return msg } func New(args ...string) lib.Message { args = append(args, "", "")[:4] domain := args[0] if domain == "" { domain = "scopes" } return &message{ head: &head{ domain: domain, action: args[1], class: args[2], item: args[3], }, } } func SimpleMessage(action string) lib.Message { return New("scopes", action) } var Quit = SimpleMessage("quit") // payload type payload struct{ data lib.Data } func (pl *payload) String() string { b, err := json.Marshal(pl.data) if err != nil { log.Error(err).Msg("payload.String()") } return string(b) } func (pl *payload) Data() lib.Data { return pl.data } func (pl *payload) FromJson(s string) lib.Payload { err := json.Unmarshal([]byte(s), &pl.data) if err != nil { log.Error(err).Msg("payload.FromJson()") } return pl } func Payload(d interface{}) lib.Payload { return &payload{d} } func PayloadFromJson[T any](s string) lib.Payload { pl := &payload{new(T)} return pl.FromJson(s) } // generic send functionality func Send(ctx lib.Context, rcv lib.Addressable, msg lib.Message) { if msg.Sender() == nil { msg.WithSender(ctx) } if cell := rcv.Cell(); cell != nil { cell.Send(msg) } else if svc, ok := ctx.Services()[rcv.Address().Service()]; ok { // TODO: check Address for sid, iid svc.Send(msg) } else { logging.WarnM(ctx, msg). Msg(fmt.Sprintf("scopes.Send: invalid address: %+v", rcv)) } }