Compare commits

..

5 Commits

Author SHA1 Message Date
5ba84bd8ee v0.0.319 fix error when findoneÃ+pipeline fails
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 1m15s
2023-11-13 16:45:00 +01:00
1260b2dc77 v0.0.318 add failure mail to testx.yml
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 1m9s
2023-11-13 15:34:58 +01:00
7d18b913c6 v0.0.317 try fix tests on pipeline
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 2m38s
2023-11-13 15:28:37 +01:00
d1f9069f2f v0.0.316 bugfix sorting
Some checks failed
Build Docker and Deploy / Run goext test-suite (push) Failing after 2m14s
2023-11-13 15:19:48 +01:00
fa6d73301e v0.0.315 atomic
Some checks failed
Build Docker and Deploy / Run goext test-suite (push) Failing after 1m26s
2023-11-12 03:10:55 +01:00
8 changed files with 155 additions and 98 deletions

View File

@@ -6,7 +6,12 @@
name: Build Docker and Deploy name: Build Docker and Deploy
run-name: Build & Deploy ${{ gitea.ref }} on ${{ gitea.actor }} run-name: Build & Deploy ${{ gitea.ref }} on ${{ gitea.actor }}
on: [push] on:
push:
branches:
- '*'
- '**'
jobs: jobs:
run_tests: run_tests:
@@ -34,3 +39,17 @@ jobs:
- name: Run tests - name: Run tests
run: cd "${{ gitea.workspace }}" && make test run: cd "${{ gitea.workspace }}" && make test
- name: Send failure mail
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.fastmail.com
server_port: 465
secure: true
username: ${{secrets.MAIL_USERNAME}}
password: ${{secrets.MAIL_PASSWORD}}
subject: Pipeline on '${{ gitea.repository }}' failed
to: ${{ steps.commiter_info.outputs.MAIL }}
from: Gitea Actions <gitea_actions@blackforestbytes.de>
body: "Go to https://gogs.blackforestbytes.com/${{ gitea.repository }}/actions"

2
go.mod
View File

@@ -1,6 +1,6 @@
module gogs.mikescher.com/BlackForestBytes/goext module gogs.mikescher.com/BlackForestBytes/goext
go 1.19 go 1.21
require ( require (
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1

View File

@@ -1,5 +1,5 @@
package goext package goext
const GoextVersion = "0.0.314" const GoextVersion = "0.0.319"
const GoextVersionTimestamp = "2023-11-10T13:37:54+0100" const GoextVersionTimestamp = "2023-11-13T16:45:00+0100"

View File

@@ -5,6 +5,7 @@ import (
"go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/rfctime" "gogs.mikescher.com/BlackForestBytes/goext/rfctime"
"reflect" "reflect"
) )
@@ -30,6 +31,9 @@ func CreateGoExtBsonRegistry() *bsoncodec.Registry {
rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.Date{}), rfctime.Date{}) rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.Date{}), rfctime.Date{})
rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.Date{}), rfctime.Date{}) rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.Date{}), rfctime.Date{})
rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.SecondsF64(0)), rfctime.SecondsF64(0))
rb.RegisterTypeDecoder(reflect.TypeOf(langext.Ptr(rfctime.SecondsF64(0))), rfctime.SecondsF64(0))
bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb) bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb) bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)

View File

@@ -1,33 +1,28 @@
package syncext package syncext
import ( import (
"context"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"sync" "sync"
"time"
) )
type AtomicBool struct { type Atomic[T any] struct {
v bool v T
listener map[string]chan bool lock sync.RWMutex
lock sync.Mutex
} }
func NewAtomicBool(value bool) *AtomicBool { func NewAtomic[T any](value T) *Atomic[T] {
return &AtomicBool{ return &Atomic[T]{
v: value, v: value,
listener: make(map[string]chan bool), lock: sync.RWMutex{},
lock: sync.Mutex{},
} }
} }
func (a *AtomicBool) Get() bool { func (a *Atomic[T]) Get() T {
a.lock.Lock() a.lock.RLock()
defer a.lock.Unlock() defer a.lock.RUnlock()
return a.v return a.v
} }
func (a *AtomicBool) Set(value bool) bool { func (a *Atomic[T]) Set(value T) T {
a.lock.Lock() a.lock.Lock()
defer a.lock.Unlock() defer a.lock.Unlock()
@@ -35,79 +30,5 @@ func (a *AtomicBool) Set(value bool) bool {
a.v = value a.v = value
for k, v := range a.listener {
select {
case v <- value:
// message sent
default:
// no receiver on channel
delete(a.listener, k)
}
}
return oldValue return oldValue
} }
func (a *AtomicBool) Wait(waitFor bool) {
_ = a.WaitWithContext(context.Background(), waitFor)
}
func (a *AtomicBool) WaitWithTimeout(timeout time.Duration, waitFor bool) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return a.WaitWithContext(ctx, waitFor)
}
func (a *AtomicBool) WaitWithContext(ctx context.Context, waitFor bool) error {
if err := ctx.Err(); err != nil {
return err
}
if a.Get() == waitFor {
return nil
}
uuid, _ := langext.NewHexUUID()
waitchan := make(chan bool)
a.lock.Lock()
a.listener[uuid] = waitchan
a.lock.Unlock()
defer func() {
a.lock.Lock()
delete(a.listener, uuid)
a.lock.Unlock()
}()
for {
if err := ctx.Err(); err != nil {
return err
}
timeOut := 1024 * time.Millisecond
if dl, ok := ctx.Deadline(); ok {
timeOutMax := dl.Sub(time.Now())
if timeOutMax <= 0 {
timeOut = 0
} else if 0 < timeOutMax && timeOutMax < timeOut {
timeOut = timeOutMax
}
}
if v, ok := ReadChannelWithTimeout(waitchan, timeOut); ok {
if v == waitFor {
return nil
}
} else {
if err := ctx.Err(); err != nil {
return err
}
if a.Get() == waitFor {
return nil
}
}
}
}

