You've already forked openaccounting-server
forked from cybercinch/openaccounting-server
deps: update vendor dependencies for S3-compatible storage
Updates AWS SDK and removes Blazer B2 dependency in favor of unified S3-compatible approach. Includes configuration examples and documentation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
251
vendor/github.com/kurin/blazer/b2/monitor.go
generated
vendored
Normal file
251
vendor/github.com/kurin/blazer/b2/monitor.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
// Copyright 2017, the Blazer authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package b2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/kurin/blazer/internal/b2assets"
|
||||
"github.com/kurin/blazer/x/window"
|
||||
)
|
||||
|
||||
// StatusInfo reports information about a client.
|
||||
type StatusInfo struct {
|
||||
// Writers contains the status of all current uploads with progress.
|
||||
Writers map[string]*WriterStatus
|
||||
|
||||
// Readers contains the status of all current downloads with progress.
|
||||
Readers map[string]*ReaderStatus
|
||||
|
||||
// RPCs contains information about recently made RPC calls over the last
|
||||
// minute, five minutes, hour, and for all time.
|
||||
RPCs map[time.Duration]MethodList
|
||||
}
|
||||
|
||||
// MethodList is an accumulation of RPC calls that have been made over a given
|
||||
// period of time.
|
||||
type MethodList []method
|
||||
|
||||
// CountByMethod returns the total RPC calls made per method.
|
||||
func (ml MethodList) CountByMethod() map[string]int {
|
||||
r := make(map[string]int)
|
||||
for i := range ml {
|
||||
r[ml[i].name]++
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type method struct {
|
||||
name string
|
||||
duration time.Duration
|
||||
status int
|
||||
}
|
||||
|
||||
type methodCounter struct {
|
||||
d time.Duration
|
||||
w *window.Window
|
||||
}
|
||||
|
||||
func (mc methodCounter) record(m method) {
|
||||
mc.w.Insert([]method{m})
|
||||
}
|
||||
|
||||
func (mc methodCounter) retrieve() MethodList {
|
||||
ms := mc.w.Reduce()
|
||||
return MethodList(ms.([]method))
|
||||
}
|
||||
|
||||
func newMethodCounter(d, res time.Duration) methodCounter {
|
||||
r := func(i, j interface{}) interface{} {
|
||||
a, ok := i.([]method)
|
||||
if !ok {
|
||||
a = nil
|
||||
}
|
||||
b, ok := j.([]method)
|
||||
if !ok {
|
||||
b = nil
|
||||
}
|
||||
for _, m := range b {
|
||||
a = append(a, m)
|
||||
}
|
||||
return a
|
||||
}
|
||||
return methodCounter{
|
||||
d: d,
|
||||
w: window.New(d, res, r),
|
||||
}
|
||||
}
|
||||
|
||||
// WriterStatus reports the status for each writer.
|
||||
type WriterStatus struct {
|
||||
// Progress is a slice of completion ratios. The index of a ratio is its
|
||||
// chunk id less one.
|
||||
Progress []float64
|
||||
}
|
||||
|
||||
// ReaderStatus reports the status for each reader.
|
||||
type ReaderStatus struct {
|
||||
// Progress is a slice of completion ratios. The index of a ratio is its
|
||||
// chunk id less one.
|
||||
Progress []float64
|
||||
}
|
||||
|
||||
// Status returns information about the current state of the client.
|
||||
func (c *Client) Status() *StatusInfo {
|
||||
c.slock.Lock()
|
||||
defer c.slock.Unlock()
|
||||
|
||||
si := &StatusInfo{
|
||||
Writers: make(map[string]*WriterStatus),
|
||||
Readers: make(map[string]*ReaderStatus),
|
||||
RPCs: make(map[time.Duration]MethodList),
|
||||
}
|
||||
|
||||
for name, w := range c.sWriters {
|
||||
si.Writers[name] = w.status()
|
||||
}
|
||||
|
||||
for name, r := range c.sReaders {
|
||||
si.Readers[name] = r.status()
|
||||
}
|
||||
|
||||
for _, c := range c.sMethods {
|
||||
si.RPCs[c.d] = c.retrieve()
|
||||
}
|
||||
|
||||
return si
|
||||
}
|
||||
|
||||
func (si *StatusInfo) table() map[string]map[string]int {
|
||||
r := make(map[string]map[string]int)
|
||||
for d, c := range si.RPCs {
|
||||
for _, m := range c {
|
||||
if _, ok := r[m.name]; !ok {
|
||||
r[m.name] = make(map[string]int)
|
||||
}
|
||||
dur := "all time"
|
||||
if d > 0 {
|
||||
dur = d.String()
|
||||
}
|
||||
r[m.name][dur]++
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *Client) addWriter(w *Writer) {
|
||||
c.slock.Lock()
|
||||
defer c.slock.Unlock()
|
||||
|
||||
if c.sWriters == nil {
|
||||
c.sWriters = make(map[string]*Writer)
|
||||
}
|
||||
|
||||
c.sWriters[fmt.Sprintf("%s/%s", w.o.b.Name(), w.name)] = w
|
||||
}
|
||||
|
||||
func (c *Client) removeWriter(w *Writer) {
|
||||
c.slock.Lock()
|
||||
defer c.slock.Unlock()
|
||||
|
||||
if c.sWriters == nil {
|
||||
return
|
||||
}
|
||||
|
||||
delete(c.sWriters, fmt.Sprintf("%s/%s", w.o.b.Name(), w.name))
|
||||
}
|
||||
|
||||
func (c *Client) addReader(r *Reader) {
|
||||
c.slock.Lock()
|
||||
defer c.slock.Unlock()
|
||||
|
||||
if c.sReaders == nil {
|
||||
c.sReaders = make(map[string]*Reader)
|
||||
}
|
||||
|
||||
c.sReaders[fmt.Sprintf("%s/%s", r.o.b.Name(), r.name)] = r
|
||||
}
|
||||
|
||||
func (c *Client) removeReader(r *Reader) {
|
||||
c.slock.Lock()
|
||||
defer c.slock.Unlock()
|
||||
|
||||
if c.sReaders == nil {
|
||||
return
|
||||
}
|
||||
|
||||
delete(c.sReaders, fmt.Sprintf("%s/%s", r.o.b.Name(), r.name))
|
||||
}
|
||||
|
||||
var (
|
||||
funcMap = template.FuncMap{
|
||||
"inc": func(i int) int { return i + 1 },
|
||||
"lookUp": func(m map[string]int, s string) int { return m[s] },
|
||||
"pRange": func(i int) string {
|
||||
f := float64(i)
|
||||
min := int(math.Pow(2, f)) - 1
|
||||
max := min + int(math.Pow(2, f))
|
||||
return fmt.Sprintf("%v - %v", time.Duration(min)*time.Millisecond, time.Duration(max)*time.Millisecond)
|
||||
},
|
||||
"methods": func(si *StatusInfo) []string {
|
||||
methods := make(map[string]bool)
|
||||
for _, ms := range si.RPCs {
|
||||
for _, m := range ms {
|
||||
methods[m.name] = true
|
||||
}
|
||||
}
|
||||
var names []string
|
||||
for name := range methods {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
},
|
||||
"durations": func(si *StatusInfo) []string {
|
||||
var ds []time.Duration
|
||||
for d := range si.RPCs {
|
||||
ds = append(ds, d)
|
||||
}
|
||||
sort.Slice(ds, func(i, j int) bool { return ds[i] < ds[j] })
|
||||
var r []string
|
||||
for _, d := range ds {
|
||||
dur := "all time"
|
||||
if d > 0 {
|
||||
dur = d.String()
|
||||
}
|
||||
r = append(r, dur)
|
||||
}
|
||||
return r
|
||||
},
|
||||
"table": func(si *StatusInfo) map[string]map[string]int { return si.table() },
|
||||
}
|
||||
statusTemplate = template.Must(template.New("status").Funcs(funcMap).Parse(string(b2assets.MustAsset("data/status.html"))))
|
||||
)
|
||||
|
||||
// ServeHTTP serves diagnostic information about the current state of the
|
||||
// client; essentially everything available from Client.Status()
|
||||
//
|
||||
// ServeHTTP satisfies the http.Handler interface. This means that a Client
|
||||
// can be passed directly to a path via http.Handle (or on a custom ServeMux or
|
||||
// a custom http.Server).
|
||||
func (c *Client) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
info := c.Status()
|
||||
statusTemplate.Execute(rw, info)
|
||||
}
|
||||
Reference in New Issue
Block a user