diff --git a/api/bandwidth.go b/api/bandwidth.go new file mode 100644 index 0000000..9434a6f --- /dev/null +++ b/api/bandwidth.go @@ -0,0 +1,79 @@ +/** + * Standalone signaling server for the Nextcloud Spreed app. + * Copyright (C) 2025 struktur AG + * + * @author Joachim Bauch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package api + +import ( + "sync/atomic" + + "github.com/strukturag/nextcloud-spreed-signaling/internal" +) + +// Bandwidth stores a bandwidth in bits per second. +type Bandwidth uint64 + +// Bits returns the bandwidth in bits per second. +func (b Bandwidth) Bits() uint64 { + return uint64(b) +} + +// Bytes returns the bandwidth in bytes per second. +func (b Bandwidth) Bytes() uint64 { + return b.Bits() / 8 +} + +// BandwidthFromBits creates a bandwidth from bits per second. +func BandwidthFromBits(b uint64) Bandwidth { + return Bandwidth(b) +} + +// BandwithFromBits creates a bandwidth from megabits per second. +func BandwidthFromMegabits(b uint64) Bandwidth { + return Bandwidth(b * 1024 * 1024) +} + +// BandwidthFromBytes creates a bandwidth from bytes per second. +func BandwidthFromBytes(b uint64) Bandwidth { + return Bandwidth(b * 8) +} + +// AtomicBandwidth is an atomic Bandwidth. The zero value is zero. +// AtomicBandwidth must not be copied after first use. +type AtomicBandwidth struct { + // 64-bit members that are accessed atomically must be 64-bit aligned. + v uint64 + _ internal.NoCopy +} + +// Load atomically loads and returns the value stored in b. +func (b *AtomicBandwidth) Load() Bandwidth { + return Bandwidth(atomic.LoadUint64(&b.v)) // +checklocksignore +} + +// Store atomically stores v into b. +func (b *AtomicBandwidth) Store(v Bandwidth) { + atomic.StoreUint64(&b.v, uint64(v)) // +checklocksignore +} + +// Swap atomically stores v into b and returns the previous value. +func (b *AtomicBandwidth) Swap(v Bandwidth) Bandwidth { + return Bandwidth(atomic.SwapUint64(&b.v, uint64(v))) // +checklocksignore +} diff --git a/api/bandwidth_test.go b/api/bandwidth_test.go new file mode 100644 index 0000000..935c8f1 --- /dev/null +++ b/api/bandwidth_test.go @@ -0,0 +1,58 @@ +/** + * Standalone signaling server for the Nextcloud Spreed app. + * Copyright (C) 2025 struktur AG + * + * @author Joachim Bauch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package api + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBandwidth(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + + var b Bandwidth + assert.EqualValues(0, b.Bits()) + assert.EqualValues(0, b.Bytes()) + + b = BandwidthFromBits(8000) + assert.EqualValues(8000, b.Bits()) + assert.EqualValues(1000, b.Bytes()) + + b = BandwidthFromBytes(1000) + assert.EqualValues(8000, b.Bits()) + assert.EqualValues(1000, b.Bytes()) + + b = BandwidthFromMegabits(2) + assert.EqualValues(2*1024*1024, b.Bits()) + assert.EqualValues(2*1024*1024/8, b.Bytes()) + + var a AtomicBandwidth + assert.EqualValues(0, a.Load()) + a.Store(1000) + assert.EqualValues(1000, a.Load()) + old := a.Swap(2000) + assert.EqualValues(1000, old) + assert.EqualValues(2000, a.Load()) +} diff --git a/internal/nocopy.go b/internal/nocopy.go new file mode 100644 index 0000000..cc81cc3 --- /dev/null +++ b/internal/nocopy.go @@ -0,0 +1,35 @@ +/** + * Standalone signaling server for the Nextcloud Spreed app. + * Copyright (C) 2025 struktur AG + * + * @author Joachim Bauch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package internal + +// NoCopy may be added to structs which must not be copied +// after the first use. +// +// See https://golang.org/issues/8005#issuecomment-190753527 +// for details. +// +// Note that it must not be embedded, due to the Lock and Unlock methods. +type NoCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*NoCopy) Lock() {} +func (*NoCopy) Unlock() {}