chore: rename everything to versia

This commit is contained in:
DevMiner 2024-08-28 00:25:25 +02:00
parent 0223ea0535
commit 3876ad2738
112 changed files with 587 additions and 576 deletions

View file

@ -0,0 +1,150 @@
package versiautils
import (
"encoding/json"
"errors"
"fmt"
"slices"
)
var (
validTextContentTypes = []string{"text/html", "text/plain"}
validImageContentTypes = []string{"image/png", "image/jpeg", "image/gif", "image/svg+xml"}
)
// ContentMap is a map of content types to their respective content.
type ContentMap[T any] map[string]T
type UnexpectedContentTypeError struct {
MIMEType string
}
func (e UnexpectedContentTypeError) Error() string {
return fmt.Sprintf("unexpected content type: %s", e.MIMEType)
}
func (m ContentMap[T]) unmarshalJSON(raw []byte, valid []string) error {
var cm map[string]json.RawMessage
if err := json.Unmarshal(raw, &cm); err != nil {
return err
}
m = make(ContentMap[T])
errs := make([]error, 0)
for k, v := range cm {
if valid != nil {
if !slices.Contains(valid, k) {
errs = append(errs, UnexpectedContentTypeError{k})
continue
}
}
var c T
if err := json.Unmarshal(v, &c); err != nil {
errs = append(errs, err)
continue
}
m[k] = c
}
if len(errs) > 0 {
return MultipleError{errs}
}
return nil
}
func (m ContentMap[T]) getPreferred(preferred []string) *T {
for _, v := range preferred {
if c, ok := m[v]; ok {
return &c
}
}
return nil
}
// TextContent is embedded string. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/structures/content-format
type TextContent struct {
Content string `json:"content"`
// Remote is always false
Remote bool `json:"remote"`
}
type TextContentTypeMap ContentMap[TextContent]
func (t TextContentTypeMap) UnmarshalJSON(data []byte) error {
return (ContentMap[TextContent])(t).unmarshalJSON(data, validTextContentTypes)
}
func (t TextContentTypeMap) String() string {
if c := (ContentMap[TextContent])(t).getPreferred(validTextContentTypes); c != nil {
return c.Content
}
return ""
}
// File is a file or other piece of content. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/structures/content-format
type File struct {
// Remote is always true
Remote bool `json:"remote"`
// URL to the attachment
Content *URL `json:"content"`
Description string `json:"description"`
Hash DataHash `json:"hash"`
Size int `json:"size"`
// BlurHash is available when the content type is an image
BlurHash *string `json:"blurhash,omitempty"`
// BlurHash is available when the content type is an image
Height *int `json:"height,omitempty"`
// BlurHash is available when the content type is an image
Width *int `json:"width,omitempty"`
FPS *int `json:"fps,omitempty"`
}
type DataHash struct {
SHA256 string `json:"sha256"`
}
type ImageContentMap ContentMap[File]
func (i ImageContentMap) UnmarshalJSON(data []byte) error {
return (ContentMap[File])(i).unmarshalJSON(data, validImageContentTypes)
}
func (i ImageContentMap) String() string {
if c := (ContentMap[File])(i).getPreferred(validImageContentTypes); c != nil {
return c.Content.String()
}
return ""
}
type NoteAttachmentContentMap ContentMap[File]
var ErrContentMapEntryNotRemote = errors.New("content map entry not remote")
func (i NoteAttachmentContentMap) UnmarshalJSON(data []byte) error {
if err := (ContentMap[File])(i).unmarshalJSON(data, nil); err != nil {
return err
}
errs := make([]error, 0)
for _, a := range i {
if !a.Remote {
errs = append(errs, ErrContentMapEntryNotRemote)
}
}
if len(errs) > 0 {
return MultipleError{errs}
}
return nil
}

View file

@ -1,85 +0,0 @@
package versiautils
import (
"encoding/json"
"slices"
"github.com/rs/zerolog/log"
)
var (
validTextContentTypes = []string{"text/html", "text/plain"}
validImageContentTypes = []string{"image/png", "image/jpeg", "image/gif", "image/svg+xml"}
)
// ContentTypeMap is a map of content types to their respective content.
type ContentTypeMap[T any] map[string]T
func (m *ContentTypeMap[T]) unmarshalJSON(raw []byte, valid []string) error {
var cm map[string]json.RawMessage
if err := json.Unmarshal(raw, &cm); err != nil {
return err
}
*m = make(ContentTypeMap[T])
for k, v := range cm {
if !slices.Contains(valid, k) {
// TODO: replace with logr
log.Debug().Caller().Str("mimetype", k).Msg("unexpected content type, skipping")
continue
}
var c T
if err := json.Unmarshal(v, &c); err != nil {
return err
}
(*m)[k] = c
}
return nil
}
func (m ContentTypeMap[T]) getPreferred(preferred []string) *T {
for _, v := range preferred {
if c, ok := m[v]; ok {
return &c
}
}
return nil
}
type TextContent struct {
Content string `json:"content"`
}
type TextContentTypeMap ContentTypeMap[TextContent]
func (t *TextContentTypeMap) UnmarshalJSON(data []byte) error {
return (*ContentTypeMap[TextContent])(t).unmarshalJSON(data, validTextContentTypes)
}
func (t TextContentTypeMap) String() string {
if c := (ContentTypeMap[TextContent])(t).getPreferred(validTextContentTypes); c != nil {
return c.Content
}
return ""
}
type ImageContent struct {
Content *URL `json:"content"`
}
type ImageContentTypeMap ContentTypeMap[ImageContent]
func (i *ImageContentTypeMap) UnmarshalJSON(data []byte) error {
return (*ContentTypeMap[ImageContent])(i).unmarshalJSON(data, validImageContentTypes)
}
func (i ImageContentTypeMap) String() string {
if c := (ContentTypeMap[ImageContent])(i).getPreferred(validImageContentTypes); c != nil {
return c.Content.String()
}
return ""
}

View file

@ -0,0 +1,22 @@
package versiautils
import (
"strings"
)
type MultipleError struct {
Errors []error
}
func (e MultipleError) Error() string {
s := strings.Builder{}
for i, err := range e.Errors {
s.WriteString(err.Error())
if i != len(e.Errors) {
s.WriteRune('\n')
}
}
return s.String()
}