manul sync backend works now

This commit is contained in:
Sticks
2025-05-20 13:01:02 -04:00
parent 7aa2dee280
commit 96abb94f21
9 changed files with 397 additions and 147 deletions

View File

@ -4,79 +4,40 @@ import (
"fmt"
"os"
"path/filepath"
"sync"
"time"
"github.com/wailsapp/wails/v2/pkg/logger"
)
// multiLogger fans every log call out to multiple logger.Logger targets with timestamps.
type multiLogger struct {
var (
baseTargets []logger.Logger
once sync.Once
initErr error
)
// InstancedLogger prefixes each message with its instance-specific prefix and a timestamp,
// while writing to shared log outputs.
type InstancedLogger struct {
prefix string
targets []logger.Logger
}
// timestamped prefixes each message with a timestamp.
func timestamped(message string) string {
return time.Now().Format("2006-01-02 15:04:05") + " " + message
// NewLogger returns a logger instance that writes to the shared logs
//
// but prefixes every message with [prefix].
func NewLogger(prefix string) (*InstancedLogger, error) {
once.Do(func() {
baseTargets, initErr = createBaseTargets()
})
if initErr != nil {
return nil, initErr
}
return &InstancedLogger{prefix: prefix, targets: baseTargets}, nil
}
func (m *multiLogger) Print(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Print(msg)
}
}
func (m *multiLogger) Trace(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Trace(msg)
}
}
func (m *multiLogger) Debug(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Debug(msg)
}
}
func (m *multiLogger) Info(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Info(msg)
}
}
func (m *multiLogger) Warning(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Warning(msg)
}
}
func (m *multiLogger) Error(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Error(msg)
}
}
func (m *multiLogger) Fatal(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Fatal(msg)
}
}
// NewRuntimeFileLogger returns a logger that writes all output both to
//
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_latest.log (or OS equivalent)
//
// and to a timestamped file
//
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_YYYY-MM-DD_HH-MM-SS.log (or OS equivalent)
//
// It also deletes any timestamped logs older than 14 days.
//
// The returned logger implements github.com/wailsapp/wails/v2/pkg/logger.Logger
// and will be used by Wails for all Go-side logging.
func NewRuntimeFileLogger() (logger.Logger, error) {
// Make sure the log directory exists
// We use $XDG_CONFIG_HOME/FanslySync/logs/runtime_latest.log or OS equivalent for $XDG_CONFIG_HOME
// createBaseTargets initializes the shared log file and console loggers once.
func createBaseTargets() ([]logger.Logger, error) {
cfgDir, err := os.UserConfigDir()
if err != nil {
return nil, fmt.Errorf("cannot determine user config dir: %w", err)
@ -86,8 +47,7 @@ func NewRuntimeFileLogger() (logger.Logger, error) {
return nil, fmt.Errorf("cannot create log directory: %w", err)
}
// Prune old logs
// We keep logs for 14 days, so delete any logs older than that
// Prune logs older than 14 days
cutoff := time.Now().Add(-14 * 24 * time.Hour)
entries, _ := os.ReadDir(logDir)
for _, e := range entries {
@ -103,20 +63,53 @@ func NewRuntimeFileLogger() (logger.Logger, error) {
}
}
// Remove old runtime_latest.log if it exists
runtimePath := filepath.Join(logDir, "runtime_latest.log")
if _, err := os.Stat(runtimePath); err == nil {
_ = os.Remove(runtimePath)
}
// Prepare file paths
ts := time.Now().Format("2006-01-02_15-04-05")
tsPath := filepath.Join(logDir, fmt.Sprintf("runtime_%s.log", ts))
latestPath := filepath.Join(logDir, "runtime_latest.log")
// Create loggers to attach to the multiLogger
// Create loggers
tsLogger := logger.NewFileLogger(tsPath)
latestLogger := logger.NewFileLogger(latestPath)
termLogger := logger.NewDefaultLogger()
// Spread into a multiLogger
// This will fan out all log messages to all three loggers
multi := &multiLogger{
targets: []logger.Logger{tsLogger, latestLogger, termLogger},
}
return multi, nil
return []logger.Logger{tsLogger, latestLogger, termLogger}, nil
}
// log dispatches a timestamped, prefixed message to all shared targets.
func (l *InstancedLogger) log(level, message string) {
timestamp := time.Now().Format("2006-01-02 15:04:05")
fullMsg := fmt.Sprintf("%s [%s] %s", timestamp, l.prefix, message)
for _, t := range l.targets {
switch level {
case "Print":
t.Print(fullMsg)
case "Trace":
t.Trace(fullMsg)
case "Debug":
t.Debug(fullMsg)
case "Info":
t.Info(fullMsg)
case "Warning":
t.Warning(fullMsg)
case "Error":
t.Error(fullMsg)
case "Fatal":
t.Fatal(fullMsg)
}
}
}
func (l *InstancedLogger) Print(message string) { l.log("Print", message) }
func (l *InstancedLogger) Trace(message string) { l.log("Trace", message) }
func (l *InstancedLogger) Debug(message string) { l.log("Debug", message) }
func (l *InstancedLogger) Info(message string) { l.log("Info", message) }
func (l *InstancedLogger) Warning(message string) { l.log("Warning", message) }
func (l *InstancedLogger) Error(message string) { l.log("Error", message) }
func (l *InstancedLogger) Fatal(message string) { l.log("Fatal", message) }

View File

@ -1,7 +1,15 @@
package utils
import (
"FanslySync/structs"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
@ -54,3 +62,76 @@ func ShowMessageBox(ctx context.Context, title, message string, opts ...MessageB
// Show the message box
runtime.MessageDialog(ctx, options)
}
func UploadPaste(payload []byte) (string, error) {
// Create HTTP client
client := &http.Client{}
// Max request duration is 30s
client.Timeout = 30 * time.Second
// Create request
var payloadStruct structs.PastePayload
payloadStruct.Content = string(payload)
// Marshal the payload to JSON
payloadJSON, err := json.Marshal(payloadStruct)
if err != nil {
return "", err
}
// Create request (POST to https://paste.hep.gg/api/)
req, err := http.NewRequest("POST", "https://paste.hep.gg/api/", nil)
if err != nil {
return "", err
}
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "FanslySync/3.0 sticks@teamhydra.dev")
req.Header.Set("Accept", "application/json")
req.Header.Set("Accept-Encoding", "gzip")
// Set the body
req.Body = io.NopCloser(bytes.NewBuffer(payloadJSON))
// Send the request
resp, err := client.Do(req)
if err != nil {
return "", err
}
// Check for non-200 status code
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
// Read the response body into our struct
var pasteResponse structs.PastePutResponse
data, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
// Unmarshal the response into our struct
err = json.Unmarshal(data, &pasteResponse)
if err != nil {
return "", err
}
// Check for error in response
if pasteResponse.Error != "" {
return "", fmt.Errorf("error from paste server: %s", pasteResponse.Error)
}
// Return the paste ID
return fmt.Sprintf("https://paste.hep.gg/api/%s/raw", pasteResponse.Payload.Id), nil
}
// percentage calculates the percentage of curr out of total.
func Percentage(curr, total int) float64 {
if total == 0 {
return 0
}
return float64(curr) / float64(total) * 100
}