64 lines
2.1 KiB
Go
64 lines
2.1 KiB
Go
package http
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/roots/wp-packages/internal/app"
|
|
"github.com/roots/wp-packages/internal/telemetry"
|
|
)
|
|
|
|
func handleAPIMonthlyInstalls(a *app.App) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
pkgType := strings.TrimPrefix(r.PathValue("type"), "wp-")
|
|
name := r.PathValue("name")
|
|
|
|
var packageID int64
|
|
err := a.DB.QueryRowContext(r.Context(),
|
|
`SELECT id FROM packages WHERE type = ? AND name = ? AND is_active = 1`,
|
|
pkgType, name,
|
|
).Scan(&packageID)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
http.Error(w, "package not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
if err != nil {
|
|
a.Logger.Error("looking up package", "error", err, "type", pkgType, "name", name)
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
installs, err := telemetry.GetMonthlyInstalls(r.Context(), a.DB, packageID)
|
|
if err != nil || len(installs) == 0 {
|
|
// Fallback to upstream for mirror mode where local monthly_installs table is absent
|
|
upstreamURL := "https://wp-packages.org/api/stats/packages/" + pkgType + "/" + name
|
|
body, fetchErr := fetchUpstreamJSON(upstreamURL, 15*time.Minute)
|
|
if fetchErr != nil {
|
|
if err != nil {
|
|
a.Logger.Error("querying monthly installs", "error", err, "package_id", packageID)
|
|
}
|
|
a.Logger.Error("fetching upstream monthly installs", "error", fetchErr, "url", upstreamURL)
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
var upstreamInstalls []telemetry.MonthlyInstall
|
|
if jsonErr := json.Unmarshal(body, &upstreamInstalls); jsonErr != nil {
|
|
a.Logger.Error("decoding upstream monthly installs", "error", jsonErr)
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
installs = upstreamInstalls
|
|
}
|
|
if installs == nil {
|
|
installs = []telemetry.MonthlyInstall{}
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Header().Set("Cache-Control", "public, max-age=300")
|
|
_ = json.NewEncoder(w).Encode(installs)
|
|
}
|
|
}
|