diff --git a/.gitignore b/.gitignore index e69de29..a982e29 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,3 @@ +*.conf +overpush +overpushd diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7eed5da --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +SUBDIRS := client core server +SRCS := $(wildcard *.go $(foreach fd, $(SUBDIRS), $(fd)/*.go)) +TARGETS := overpush overpushd + +all: proto $(TARGETS) + go build ./... + +.PHONY: overpushd +overpushd: $(SRCS) cmd/overpushd/main.go + go build ./cmd/overpushd + +.PHONY: overpush +overpush: $(SRCS) cmd/overpush/main.go + go build ./cmd/overpush + +.PHONY: proto +proto: + ( cd proto && make ) + +print-%: ; @echo '$(subst ','\'',$*=$($*))' diff --git a/core/core.go b/core/core.go index e408cd8..8ff9304 100644 --- a/core/core.go +++ b/core/core.go @@ -1,11 +1,12 @@ package core import ( - "fmt" + "strings" "sync" "time" - pb "git.wntrmute.dev/kyle/overpush/proto" + "git.wntrmute.dev/kyle/goutils/backoff" + "git.wntrmute.dev/kyle/goutils/log" "github.com/gregdel/pushover" ) @@ -17,15 +18,21 @@ const MessageBuffer = 16 type Account struct { p *pushover.Pushover nextTransmit time.Time - q chan pb.Message + q chan *Message lock *sync.Mutex + bo *backoff.Backoff +} + +func (a *Account) Queue() chan<- *Message { + return a.q } func NewAccount(token string) *Account { return &Account{ p: pushover.New(token), - q: make(chan pb.Message, MessageBuffer), + q: make(chan *Message, MessageBuffer), lock: &sync.Mutex{}, + bo: backoff.New(4*time.Hour, 5*time.Second), } } @@ -40,19 +47,59 @@ func (a *Account) UpdateLimit(limit *pushover.Limit) { func (a *Account) Receive() { for { - for { - if a.nextTransmit.After(time.Now()) { - sleep := time.Until(a.nextTransmit) - time.Sleep(sleep) - } else { - break - } - } m, closed := <-a.q - if closed { + if !closed { panic("channel closed") } - fmt.Println(m.String()) + a.Push(m) } } + +func (a *Account) push(m *pushover.Message, r *pushover.Recipient) (*pushover.Response, error) { + for time.Now().Before(a.nextTransmit) { + log.Infof("delaying until next transmit: %s", a.nextTransmit.Format(time.DateTime)) + wait := time.Until(a.nextTransmit) + time.Sleep(wait) + } + + resp, err := a.p.SendMessage(m, r) + if err != nil { + return resp, err + } + + if resp.Limit != nil { + log.Debugf("API limits: %d / %d remaining", resp.Limit.Remaining, resp.Limit.Total) + log.Debugf("API next reset: %s", resp.Limit.NextReset.Format(time.DateTime)) + a.UpdateLimit(resp.Limit) + } + + return resp, nil +} + +func (a *Account) Push(m *Message) { + for i, r := range m.r { + recipient := pushover.NewRecipient(r) + resp, err := a.push(m.m, recipient) + if err != nil { + // if there's an error, log it, clean up the recipient list. + log.Errf("core: failed to send message: %s", err) + + if resp.Status/100 == 4 { + log.Errf("core: the Pushover API reported the following errors: %s", strings.Join(resp.Errors, ", ")) + log.Infoln("core: 4XX error from Pushover API; not retrying - dropping the message") + return + } + log.Infoln("core: requeueing message that failed to send") + log.Infoln("core: backing off") + m.r = m.r[i:] + a.q <- m + time.Sleep(a.bo.Duration()) + return + } + + a.bo.Reset() + } + + return +} diff --git a/core/message.go b/core/message.go new file mode 100644 index 0000000..def35e4 --- /dev/null +++ b/core/message.go @@ -0,0 +1,72 @@ +package core + +import ( + "bytes" + "time" + + "git.wntrmute.dev/kyle/goutils/log" + pb "git.wntrmute.dev/kyle/overpush/proto" + "github.com/gregdel/pushover" +) + +var priorityMap = map[pb.Priority]int{ + pb.Priority_PriorityInvalid: pushover.PriorityNormal, + pb.Priority_PriorityLowest: pushover.PriorityLowest, + pb.Priority_PriorityLow: pushover.PriorityLow, + pb.Priority_PriorityNormal: pushover.PriorityNormal, + pb.Priority_PriorityHigh: pushover.PriorityHigh, + pb.Priority_PriorityEmergency: pushover.PriorityEmergency, +} + +type Message struct { + m *pushover.Message + r []string + buf *bytes.Buffer +} + +func (m *Message) Close() error { + if m.buf != nil { + m.buf.Reset() + } + return nil +} + +func NewMessage(pbmsg *pb.Message) *Message { + msg := &Message{ + m: &pushover.Message{ + Message: pbmsg.Text, + }, + } + + if t := pbmsg.GetTimestamp(); t != 0 { + msg.m.Timestamp = t + } else { + msg.m.Timestamp = time.Now().Unix() + } + + priority, ok := priorityMap[pbmsg.Priority] + if !ok { + log.Warningln("core: message has an unknown priority; marking it as normal priority") + priority = pushover.PriorityNormal + } + msg.m.Priority = priority + + if url := pbmsg.GetUrl(); url != nil { + msg.m.URL = url.GetLink() + msg.m.URLTitle = url.GetTitle() + } + + if attachment := pbmsg.GetAttachment(); attachment != nil { + msg.buf = bytes.NewBuffer(attachment) + if err := msg.m.AddAttachment(msg.buf); err != nil { + log.Warningf("core: adding attachment to message failed: %s", err) + if pbmsg.Priority == pb.Priority_PriorityLowest { + return nil + } + log.Warningln("core: continuing without attachment") + } + } + + msg.r = pbmsg.GetRecipients() + return msg +} diff --git a/go.mod b/go.mod index 4aa4a21..1307ccd 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,20 @@ module git.wntrmute.dev/kyle/overpush go 1.20 require ( + git.wntrmute.dev/kyle/goutils v1.7.2 + github.com/gregdel/pushover v1.2.0 + google.golang.org/appengine v1.6.7 + google.golang.org/grpc v1.55.0 + google.golang.org/protobuf v1.30.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/gregdel/pushover v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/go-syslog v1.0.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect ) diff --git a/go.sum b/go.sum index 310941a..b7b42d3 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,34 @@ +git.wntrmute.dev/kyle/goutils v1.7.2 h1:0y1k4wXfNgFhwSE7TifmnYNaySUgGzU96o4YY2KYtQI= +git.wntrmute.dev/kyle/goutils v1.7.2/go.mod h1:1PGn83Ac98KWyI6yfpCVyP1Ji61PX6lFpROxY+IoTJg= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gregdel/pushover v1.2.0 h1:SLnpvJijUyEZvkJNyrldGhFhryYgQYlThSLpB5Oqt5k= github.com/gregdel/pushover v1.2.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= +github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= diff --git a/proto/message.pb.go b/proto/message.pb.go index e88cddd..de73484 100644 --- a/proto/message.pb.go +++ b/proto/message.pb.go @@ -20,55 +20,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type AlertType int32 +type MessageType int32 const ( - AlertType_AlertTypeInvalid AlertType = 0 - AlertType_AlertTypeMessage AlertType = 1 - AlertType_AlertTypeMessageWithTitle AlertType = 2 - AlertType_AlertTypeMessageWithAttachment AlertType = 3 + MessageType_MessageTypeInvalid MessageType = 0 + MessageType_MessageTypeMessage MessageType = 1 + MessageType_MessageTypeMessageWithTitle MessageType = 2 + MessageType_MessageTypeMessageWithAttachment MessageType = 3 ) -// Enum value maps for AlertType. +// Enum value maps for MessageType. var ( - AlertType_name = map[int32]string{ - 0: "AlertTypeInvalid", - 1: "AlertTypeMessage", - 2: "AlertTypeMessageWithTitle", - 3: "AlertTypeMessageWithAttachment", + MessageType_name = map[int32]string{ + 0: "MessageTypeInvalid", + 1: "MessageTypeMessage", + 2: "MessageTypeMessageWithTitle", + 3: "MessageTypeMessageWithAttachment", } - AlertType_value = map[string]int32{ - "AlertTypeInvalid": 0, - "AlertTypeMessage": 1, - "AlertTypeMessageWithTitle": 2, - "AlertTypeMessageWithAttachment": 3, + MessageType_value = map[string]int32{ + "MessageTypeInvalid": 0, + "MessageTypeMessage": 1, + "MessageTypeMessageWithTitle": 2, + "MessageTypeMessageWithAttachment": 3, } ) -func (x AlertType) Enum() *AlertType { - p := new(AlertType) +func (x MessageType) Enum() *MessageType { + p := new(MessageType) *p = x return p } -func (x AlertType) String() string { +func (x MessageType) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (AlertType) Descriptor() protoreflect.EnumDescriptor { +func (MessageType) Descriptor() protoreflect.EnumDescriptor { return file_message_proto_enumTypes[0].Descriptor() } -func (AlertType) Type() protoreflect.EnumType { +func (MessageType) Type() protoreflect.EnumType { return &file_message_proto_enumTypes[0] } -func (x AlertType) Number() protoreflect.EnumNumber { +func (x MessageType) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use AlertType.Descriptor instead. -func (AlertType) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use MessageType.Descriptor instead. +func (MessageType) EnumDescriptor() ([]byte, []int) { return file_message_proto_rawDescGZIP(), []int{0} } @@ -135,14 +135,15 @@ type Message struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Type AlertType `protobuf:"varint,2,opt,name=type,proto3,enum=overpush.AlertType" json:"type,omitempty"` - Priority Priority `protobuf:"varint,3,opt,name=priority,proto3,enum=overpush.Priority" json:"priority,omitempty"` - Recipients []string `protobuf:"bytes,4,rep,name=recipients,proto3" json:"recipients,omitempty"` - StreamName string `protobuf:"bytes,5,opt,name=stream_name,json=streamName,proto3" json:"stream_name,omitempty"` // string transmitter = 6; - Title string `protobuf:"bytes,8,opt,name=title,proto3" json:"title,omitempty"` - Text string `protobuf:"bytes,9,opt,name=text,proto3" json:"text,omitempty"` - Attachment []byte `protobuf:"bytes,10,opt,name=attachment,proto3" json:"attachment,omitempty"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Type MessageType `protobuf:"varint,2,opt,name=type,proto3,enum=overpush.MessageType" json:"type,omitempty"` + Priority Priority `protobuf:"varint,3,opt,name=priority,proto3,enum=overpush.Priority" json:"priority,omitempty"` + Recipients []string `protobuf:"bytes,4,rep,name=recipients,proto3" json:"recipients,omitempty"` + StreamName string `protobuf:"bytes,5,opt,name=stream_name,json=streamName,proto3" json:"stream_name,omitempty"` // string transmitter = 6; + Title string `protobuf:"bytes,8,opt,name=title,proto3" json:"title,omitempty"` + Text string `protobuf:"bytes,9,opt,name=text,proto3" json:"text,omitempty"` + Attachment []byte `protobuf:"bytes,10,opt,name=attachment,proto3" json:"attachment,omitempty"` + Url *URL `protobuf:"bytes,11,opt,name=url,proto3" json:"url,omitempty"` } func (x *Message) Reset() { @@ -177,18 +178,18 @@ func (*Message) Descriptor() ([]byte, []int) { return file_message_proto_rawDescGZIP(), []int{0} } -func (x *Message) GetTimestamp() uint64 { +func (x *Message) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *Message) GetType() AlertType { +func (x *Message) GetType() MessageType { if x != nil { return x.Type } - return AlertType_AlertTypeInvalid + return MessageType_MessageTypeInvalid } func (x *Message) GetPriority() Priority { @@ -233,45 +234,55 @@ func (x *Message) GetAttachment() []byte { return nil } +func (x *Message) GetUrl() *URL { + if x != nil { + return x.Url + } + return nil +} + var File_message_proto protoreflect.FileDescriptor var file_message_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x08, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x22, 0x8b, 0x02, 0x0a, 0x07, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x13, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x41, 0x6c, 0x65, - 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x08, - 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, - 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0a, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x74, 0x74, - 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x2a, 0x7a, 0x0a, 0x09, 0x41, 0x6c, 0x65, 0x72, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x6c, - 0x65, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x01, - 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x10, 0x02, 0x12, - 0x22, 0x0a, 0x1e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, - 0x74, 0x10, 0x03, 0x2a, 0x81, 0x01, 0x0a, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, - 0x79, 0x4c, 0x6f, 0x77, 0x65, 0x73, 0x74, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x6f, 0x77, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x10, 0x03, 0x12, 0x10, - 0x0a, 0x0c, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x48, 0x69, 0x67, 0x68, 0x10, 0x04, - 0x12, 0x15, 0x0a, 0x11, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6d, 0x65, 0x72, - 0x67, 0x65, 0x6e, 0x63, 0x79, 0x10, 0x05, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x08, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x1a, 0x09, 0x75, 0x72, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x02, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6f, + 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6f, 0x76, + 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, + 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x63, + 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, + 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, + 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x55, 0x52, 0x4c, + 0x52, 0x03, 0x75, 0x72, 0x6c, 0x2a, 0x84, 0x01, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x16, 0x0a, + 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x54, + 0x69, 0x74, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, + 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0x03, 0x2a, 0x81, 0x01, 0x0a, + 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x12, + 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x6f, 0x77, 0x65, 0x73, 0x74, + 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x6f, + 0x77, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4e, + 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x72, 0x69, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x48, 0x69, 0x67, 0x68, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x10, 0x05, + 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -289,18 +300,20 @@ func file_message_proto_rawDescGZIP() []byte { var file_message_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_message_proto_goTypes = []interface{}{ - (AlertType)(0), // 0: overpush.AlertType - (Priority)(0), // 1: overpush.Priority - (*Message)(nil), // 2: overpush.Message + (MessageType)(0), // 0: overpush.MessageType + (Priority)(0), // 1: overpush.Priority + (*Message)(nil), // 2: overpush.Message + (*URL)(nil), // 3: overpush.URL } var file_message_proto_depIdxs = []int32{ - 0, // 0: overpush.Message.type:type_name -> overpush.AlertType + 0, // 0: overpush.Message.type:type_name -> overpush.MessageType 1, // 1: overpush.Message.priority:type_name -> overpush.Priority - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 3, // 2: overpush.Message.url:type_name -> overpush.URL + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_message_proto_init() } @@ -308,6 +321,7 @@ func file_message_proto_init() { if File_message_proto != nil { return } + file_url_proto_init() if !protoimpl.UnsafeEnabled { file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Message); i { diff --git a/proto/message.proto b/proto/message.proto index 5911716..2a37eb7 100644 --- a/proto/message.proto +++ b/proto/message.proto @@ -2,12 +2,13 @@ syntax = 'proto3'; package overpush; option go_package = '.;pb'; +import 'url.proto'; -enum AlertType { - AlertTypeInvalid = 0; - AlertTypeMessage = 1; - AlertTypeMessageWithTitle = 2; - AlertTypeMessageWithAttachment = 3; +enum MessageType { + MessageTypeInvalid = 0; + MessageTypeMessage = 1; + MessageTypeMessageWithTitle = 2; + MessageTypeMessageWithAttachment = 3; } enum Priority { @@ -20,8 +21,8 @@ enum Priority { } message Message { - uint64 timestamp = 1; - AlertType type = 2; + int64 timestamp = 1; + MessageType type = 2; Priority priority = 3; repeated string recipients = 4; string stream_name = 5; @@ -30,4 +31,5 @@ message Message { string title = 8; string text = 9; bytes attachment = 10; + URL url = 11; } diff --git a/proto/response.pb.go b/proto/response.pb.go index c95c194..5dc7c3d 100644 --- a/proto/response.pb.go +++ b/proto/response.pb.go @@ -20,55 +20,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type TLDR int32 +type Status int32 const ( - TLDR_TLDRInvalid TLDR = 0 - TLDR_TLDRSent TLDR = 1 - TLDR_TLDRQueued TLDR = 2 - TLDR_TLDRFailed TLDR = 3 + Status_StatusInvalid Status = 0 + Status_StatusSent Status = 1 + Status_StatusQueued Status = 2 + Status_StatusFailed Status = 3 ) -// Enum value maps for TLDR. +// Enum value maps for Status. var ( - TLDR_name = map[int32]string{ - 0: "TLDRInvalid", - 1: "TLDRSent", - 2: "TLDRQueued", - 3: "TLDRFailed", + Status_name = map[int32]string{ + 0: "StatusInvalid", + 1: "StatusSent", + 2: "StatusQueued", + 3: "StatusFailed", } - TLDR_value = map[string]int32{ - "TLDRInvalid": 0, - "TLDRSent": 1, - "TLDRQueued": 2, - "TLDRFailed": 3, + Status_value = map[string]int32{ + "StatusInvalid": 0, + "StatusSent": 1, + "StatusQueued": 2, + "StatusFailed": 3, } ) -func (x TLDR) Enum() *TLDR { - p := new(TLDR) +func (x Status) Enum() *Status { + p := new(Status) *p = x return p } -func (x TLDR) String() string { +func (x Status) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (TLDR) Descriptor() protoreflect.EnumDescriptor { +func (Status) Descriptor() protoreflect.EnumDescriptor { return file_response_proto_enumTypes[0].Descriptor() } -func (TLDR) Type() protoreflect.EnumType { +func (Status) Type() protoreflect.EnumType { return &file_response_proto_enumTypes[0] } -func (x TLDR) Number() protoreflect.EnumNumber { +func (x Status) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use TLDR.Descriptor instead. -func (TLDR) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use Status.Descriptor instead. +func (Status) EnumDescriptor() ([]byte, []int) { return file_response_proto_rawDescGZIP(), []int{0} } @@ -77,9 +77,9 @@ type Response struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"` + Status Status `protobuf:"varint,3,opt,name=status,proto3,enum=overpush.Status" json:"status,omitempty"` Errors []string `protobuf:"bytes,4,rep,name=errors,proto3" json:"errors,omitempty"` // optional string receipt = 5; } @@ -115,7 +115,7 @@ func (*Response) Descriptor() ([]byte, []int) { return file_response_proto_rawDescGZIP(), []int{0} } -func (x *Response) GetTimestamp() uint64 { +func (x *Response) GetTimestamp() int64 { if x != nil { return x.Timestamp } @@ -129,11 +129,11 @@ func (x *Response) GetId() string { return "" } -func (x *Response) GetStatus() int32 { +func (x *Response) GetStatus() Status { if x != nil { return x.Status } - return 0 + return Status_StatusInvalid } func (x *Response) GetErrors() []string { @@ -147,19 +147,21 @@ var File_response_proto protoreflect.FileDescriptor var file_response_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x22, 0x68, 0x0a, 0x08, 0x52, 0x65, + 0x12, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x22, 0x7a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0x2a, 0x45, 0x0a, 0x04, 0x54, 0x4c, 0x44, 0x52, 0x12, 0x0f, 0x0a, 0x0b, - 0x54, 0x4c, 0x44, 0x52, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, - 0x08, 0x54, 0x4c, 0x44, 0x52, 0x53, 0x65, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x54, - 0x4c, 0x44, 0x52, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x54, - 0x4c, 0x44, 0x52, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x03, 0x42, 0x06, 0x5a, 0x04, 0x2e, - 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x28, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x75, 0x73, 0x68, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2a, 0x4f, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x65, 0x6e, + 0x74, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x51, 0x75, 0x65, + 0x75, 0x65, 0x64, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x03, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -177,15 +179,16 @@ func file_response_proto_rawDescGZIP() []byte { var file_response_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_response_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_response_proto_goTypes = []interface{}{ - (TLDR)(0), // 0: overpush.TLDR + (Status)(0), // 0: overpush.Status (*Response)(nil), // 1: overpush.Response } var file_response_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: overpush.Response.status:type_name -> overpush.Status + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_response_proto_init() } diff --git a/proto/response.proto b/proto/response.proto index 47b7953..01b0cd1 100644 --- a/proto/response.proto +++ b/proto/response.proto @@ -3,17 +3,17 @@ package overpush; option go_package = '.;pb'; -enum TLDR { - TLDRInvalid = 0; - TLDRSent = 1; - TLDRQueued = 2; - TLDRFailed = 3; +enum Status { + StatusInvalid = 0; + StatusSent = 1; + StatusQueued = 2; + StatusFailed = 3; } message Response { - uint64 timestamp = 1; + int64 timestamp = 1; string id = 2; - int32 status = 3; + Status status = 3; repeated string errors = 4; // optional string receipt = 5; -} \ No newline at end of file +} diff --git a/proto/url.pb.go b/proto/url.pb.go new file mode 100644 index 0000000..a1993d5 --- /dev/null +++ b/proto/url.pb.go @@ -0,0 +1,150 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.12.4 +// source: url.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type URL struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Link string `protobuf:"bytes,2,opt,name=link,proto3" json:"link,omitempty"` +} + +func (x *URL) Reset() { + *x = URL{} + if protoimpl.UnsafeEnabled { + mi := &file_url_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *URL) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*URL) ProtoMessage() {} + +func (x *URL) ProtoReflect() protoreflect.Message { + mi := &file_url_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use URL.ProtoReflect.Descriptor instead. +func (*URL) Descriptor() ([]byte, []int) { + return file_url_proto_rawDescGZIP(), []int{0} +} + +func (x *URL) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *URL) GetLink() string { + if x != nil { + return x.Link + } + return "" +} + +var File_url_proto protoreflect.FileDescriptor + +var file_url_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x75, 0x72, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6f, 0x76, 0x65, + 0x72, 0x70, 0x75, 0x73, 0x68, 0x22, 0x2f, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_url_proto_rawDescOnce sync.Once + file_url_proto_rawDescData = file_url_proto_rawDesc +) + +func file_url_proto_rawDescGZIP() []byte { + file_url_proto_rawDescOnce.Do(func() { + file_url_proto_rawDescData = protoimpl.X.CompressGZIP(file_url_proto_rawDescData) + }) + return file_url_proto_rawDescData +} + +var file_url_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_url_proto_goTypes = []interface{}{ + (*URL)(nil), // 0: overpush.URL +} +var file_url_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_url_proto_init() } +func file_url_proto_init() { + if File_url_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_url_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*URL); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_url_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_url_proto_goTypes, + DependencyIndexes: file_url_proto_depIdxs, + MessageInfos: file_url_proto_msgTypes, + }.Build() + File_url_proto = out.File + file_url_proto_rawDesc = nil + file_url_proto_goTypes = nil + file_url_proto_depIdxs = nil +} diff --git a/proto/url.proto b/proto/url.proto new file mode 100644 index 0000000..679c616 --- /dev/null +++ b/proto/url.proto @@ -0,0 +1,9 @@ +syntax = 'proto3'; +package overpush; + +option go_package = '.;pb'; + +message URL { + string title = 1; + string link = 2; +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..1728096 --- /dev/null +++ b/server/server.go @@ -0,0 +1,89 @@ +package server + +import ( + "context" + "errors" + "fmt" + "net" + "time" + + "git.wntrmute.dev/kyle/goutils/config" + "git.wntrmute.dev/kyle/goutils/log" + "git.wntrmute.dev/kyle/overpush/core" + pb "git.wntrmute.dev/kyle/overpush/proto" + "github.com/google/uuid" + "google.golang.org/grpc" +) + +type Service struct { + Default *core.Account + Accounts map[string]*core.Account + address string + Listener net.TCPListener + + // omg thank you for mentioning this in the docs ever you fucking asshats + pb.UnimplementedOverpushServer +} + +func (svc *Service) QueueMessage(ctx context.Context, msg *pb.Message) (*pb.Response, error) { + var acct *core.Account + var ok bool + + log.Debugf("message %d queued", msg.Timestamp) + + stream := msg.GetStreamName() + if stream == "" { + acct = svc.Default + } else if acct, ok = svc.Accounts[stream]; !ok { + return &pb.Response{ + Timestamp: time.Now().Unix(), + Id: uuid.NewString(), + Status: pb.Status_StatusFailed, + Errors: []string{fmt.Sprintf("server: invalid stream name %s", stream)}, + }, errors.New("service: invalid stream name " + stream) + } + + qmsg := core.NewMessage(msg) + if qmsg == nil { + log.Err("server: invalid message received, dropping") + return &pb.Response{ + Timestamp: time.Now().Unix(), + Id: uuid.NewString(), + Status: pb.Status_StatusFailed, + Errors: []string{"service: invalid message"}, + }, errors.New("server: invalid message received, dropping") + } + + acct.Queue() <- qmsg + return &pb.Response{ + Timestamp: time.Now().Unix(), + Id: uuid.NewString(), + Status: pb.Status_StatusQueued, + }, nil +} + +func New() (*Service, error) { + srv := &Service{ + address: config.GetDefault("address", "127.0.0.1:5000"), + } + + defaultToken := config.Get("primary_token") + if defaultToken == "" { + return nil, errors.New("server: no primary token defined") + } + srv.Default = core.NewAccount(defaultToken) + return srv, nil +} + +func Run(srv *Service) error { + var opts []grpc.ServerOption + + lsn, err := net.Listen("tcp4", srv.address) + if err != nil { + return fmt.Errorf("server: failed to set up listener: %w", err) + } + + grpcServer := grpc.NewServer(opts...) + pb.RegisterOverpushServer(grpcServer, srv) + return grpcServer.Serve(lsn) +}