Example #1
0
// GetIndexes is used in Subsonic to return an alphabetical index of artists and IDs
func GetIndexes(res http.ResponseWriter, req *http.Request) {
	// Retrieve render
	r := context.Get(req, api.CtxRender).(*render.Render)

	// Create a new response container, build indexes container
	c := newContainer()
	c.Indexes = &IndexesContainer{
		LastModified: common.ScanTime(),
	}

	// Fetch list of all artists, ordered alphabetically
	artists, err := data.DB.AllArtistsByTitle()
	if err != nil {
		log.Println(err)
		r.XML(res, 200, ErrGeneric)
		return
	}

	// Use a set to track indexes which already exist
	indexSet := set.New()

	// Iterate all artists and begin building indexes
	indexes := make([]Index, 0)

	// Use a counter which is incremented each time a new index is added, in order to
	// add artists at the right index
	i := -1
	for _, a := range artists {
		// Get the initial character of the artist title
		char := string(a.Title[0])

		// Create the index if it doesn't already exist, increment counter so new artists
		// slot into that index
		if indexSet.Add(char) {
			indexes = append(indexes, Index{Name: char})
			i++
		}

		// Add this folder to the index at the current position
		indexes[i].Artists = append(indexes[i].Artists, Artist{
			Name: a.Title,
			// Since Subsonic and wavepipe have different data models, we get around
			// the ID restriction by adding a prefix describing what this actually is
			ID: "artist_" + strconv.Itoa(a.ID),
		})
	}

	// Add indexes, write response
	c.Indexes.Indexes = indexes
	r.XML(res, 200, c)
}
Example #2
0
// GetDatabaseMetrics returns a variety of metrics about the wavepipe database, including
// total numbers of specific objects, and the time when the database was last updated
func GetDatabaseMetrics() (*DatabaseMetrics, error) {
	// Fetch total artists
	artists, err := data.DB.CountArtists()
	if err != nil {
		return nil, err
	}

	// Fetch total albums
	albums, err := data.DB.CountAlbums()
	if err != nil {
		return nil, err
	}

	// Fetch total songs
	songs, err := data.DB.CountSongs()
	if err != nil {
		return nil, err
	}

	// Fetch total folders
	folders, err := data.DB.CountFolders()
	if err != nil {
		return nil, err
	}

	// Fetch total art
	art, err := data.DB.CountArt()
	if err != nil {
		return nil, err
	}

	// Combine all metrics
	return &DatabaseMetrics{
		Updated: common.ScanTime(),
		Artists: artists,
		Albums:  albums,
		Songs:   songs,
		Art:     art,
		Folders: folders,
	}, nil
}
Example #3
0
// GetStatus returns the current server status, and optionally, server metrics, with
// an HTTP status and JSON.
func GetStatus(w http.ResponseWriter, r *http.Request) {
	// Retrieve render
	ren := context.Get(r, CtxRender).(*render.Render)

	// Output struct for songs request
	out := StatusResponse{}

	// Check API version
	if version, ok := mux.Vars(r)["version"]; ok {
		// Check if this API call is supported in the advertised version
		if !apiVersionSet.Has(version) {
			ren.JSON(w, 400, errRes(400, "unsupported API version: "+version))
			return
		}
	}

	// Retrieve current server status
	out.Status = common.ServerStatus()

	// If requested, fetch additional metrics (not added by default due to full table scans in database)
	if metricTypes := r.URL.Query().Get("metrics"); metricTypes != "" {
		// Begin building metrics
		outMetrics := &metrics.Metrics{}

		// Constants to check for various metric types
		const (
			mAll      = "all"
			mDatabase = "database"
			mNetwork  = "network"
		)

		// Set of valid metric types
		validSet := set.New(mAll, mDatabase, mNetwork)

		// Check for comma-separated list of metric types
		metricSet := set.New()
		for _, m := range strings.Split(metricTypes, ",") {
			// Add valid types to set
			if validSet.Has(m) {
				metricSet.Add(m)
			}
		}

		// If requested, get metrics about the database
		if metricSet.Has(mAll) || metricSet.Has(mDatabase) {
			// Check for cached metrics, and make sure they are up to date
			if databaseMetricsCache != nil && common.ScanTime() <= cacheTime {
				outMetrics.Database = databaseMetricsCache
			} else {
				// Fetch new metrics
				dbMetrics, err := metrics.GetDatabaseMetrics()
				if err != nil {
					log.Println(err)
					ren.JSON(w, 500, serverErr)
					return
				}
				outMetrics.Database = dbMetrics

				// Cache metrics and update time
				databaseMetricsCache = dbMetrics
				cacheTime = time.Now().Unix()
			}
		}

		// If requested, get metrics about the network
		if metricSet.Has(mAll) || metricSet.Has(mNetwork) {
			outMetrics.Network = &metrics.NetworkMetrics{
				RXBytes: metrics.RXBytes(),
				TXBytes: metrics.TXBytes(),
			}
		}

		// Return metrics
		out.Metrics = outMetrics
	}

	// HTTP 200 OK with JSON
	out.Error = nil
	ren.JSON(w, 200, out)
	return
}