113
syncext/bool.go Normal file
View File

@@ -0,0 +1,113 @@
package syncext
import (
"context"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"sync"
"time"
)
type AtomicBool struct {
v bool
listener map[string]chan bool
lock sync.Mutex
}
func NewAtomicBool(value bool) *AtomicBool {
return &AtomicBool{
v: value,
listener: make(map[string]chan bool),
lock: sync.Mutex{},
}
}
func (a *AtomicBool) Get() bool {
a.lock.Lock()
defer a.lock.Unlock()
return a.v
}
func (a *AtomicBool) Set(value bool) bool {
a.lock.Lock()
defer a.lock.Unlock()
oldValue := a.v
a.v = value
for k, v := range a.listener {
select {
case v <- value:
// message sent
default:
// no receiver on channel
delete(a.listener, k)
}
}
return oldValue
}
func (a *AtomicBool) Wait(waitFor bool) {
_ = a.WaitWithContext(context.Background(), waitFor)
}
func (a *AtomicBool) WaitWithTimeout(timeout time.Duration, waitFor bool) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return a.WaitWithContext(ctx, waitFor)
}
func (a *AtomicBool) WaitWithContext(ctx context.Context, waitFor bool) error {
if err := ctx.Err(); err != nil {
return err
}
if a.Get() == waitFor {
return nil
}
uuid, _ := langext.NewHexUUID()
waitchan := make(chan bool)
a.lock.Lock()
a.listener[uuid] = waitchan
a.lock.Unlock()
defer func() {
a.lock.Lock()
delete(a.listener, uuid)
a.lock.Unlock()
}()
for {
if err := ctx.Err(); err != nil {
return err
}
timeOut := 1024 * time.Millisecond
if dl, ok := ctx.Deadline(); ok {
timeOutMax := dl.Sub(time.Now())
if timeOutMax <= 0 {
timeOut = 0
} else if 0 < timeOutMax && timeOutMax < timeOut {
timeOut = timeOutMax
}
}
if v, ok := ReadChannelWithTimeout(waitchan, timeOut); ok {
if v == waitFor {
return nil
}
} else {
if err := ctx.Err(); err != nil {
return err
}
if a.Get() == waitFor {
return nil
}
}
}
}

View File

@@ -81,13 +81,13 @@ func (c *Coll[TData]) findOneInternal(ctx context.Context, filter bson.M, allowN
if cursor.Next(ctx) { if cursor.Next(ctx) {
v, err := c.decodeSingle(ctx, cursor) v, err := c.decodeSingle(ctx, cursor)
if err != nil { if err != nil {
return nil, exerr.Wrap(err, "mongo-aggregation [find-one] failed").Any("pipeline", pipeline).Str("collection", c.Name()).Build() return nil, exerr.Wrap(err, "mongo-aggregation [find-one] failed to decode results").Any("pipeline", pipeline).Str("collection", c.Name()).Build()
} }
return &v, nil return &v, nil
} else if allowNull { } else if allowNull {
return nil, nil return nil, nil
} else { } else {
return nil, exerr.Wrap(err, "mongo-aggregation [find-one] failed").Any("pipeline", pipeline).Str("collection", c.Name()).Build() return nil, exerr.Wrap(mongo.ErrNoDocuments, "mongo-aggregation [find-one] returned no documents").Any("pipeline", pipeline).Str("collection", c.Name()).Build()
} }
} }
} }

View File

@@ -42,8 +42,8 @@ func (c *Coll[TData]) Paginate(ctx context.Context, filter pag.Filter, page int,
pipelineCount := mongo.Pipeline{} pipelineCount := mongo.Pipeline{}
pipelineCount = append(pipelineCount, bson.D{{Key: "$count", Value: "count"}}) pipelineCount = append(pipelineCount, bson.D{{Key: "$count", Value: "count"}})
pipelineList := langext.ArrConcat(mongo.Pipeline{}, pipelineFilter, pipelinePaginate, c.extraModPipeline) pipelineList := langext.ArrConcat(pipelineFilter, pipelineSort, pipelinePaginate, c.extraModPipeline)
pipelineTotalCount := langext.ArrConcat(mongo.Pipeline{}, pipelineFilter, pipelineCount) pipelineTotalCount := langext.ArrConcat(pipelineFilter, pipelineCount)
cursorList, err := c.coll.Aggregate(ctx, pipelineList) cursorList, err := c.coll.Aggregate(ctx, pipelineList)
if err != nil { if err != nil {