service

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Directory

type Directory struct {
	ID         int    `json:"id"`
	BeatmapID  int32  `json:"beatmap_id"`
	SongName   string `json:"song_name"`
	ArtistName string `json:"artist_name"`
	Beatmaps   []osu.DatabaseBeatmap
}

type Osu

type Osu struct {
	BeatmapDifficultyIndex map[int32]map[int32]int
	BeatmapByDifficultyId  map[int32]int32
	Logger                 *slog.Logger
	// contains filtered or unexported fields
}

func NewOsuService

func NewOsuService(gamePath string, logger *slog.Logger, repos *repository.Repos) (*Osu, error)

func (*Osu) GetBackgroundFile

func (o *Osu) GetBackgroundFile(path string) ([]byte, error)

func (*Osu) GetBackgroundFilePath

func (o *Osu) GetBackgroundFilePath(beatmapId int32) string

func (*Osu) GetBeatmapByDifficultyId

func (o *Osu) GetBeatmapByDifficultyId(difficultyId int32) (*osu.Beatmap, error)

func (*Osu) GetBeatmaps

func (o *Osu) GetBeatmaps() []osu.DatabaseBeatmap

func (*Osu) GetOsuFilePath

func (o *Osu) GetOsuFilePath(bm osu.DatabaseBeatmap) string

func (*Osu) GetTrackPathByDifficultyId

func (o *Osu) GetTrackPathByDifficultyId(ctx context.Context, difficultyId int32) (string, error)

func (*Osu) GetUserID

func (o *Osu) GetUserID(username string) (int, error)

func (*Osu) ParseBeatmapFile

func (o *Osu) ParseBeatmapFile(bm osu.DatabaseBeatmap) (*osu.Beatmap, error)

func (*Osu) ReadOsuDBFile

func (o *Osu) ReadOsuDBFile() error

type OsuSkins

type OsuSkins struct {
	// contains filtered or unexported fields
}

type ProgressEvent

type ProgressEvent struct {
	Stage   ProgressStage `json:"stage"`
	Table   string        `json:"table,omitempty"` // set on StageWrite: "beatmapsets" | "beatmaps" | "skill_cache"
	Done    int64         `json:"done"`
	Total   int64         `json:"total"`
	Message string        `json:"message,omitempty"`
	Err     string        `json:"error,omitempty"`
	At      time.Time     `json:"at"`
}

ProgressEvent is a single unit of live sync progress, meant to be forwarded to a frontend (e.g. published over the realtime websocket hub).

This intentionally carries only beatmap-level counts, not per-file or per-mod-combination detail (there's no BeatmapID/Mods field) — at 16k beatmaps × 36 mod combinations, anything finer-grained is 576k+ events for a single sync run, which floods the frontend far faster than a progress bar can usefully render and was observed to make the browser tab unresponsive. "N of 16000 beatmaps done" is all a human watching a progress bar actually needs. Emission is also rate-limited — see emitThrottled — so even StageCalcProgress/StageWrite fire at most a couple of times a second, not once per completed unit of work.

type ProgressStage

type ProgressStage string

ProgressStage identifies which phase of the sync a ProgressEvent describes. Deliberately coarse — see the package-level comment on ProgressEvent for why per-beatmap/per-mod-combination detail was cut.

const (
	StageReadDB       ProgressStage = "read_db"       // osu!.db parsed into raw rows
	StageDiff         ProgressStage = "diff"          // MD5 diff against stored beatmaps done
	StageCalcProgress ProgressStage = "calc_progress" // N/total beatmaps fully calculated (skill math for all mod combinations)
	StageWrite        ProgressStage = "write"         // a db upsert batch was flushed
	StageDone         ProgressStage = "done"          // Run() finished
)

type Syncer

type Syncer struct {
	// contains filtered or unexported fields
}

func NewSyncer

func NewSyncer(osuSvc *Osu, repos *repository.Repos, logger *slog.Logger, opts ...SyncerOption) *Syncer

NewSyncer requires an explicit logger rather than reaching into Osu's internal one — if you don't see sync logs, check what's passed here first (nil logger, or one configured below Info level, are the usual culprits).

func (*Syncer) Run

func (s *Syncer) Run(ctx context.Context) error

Run performs a full sync pass:

  1. parse osu!.db
  2. map rows into model.BeatmapSet / model.Beatmap
  3. diff MD5 hashes against what's already stored to find changed/new maps
  4. for changed maps only: parse the .osu file and compute Skills for every mod combination via skills.ProcessBeatmap
  5. persist everything, then drop rows for maps no longer present

type SyncerOption

type SyncerOption func(*Syncer)

func WithConcurrency

func WithConcurrency(n int) SyncerOption

func WithProgress

func WithProgress(ch chan<- ProgressEvent) SyncerOption

WithProgress attaches a channel that Syncer publishes ProgressEvent values to as it works. Sends are non-blocking — if the channel is full, the event is dropped rather than stalling the sync. Give the channel a reasonable buffer (e.g. 1024) and a goroutine that drains it promptly.

func WithSkillCalcTimeout

func WithSkillCalcTimeout(d time.Duration) SyncerOption

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL