diff --git a/README.md b/README.md index 2971000..a672bd6 100644 --- a/README.md +++ b/README.md @@ -40,4 +40,6 @@ Potentially needs `export GOPRIVATE="gogs.mikescher.com"` | | | | | rext | Mike | Regex Wrapper, wraps regexp with a better interface | | wmo | Mike | Mongo Wrapper, wraps mongodb with a better interface | +| | | | +| scn | Mike | SimpleCloudNotifier | | | | | \ No newline at end of file diff --git a/exerr/data.go b/exerr/data.go index 5d6b0b7..081cfe4 100644 --- a/exerr/data.go +++ b/exerr/data.go @@ -65,7 +65,7 @@ var ( TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) TypeAuthFailed = NewType("AUTH_FAILED", langext.Ptr(401)) - // other values come the used package + // other values come from the downstream application that uses goext ) var registeredTypes = dataext.SyncSet[string]{} diff --git a/goextVersion.go b/goextVersion.go index a912cc9..d03294f 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.352" +const GoextVersion = "0.0.353" -const GoextVersionTimestamp = "2023-12-29T19:29:36+0100" +const GoextVersionTimestamp = "2024-01-04T12:38:03+0100" diff --git a/scn/scn.go b/scn/scn.go new file mode 100644 index 0000000..858054a --- /dev/null +++ b/scn/scn.go @@ -0,0 +1,13 @@ +package scn + +type Connection struct { + uid string + token string +} + +func New(userid string, token string) *Connection { + return &Connection{ + uid: userid, + token: token, + } +} diff --git a/scn/send.go b/scn/send.go new file mode 100644 index 0000000..a446576 --- /dev/null +++ b/scn/send.go @@ -0,0 +1,171 @@ +package scn + +import ( + "bytes" + "context" + "gogs.mikescher.com/BlackForestBytes/goext/exerr" + json "gogs.mikescher.com/BlackForestBytes/goext/gojson" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "io" + "net/http" + "time" +) + +var ( + ErrAuthFailed = exerr.NewType("GOEXT_SCN_AUTHFAILED", nil) + ErrQuota = exerr.NewType("GOEXT_SCN_QUOTAEXCEEDED", nil) + ErrBadRequest = exerr.NewType("GOEXT_SCN_BADREQUEST", nil) + ErrInternalServerErr = exerr.NewType("GOEXT_SCN_INTERNALSERVER", nil) + ErrOther = exerr.NewType("GOEXT_SCN_OTHER", nil) +) + +type MessageResponse struct { + ErrHighlight int `json:"errhighlight"` + Error int `json:"error"` + IsPro bool `json:"is_pro"` + Message string `json:"message"` + Messagecount int `json:"messagecount"` + Quota int `json:"quota"` + QuotaMax int `json:"quota_max"` + SCNMessageID string `json:"scn_msg_id"` + Success bool `json:"success"` + SuppressSend bool `json:"suppress_send"` +} + +type MessageErrResponse struct { + Errhighlight int `json:"errhighlight"` + Error int `json:"error"` + Message string `json:"message"` + Success bool `json:"success"` +} + +type MessageBuilder struct { + conn *Connection + title string + content *string + channel *string + time *time.Time + sendername *string + priority *int +} + +func (c *Connection) Message(title string) *MessageBuilder { + return &MessageBuilder{conn: c, title: title} +} + +func (c *MessageBuilder) Channel(channel string) *MessageBuilder { + c.channel = &channel + return c +} + +func (c *MessageBuilder) Content(content string) *MessageBuilder { + c.content = &content + return c +} + +func (c *MessageBuilder) Time(t time.Time) *MessageBuilder { + c.time = &t + return c +} + +func (c *MessageBuilder) SenderName(sn string) *MessageBuilder { + c.sendername = &sn + return c +} + +func (c *MessageBuilder) Priority(p int) *MessageBuilder { + c.priority = &p + return c +} + +func (c *MessageBuilder) Send(ctx context.Context) (MessageResponse, error) { + client := http.Client{Timeout: 5 * time.Second} + + body := langext.H{} + + body["user_id"] = c.conn.uid + body["key"] = c.conn.token + + if c.channel != nil { + body["channel"] = *c.channel + } + + body["title"] = c.title + + if c.content != nil { + body["content"] = *c.content + } + + if c.sendername != nil { + body["content"] = *c.sendername + } + + if c.time != nil { + body["timestamp"] = c.time.Unix() + } + + if c.priority != nil { + body["priority"] = *c.priority + } + + body["msg_id"] = langext.MustHexUUID() + + rawbody, err := json.Marshal(body) + if err != nil { + return MessageResponse{}, err + } + + req, err := http.NewRequestWithContext(ctx, "POST", "https://simplecloudnotifier.de/", bytes.NewBuffer(rawbody)) + if err != nil { + return MessageResponse{}, err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + return MessageResponse{}, err + } + + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + + raw, err := io.ReadAll(resp.Body) + if err != nil { + return MessageResponse{}, err + } + + var mr MessageResponse + err = json.Unmarshal(raw, &mr) + if err != nil { + return MessageResponse{}, err + } + + return mr, nil + } else { + errMessage := resp.Status + + if raw, err := io.ReadAll(resp.Body); err == nil { + var mr MessageErrResponse + if err = json.Unmarshal(raw, &mr); err == nil { + errMessage = mr.Message + } + } + + if resp.StatusCode == 400 { + return MessageResponse{}, exerr.New(ErrBadRequest, errMessage).Build() + } + if resp.StatusCode == 401 { + return MessageResponse{}, exerr.New(ErrAuthFailed, errMessage).Build() + } + if resp.StatusCode == 403 { + return MessageResponse{}, exerr.New(ErrQuota, errMessage).Build() + } + if resp.StatusCode == 500 { + return MessageResponse{}, exerr.New(ErrInternalServerErr, errMessage).Build() + } + + return MessageResponse{}, exerr.New(ErrOther, errMessage).Build() + } + +} diff --git a/scn/send_test.go b/scn/send_test.go new file mode 100644 index 0000000..a16d61f --- /dev/null +++ b/scn/send_test.go @@ -0,0 +1,24 @@ +package scn + +import ( + "context" + "fmt" + "testing" +) + +func TestSendSCN(t *testing.T) { + t.Skip() + return + + mr, err := New("TODO", "TODO"). + Message("Hello Test"). + Content("This is a test / goext"). + Send(context.Background()) + + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", mr) + +}