feat: add a platform-aware apps download page
ci / api / api (push) Successful in 48s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m10s
ci / db / db (push) Successful in 57s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m1s
ci / desktop / rust (desktop proxy) (push) Successful in 5m37s
ci / ts / ts (packages + web) (push) Successful in 4m10s
release / release (версия и заметки) (push) Successful in 11s
release / android (APK в релиз) (push) Successful in 4m22s
ci / api / api (push) Successful in 48s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m10s
ci / db / db (push) Successful in 57s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m1s
ci / desktop / rust (desktop proxy) (push) Successful in 5m37s
ci / ts / ts (packages + web) (push) Successful in 4m10s
release / release (версия и заметки) (push) Successful in 11s
release / android (APK в релиз) (push) Successful in 4m22s
Serve desktop and Android builds from the latest Gitea release on /download, and fix the desktop compile and CI flakes that blocked v1.3.0. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
efe78d7e07
commit
597067689a
30 files changed
+1180
-395
No files matched your search
@@ -28,6 +28,14 @@ const (
|
||||
BearerAuthScopes = "bearerAuth.Scopes"
|
||||
)
|
||||
|
||||
// Defines values for AppClient.
|
||||
const (
|
||||
AppClientAndroid AppClient = "android"
|
||||
AppClientLinux AppClient = "linux"
|
||||
AppClientMacos AppClient = "macos"
|
||||
AppClientWindows AppClient = "windows"
|
||||
)
|
||||
|
||||
// Defines values for AuthTokensTokenType.
|
||||
const (
|
||||
Bearer AuthTokensTokenType = "Bearer"
|
||||
@@ -35,9 +43,9 @@ const (
|
||||
|
||||
// Defines values for ClientType.
|
||||
const (
|
||||
Android ClientType = "android"
|
||||
Desktop ClientType = "desktop"
|
||||
Web ClientType = "web"
|
||||
ClientTypeAndroid ClientType = "android"
|
||||
ClientTypeDesktop ClientType = "desktop"
|
||||
ClientTypeWeb ClientType = "web"
|
||||
)
|
||||
|
||||
// Defines values for HealthStatusStatus.
|
||||
@@ -319,6 +327,26 @@ type AndroidRelease struct {
|
||||
VersionCode int `json:"version_code"`
|
||||
}
|
||||
|
||||
// AppClient defines model for AppClient.
|
||||
type AppClient string
|
||||
|
||||
// AppClientFile defines model for AppClientFile.
|
||||
type AppClientFile struct {
|
||||
Client AppClient `json:"client"`
|
||||
DownloadUrl string `json:"download_url"`
|
||||
Filename string `json:"filename"`
|
||||
Sha256 *string `json:"sha256,omitempty"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
// AppClients defines model for AppClients.
|
||||
type AppClients struct {
|
||||
Clients []AppClientFile `json:"clients"`
|
||||
NotesMd string `json:"notes_md"`
|
||||
Version string `json:"version"`
|
||||
VersionCode int `json:"version_code"`
|
||||
}
|
||||
|
||||
// Artist defines model for Artist.
|
||||
type Artist struct {
|
||||
AlbumCount int `json:"album_count"`
|
||||
@@ -1688,6 +1716,12 @@ type ServerInterface interface {
|
||||
// Последняя версия Android-приложения (из релизов Gitea через сервер)
|
||||
// (GET /api/v1/app/android/latest)
|
||||
GetAndroidLatest(w http.ResponseWriter, r *http.Request)
|
||||
// Клиенты последнего релиза (Android и десктоп)
|
||||
// (GET /api/v1/app/clients)
|
||||
GetAppClients(w http.ResponseWriter, r *http.Request)
|
||||
// Файл клиента (кэшируется на сервере, поддерживает Range)
|
||||
// (GET /api/v1/app/download/{client}/{version})
|
||||
DownloadAppClient(w http.ResponseWriter, r *http.Request, client AppClient, version string)
|
||||
// Исполнитель
|
||||
// (GET /api/v1/artists/{id})
|
||||
GetArtist(w http.ResponseWriter, r *http.Request, id EntityId)
|
||||
@@ -2054,6 +2088,18 @@ func (_ Unimplemented) GetAndroidLatest(w http.ResponseWriter, r *http.Request)
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Клиенты последнего релиза (Android и десктоп)
|
||||
// (GET /api/v1/app/clients)
|
||||
func (_ Unimplemented) GetAppClients(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Файл клиента (кэшируется на сервере, поддерживает Range)
|
||||
// (GET /api/v1/app/download/{client}/{version})
|
||||
func (_ Unimplemented) DownloadAppClient(w http.ResponseWriter, r *http.Request, client AppClient, version string) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Исполнитель
|
||||
// (GET /api/v1/artists/{id})
|
||||
func (_ Unimplemented) GetArtist(w http.ResponseWriter, r *http.Request, id EntityId) {
|
||||
@@ -3438,6 +3484,54 @@ func (siw *ServerInterfaceWrapper) GetAndroidLatest(w http.ResponseWriter, r *ht
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetAppClients operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetAppClients(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetAppClients(w, r)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// DownloadAppClient operation middleware
|
||||
func (siw *ServerInterfaceWrapper) DownloadAppClient(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var err error
|
||||
|
||||
// ------------- Path parameter "client" -------------
|
||||
var client AppClient
|
||||
|
||||
err = runtime.BindStyledParameterWithOptions("simple", "client", chi.URLParam(r, "client"), &client, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "client", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Path parameter "version" -------------
|
||||
var version string
|
||||
|
||||
err = runtime.BindStyledParameterWithOptions("simple", "version", chi.URLParam(r, "version"), &version, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "version", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.DownloadAppClient(w, r, client, version)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetArtist operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtist(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -5074,6 +5168,12 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/app/android/latest", wrapper.GetAndroidLatest)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/app/clients", wrapper.GetAppClients)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/app/download/{client}/{version}", wrapper.DownloadAppClient)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/artists/{id}", wrapper.GetArtist)
|
||||
})
|
||||
@@ -6269,6 +6369,74 @@ func (response GetAndroidLatestdefaultApplicationProblemPlusJSONResponse) VisitG
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type GetAppClientsRequestObject struct {
|
||||
}
|
||||
|
||||
type GetAppClientsResponseObject interface {
|
||||
VisitGetAppClientsResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type GetAppClients200JSONResponse AppClients
|
||||
|
||||
func (response GetAppClients200JSONResponse) VisitGetAppClientsResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type GetAppClientsdefaultApplicationProblemPlusJSONResponse struct {
|
||||
Body Problem
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (response GetAppClientsdefaultApplicationProblemPlusJSONResponse) VisitGetAppClientsResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/problem+json")
|
||||
w.WriteHeader(response.StatusCode)
|
||||
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type DownloadAppClientRequestObject struct {
|
||||
Client AppClient `json:"client"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type DownloadAppClientResponseObject interface {
|
||||
VisitDownloadAppClientResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type DownloadAppClient200ApplicationoctetStreamResponse struct {
|
||||
Body io.Reader
|
||||
ContentLength int64
|
||||
}
|
||||
|
||||
func (response DownloadAppClient200ApplicationoctetStreamResponse) VisitDownloadAppClientResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
if response.ContentLength != 0 {
|
||||
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
|
||||
}
|
||||
w.WriteHeader(200)
|
||||
|
||||
if closer, ok := response.Body.(io.ReadCloser); ok {
|
||||
defer closer.Close()
|
||||
}
|
||||
_, err := io.Copy(w, response.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
type DownloadAppClientdefaultApplicationProblemPlusJSONResponse struct {
|
||||
Body Problem
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (response DownloadAppClientdefaultApplicationProblemPlusJSONResponse) VisitDownloadAppClientResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/problem+json")
|
||||
w.WriteHeader(response.StatusCode)
|
||||
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type GetArtistRequestObject struct {
|
||||
Id EntityId `json:"id"`
|
||||
}
|
||||
@@ -7816,6 +7984,12 @@ type StrictServerInterface interface {
|
||||
// Последняя версия Android-приложения (из релизов Gitea через сервер)
|
||||
// (GET /api/v1/app/android/latest)
|
||||
GetAndroidLatest(ctx context.Context, request GetAndroidLatestRequestObject) (GetAndroidLatestResponseObject, error)
|
||||
// Клиенты последнего релиза (Android и десктоп)
|
||||
// (GET /api/v1/app/clients)
|
||||
GetAppClients(ctx context.Context, request GetAppClientsRequestObject) (GetAppClientsResponseObject, error)
|
||||
// Файл клиента (кэшируется на сервере, поддерживает Range)
|
||||
// (GET /api/v1/app/download/{client}/{version})
|
||||
DownloadAppClient(ctx context.Context, request DownloadAppClientRequestObject) (DownloadAppClientResponseObject, error)
|
||||
// Исполнитель
|
||||
// (GET /api/v1/artists/{id})
|
||||
GetArtist(ctx context.Context, request GetArtistRequestObject) (GetArtistResponseObject, error)
|
||||
@@ -8972,6 +9146,57 @@ func (sh *strictHandler) GetAndroidLatest(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
// GetAppClients operation middleware
|
||||
func (sh *strictHandler) GetAppClients(w http.ResponseWriter, r *http.Request) {
|
||||
var request GetAppClientsRequestObject
|
||||
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.GetAppClients(ctx, request.(GetAppClientsRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "GetAppClients")
|
||||
}
|
||||
|
||||
response, err := handler(r.Context(), w, r, request)
|
||||
|
||||
if err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
} else if validResponse, ok := response.(GetAppClientsResponseObject); ok {
|
||||
if err := validResponse.VisitGetAppClientsResponse(w); err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
}
|
||||
} else if response != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
|
||||
}
|
||||
}
|
||||
|
||||
// DownloadAppClient operation middleware
|
||||
func (sh *strictHandler) DownloadAppClient(w http.ResponseWriter, r *http.Request, client AppClient, version string) {
|
||||
var request DownloadAppClientRequestObject
|
||||
|
||||
request.Client = client
|
||||
request.Version = version
|
||||
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.DownloadAppClient(ctx, request.(DownloadAppClientRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "DownloadAppClient")
|
||||
}
|
||||
|
||||
response, err := handler(r.Context(), w, r, request)
|
||||
|
||||
if err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
} else if validResponse, ok := response.(DownloadAppClientResponseObject); ok {
|
||||
if err := validResponse.VisitDownloadAppClientResponse(w); err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
}
|
||||
} else if response != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
|
||||
}
|
||||
}
|
||||
|
||||
// GetArtist operation middleware
|
||||
func (sh *strictHandler) GetArtist(w http.ResponseWriter, r *http.Request, id EntityId) {
|
||||
var request GetArtistRequestObject
|
||||
@@ -10343,273 +10568,278 @@ func (sh *strictHandler) GetReadyz(w http.ResponseWriter, r *http.Request) {
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"zW9kz1wBAA==",
|
||||
"H4sIAAAAAAAC/+y9fW8cx5Uv/FUas/sAZHZEUrLlJBIWD2T5TbtWzIjy4+ci0h02Z4pkr3q6x909lBhD",
|
||||
"ACnGkX2piGtvdjdI1na8uYu9QP4ZURxpRPEF8Cfo/gr5JBd1TlV1VXdVdw/ZQ9mLBYJYnOmprpdTp06d",
|
||||
"8zu/80mj7Xd7vke8KGxc+qTRswO7SyISwF9X+0HoB/RfHRK2A6cXOb7XuNSIv4qH8XGyER/Fz5ONeJA8",
|
||||
"jA+T7fiFFe8nW8lGshkfJRtWPIqfW4seuRe12tDQogU/GsZ7yXa8l2wln8fD+IWVbCYPaCvxYTxKfp1s",
|
||||
"N5oNh77l4z4J1hvNhmd3SeNSA9toNBthe5V0bdqraL1HvwmjwPFWGvfvNxtve5ETrV/r0G+hkZ4draZt",
|
||||
"OJ1GsxGQj/tOQDqNS1HQJ3J7y37QtaPGpUa/D0/m23/f6TqRaDzTQxe+lBvskGW770aNSxfnmo2ufc/p",
|
||||
"9ruNSxfm6F+Oh3+dF+9xvIiskABetOD3gzaZ3EA+7Lm+3VmI7KgfvuO4EdEt87fJg3iQPEi2ks1k20oe",
|
||||
"xkNYvudW/DwexMfJDnz3uNFskHs91++QxqVl2w2JfgFDeJkyP05EuiBpfx2Q5calxl/NpuI4i4+Fs3JX",
|
||||
"G/fFYOwgsNfp32G07tIP6KDp3x+GJJjUxN2nPw57vhcS6Pd84C+5pEv/2fa9iHggHHav5zptm07jbA+f",
|
||||
"+Jt/COmcfiK9q2jMvF14Y2ZVvk4+i0fxk3g/HlhTN965av309Ys/noZVZT+nrV/pdB2PTgVs68DvkSBy",
|
||||
"sNPtgNgR6bTsSBlyx47Iucjpkvy4m42OE/Zce72F0/hJw+u7rr1E5x2nMPcDp1NhPpsNJ2wtuX77DulI",
|
||||
"G3rJ911ie/R71w6jluuvOF5Rd0t74/pt2yUandFsdPth1Gqv2t4KabUD0iFe5NhuqO+O/HDPDsO7fmDo",
|
||||
"eEDWHHI3bPVBekPN7vq3+Ch+Fg+TBxbo0M1kMz6A7bYRj+Jd+NcjKz4S226P/nkYD6x4Lz6Kn8SDeDd+",
|
||||
"GQ+p2oyHMxZVylayCR/tJVvQMKhg0NMv45FF/3cgXho/SbbhFckWbXaYbMb79MHkUbwfj5JPrfhl8jje",
|
||||
"4yqaKujnyVa6hvJYfZzbIom+QZ+532z0QxJwIcqrpXRn/gK3qng8I4Lspfl5FmutyJZh5cyr35R3SVYM",
|
||||
"b4tJ8Jf+gbQjOi6x3+btFZLfc0LTVVJ56ebV6DvpRK2wE7OTCq9XG9EOx13qd/PDsIPICaPS7sNTN8gy",
|
||||
"bantr5Gg1fZdP1AnILcTswPFX/YDt5LC6fQD0LgtpXVxplbWSJETGTRFFNjtO9UX8SZ9XDeudWIXrZxs",
|
||||
"BuT2A/aOtSFPUWaim3yp1IkRgzCuOV21/IlxRmt46iU6i6k1Tt1Cv9u1g/Uf1K6pZ1O02n4fTZ/8tjtj",
|
||||
"aZf7U7ZS77NVOZWqllc+txxa7avtlme766ETMjM3L0L0+1+SoLVGgmrq0PeIfkGWbcdVzC3pu4/7pG/6",
|
||||
"Luh7Hm1c+2Xk91okCLS3xW/jAVg2O/QKQQ2dB/BHfCQZsmBhDOM9aqNQY2Qr3qMGDn0i+TTZTHasv2z8",
|
||||
"1oqP46N4DyyVQfyc/n/TSh4mD+Ij2vQIbpAPkkflFmFmXdiw0zGy+ROT1VQXQB6vfjU7ge90bhCX2KHG",
|
||||
"Guj4dz1qrvBtmjdKHa8V9ns9P4hwOTJT+iW1CZPNeITzNaI2nUWtwmQH7maHyTb8GR/GR/EuzgqdxUZT",
|
||||
"s3aeH5Gw1dW95z9hblkrR/HT+Miaum4Hd+gAhHU5pNYlfe20TnWEq/aFi29oRxk6vySK+nG86I3XtX1c",
|
||||
"I0Ho4A2K3LO7Pbjxzc28MXNe9072dKsNd9JPynQNbzzzQ2lmWF/FaJrqEmYXTCsTvd5V12E3ROJR6+oX",
|
||||
"DRsFpdFs3HW8jn8X7FfH69+jTdptX1YW6fBEU+84rka62uI1hYpL9Od+s1wglx2XGMz2epY4syRsDNKL",
|
||||
"xRIofS2c6dA0N2Ood2Wqdda4tHlMclj0XZ0yygennRRhg2QOFnp+FZ3fFS0Eo3CUGAi6Y5+tt9y1Cge7",
|
||||
"MJ/yJ/qphmDsobYX/Y4TXWlHfnDibpz0hmzszttepLVK21FOo9LGZvDmq+uazQdmu+4Hy41LvyjZPOlk",
|
||||
"3L+d9WPRExoOdXqMgVEwpFYCPVVexiOLWQAvky/iQ+5dPmb+iedwHA3gJy81x/395ol8XBXXp2evU/UD",
|
||||
"09DpOHQ4tjsvTS1aHAYLJF2byA5WSNTSv7XUvmO/xs/H9gKARQML0+RyoDYpdy8dsjKvRnmrxQOSCu4r",
|
||||
"c4H0o9Wb/h3i6czxdpuEYSuiX2u1HrnXcwISthxP61ffiI/ifSt+BnbTYTyysMFz1NyK98GpR03bzXgY",
|
||||
"7ydb8WG8B3ERjVFOlgMSrqY9ybzqt/HLZMdaxJMBlvaSxYyORSseZb7pkPBO5PcWtVdA+gYhb9yAeZPY",
|
||||
"AQm0VkqfOZ+Llvk6yS2PMrXKa5VZZe3rFu5N34/CKLB7V1OH3g3ycZ/ozj+P3NV5cqVTgdxtVVfJytNN",
|
||||
"tXVdX6+C63GePWLsZbsfBHSZSnta8ICmp8VdA8m4mVnwu2QJbkPcbmUio5WAq6AsPgxJYBxYNq7Qte+9",
|
||||
"T7yVaLVx6Y3XNU2Wu9W/5a5qK95Ntukhgo70AZwoo+QBRq+eJhvJFpwk+zOW5IuHL/mPYDuiR/zIgs8P",
|
||||
"6C3zDJ3gkizBC7QLhTpZH+yJSLfnB3awrohGZs6+Aa1DZ22bHqx0IuDOTW/bdMAWzmnjhLtccmdrhkdb",
|
||||
"zXdSN9C314gXvWlH7dX8OMnaWHb9vGuvQ3Nw27bvXcMfXZybK3HhsPcUd+8GCSHsqzs2epHJwdLpY9iQ",
|
||||
"GBzYAaFv0voDvqU2U/IZRHAOLOZi2Ui246E1das/N/casV6bs+K9+DAexi+mhZG1Cd4WOIV24yH8jtpa",
|
||||
"BxaEoYbYXvltTYxLGYTUY910veMQt/M29xllHc4dYriHEreCcsPHmtiO7uXvEduNVk3etlB8ztWef0ej",
|
||||
"4TIvZb/Svs4JIz9Yp1J24nsB1ZNjWrRwZ6oYp9CZiOkreVsFg6vD7JPn6VXZfe/5YfSWE+idwx1nXH88",
|
||||
"4A9KBZahFKB5Xafed5aofjRsF+F51fptWhUFLCBuy9DbZiMEQEq1pnKbEfsgNyK9rdkwO1LlYdchX8o0",
|
||||
"vioBY50wuvrdpb4phmmzMEHpiauGE+7zAImhWVghWIWCBwxfdZ0wdLyVVsEjuOzVVwnBT9h3kypIg7H5",
|
||||
"992110pNsY/sNXKdRIHTDvPHGZurJl8L8To+E9lhq1OYjlhaMdYtrUD4K45ntv3TG1rZoCSTHXBDa06b",
|
||||
"CNM6h+EbABxvFB/Ew2TD+u7PV1cDv0usWesj9EV/97Jpfffneececa2ffPcSXNLCOj8vWUqyb6TgfnIi",
|
||||
"q1fCasgToZvG6+T7jXX6bxDS9waE5LR6AVkuhx468/DY2eKWRO9Oh1rSbZEPvCXfDjosjKtDKahaeiIw",
|
||||
"kCyeMX4SvwSJwEAwRIsx1hg/QWFIPuMfDEA26MfoK0420SuMoV/wB+9UcZ++uqiG/MsxUSbZWV0hXkCK",
|
||||
"Fqym7mt6XqV7aRN53ZR5g/h3Uzp82fCK5fjqqu+0iUmaW05HnZ/SFZd9AZVmvPRMTFt8rcy5IHW6cPjz",
|
||||
"drQ6b0cRCTyNRRy2iEeF33gorJB7+Z7PlZm3+Lum3L6hb7Rf+utTD78cw08jjbRkdfI3KnxVQSfnUQuf",
|
||||
"9lbBmjGZqn2va0ftVb3bx3CHSH9T3n2j5TjJ2W42QhY0PE2aQ/UFE/46zankRfTGhSq9dDvyx7ORDLDO",
|
||||
"mcUvA8pCYgftVVDPrkt4rGwVHRUNBpnSur+XA79bgkZVj8IPP7z21tqPqbn1wIr3AVUzjA+TB/EA0U/7",
|
||||
"1BpKHlKLag+ipcf0UfbMYXwE/rsRvYyUaTm/DRGF8exif3nZdRRUmaRVmKvINNyeHzqF6Fw8XKrCETNr",
|
||||
"B/ZVGNlBxJxWLeKBv+GO04MlJHfgKtEP0fQK+zBC17kD9pbH/tFxQvER/7duYamotEISAgzjJB6R9BFp",
|
||||
"4OqqmDbBkt2+cxVF2ORJzF887CXiFthpn9Q0RGOH6VWeGHdudUBBdgLu39aE/tm1FztdagiWCibu77Fs",
|
||||
"iKymhCZajtfBc1fn2e8RO2p1mddbOJ2Xl6lUeKiXXK0shqv95WXXsCmLNlXpzPR7nbKrc2kba77bV0xQ",
|
||||
"r99d0uh+aRPIC8JnX51CocMb6fDVORQvlqVBGdHtMmm95vX6UaHIjiWoGbEsd6SoYimO0blmPSJaGPLK",
|
||||
"SWzx67+X0ptKnjBIzjd1A6lDIk3S5DIjuLp2o79I0eS5YG4tGSi6keqsrtvSKAzbQbFfFLG+MKeVa02c",
|
||||
"//wFtBPF36ZA1mkuc0p3cB7oKe983CfsCTg99BdfeZRyX4qWvY7cgrxAnDS9INtSPX5SdfHLMrIqoLxP",
|
||||
"65Wh96EM4DZnYhZAXSuceFWxoVmhET3LOoDU7Cwl6bDCcUXX9EN4bHw1g1s6r2TkSRzj+iZ+ZlAk0h3Z",
|
||||
"HL8sN9fsaLUF0f3QDMA0OyTT2WO3zfSMy4VHjlhgJNkEuOkxy0cZgiMy+SweML8lQPUEmhXQfBw3Yz6o",
|
||||
"lOOzIOwaCCRJqaK/TiIbztQ7Tq9ncv5E9sqpJi636CKIq05o2g11zVgPxMCKgr9Scr0eHZKLZQwgo0jg",
|
||||
"hffpOsh5RiMr3gNApHP+J14TAhlKDGzR7kerM463ZrtOR/asL+r1X2Q7rh5OlewkmwCtgcAIfy3Iy1Mq",
|
||||
"TtYU/VZ8fswBWPHABHN+rM2uSYO2RpaAETgUwGNAWz1MtpNP2UsgrsLIHDbio2QzHjSa1c4mCb2jBT0E",
|
||||
"djcsg0jnVjzF3Wi0N7uqCmdTw17y+9GlJdf27jQqYnMKEEE3iN2OSOcmh8yc/nw8BfpGOQfMyBu5z3XA",
|
||||
"I5Q5ODU8otmI/Mh2x/B64vPlCAroJ09eYNeNjA9Hd9vgPzMYs4HUauks0efy2pB9Yehzx4j5aK8SZtib",
|
||||
"FLO6vRf9O4scxLe4bDvuojWFmozlQaLHUMWv7nL9AyHaYbIBmYGbhry9jD75YzyMnydbEI0DVhiLMQDt",
|
||||
"QkugZqgGewaBYaZVsH2qXVPfZMGml8B29P0rgd1RHOClextnUT/7gJM3uspLcPQsodOKRxwjf9miI4+f",
|
||||
"UE3KQuPxIPkieWClGH465W3fv+OQau6yGyyELbIDO11AutObdWBjtkYG9Z6u10Lb9uYDfyUgoQ5U1OmY",
|
||||
"YKfVja9ihJDnhKundBct+33P0Mvlvusa4BCIxDGgk/w107h7gd8mYVg93Vl6J/iaxz0O/BZ7ZeHto4K6",
|
||||
"TLOUYVaU7qgrwadUebs89CaTjPT1fM7SiRULX2SsUfEz7i6+eDk7CXYOVVmMaeqRFe9S3WQlv4oH8Yv4",
|
||||
"ZbLdtKhNRI0lVZtBTjIgnAFVEj+nNlx8KPLFhhqUiG7TLUB8BxHbhWi8GugAmlqQRWVSiDyqIggAX91C",
|
||||
"qq38DP9ratqB/t+DrIenoKER8ANxpkG8RzVW0wIEDsB0jukcj5LN5FO4zNDZPkCQDj1i8BKEJuwhmN0v",
|
||||
"QcU/qrLLT2RF6G3cX4OFvU8l5Ch+AoRyTxkZAAxkIN/e9pg5/gJ3QFXIZRFw0oxCrAwp1CIpJuHnK0I1",
|
||||
"sinOi1S5LbZAgjUSXPOWfc3m6Tktbeb+mjZtf4knbrVk6IhWaeziDW8XxVPKzcFcUpDtB/ER/S8V6s+T",
|
||||
"L5i0olkyTDaSz6iqEIFVHmtV0GnStQyVU4Z/wgBF6zpei2VItbJp3rk7K/Q5PmDIJry5sh9d9TvEYqbH",
|
||||
"OXZRRaQUCHKy04Q7LhvoER0edJBKerIB2YUsmyc1+IbJBiTSsZU4Pzf3059qSSGYjy1ds57T65/r9kOn",
|
||||
"raV54OQHLcSxhcqP6ZlFXwumcXXYmCQ7JgKMZEcZWzywphZI9/8jwbQ8zMbczPmZudJbInPdpbn2sgDr",
|
||||
"xliw1lpx1m+gkA+yJuCvelnNzhwYqwfJjtg9cOmvZsOwPERtBtIQ0KMolaP4uSqaL+gqgQsiHlDDWPI5",
|
||||
"aLdQBrtcGwTXDqNWPzy1j1fungpM1hHH8Rem81cgB3UEDrhInTxggBB8UwZbEaL4G1BTXKcxADBCVTY4",
|
||||
"GlgGFCODjR5QbE397J0F1MiH9PoI1otIThzQqyx8cRQfCC3PmwMJg9Pg0bRWxCZIEQCrHrbtGkgrhWtY",
|
||||
"k7K5B2bNMbN/OAZIAGEf0b+t96+9eePKjf/Reu+DhZtNemnfgqv4EZ58mPX3CO7u1AZHD0ElK84UhPGW",
|
||||
"wxa5RxVlpZ1LH/dhWKGxuRBsjErN0VmvHgtRLs1aNAmsIj0XgzXbbXUdrx/pHDLxP8a7KIgwj2Ajg50w",
|
||||
"QtVHDYZDKUyQ8cxQwQYWZaTTLQ8apE6Tqok06a9aXRKGzFtYgWdipdULHD9wovVSO9RemeePSh7b8h7y",
|
||||
"g+tu4ESkFZFuz2Uhrcws/5806oKi/AD3O1wFk0/FtRFd7B2/Hc4yTTXT7fzVj6fVQM1QZHsXhWoqxPqY",
|
||||
"5pdEVdkGqpArGzszwSZ5a+YUb26ymhLBsrrMGX2UOaFgw5iPAIOvVHMOaMh7FQVWCQugBw0oGuWUGkSr",
|
||||
"MbQ7XAQ/L1bZka94o0iTeLEcyy3LrXntazFF0JA4rSUyr8/6LzdHvkW3EMbV0OTAOxID0zIb5WfvLJxL",
|
||||
"PuU09JBN/zm1P4K7wMmSPMRDNjU5BnqjQkLeqx0BYnRUPPSk5m8fYfaT5s0iA3/E8vmZmtvh5s8hWE/g",
|
||||
"WE+24mN6dZxuWlQ8Ja7E7Is2GZffQNv7H/iGVWd8zjTbEMgvO6sbNe/xWo+2y1k7LtmKn6DPI3mEWXjs",
|
||||
"Ooz+BAjCgNTG+0i3Bb9afP3CBQti3QBBmeG9a7EI+OItL9m0FjGYOxMQO/S9xRkLTPw08MN8b+hxkWI9",
|
||||
"7IQVpJSSVTrggW8oFcGFnzk1cNmG1JY/zvOSWIswk+d4X2ch6LM4c8tT81MNStCgXhZyMage8Tro/O76",
|
||||
"fQ8d4+j9hhhjNv9FisNkk5dPyvdQzyXCTNpYt6F8NhZpgRVW2f4pMXlukjAyMrj0O46f5rrnDpt9hTAI",
|
||||
"KYfiI8UsBdTJC+aNPmJxW3U7CYWPt+GRSspD98/5ubm5aa2OkqYyn8FxR2+ooXIa51qAv8D2MpPwJyTu",
|
||||
"w3gA+t+fpzRMKbMf08aLM+BY5Ls6jBbp2SdPI6qKzFF/2cI4N1XeYNRPm3eDKesQ4syplMhrWyAdmdwT",
|
||||
"b1mY9Hp9EAXE7v68b7vs0BDR3X7kN5oNP3BWHA9gD6vOyir0qONADpLr39U2KR8tUoORvRK2lp0A0pYY",
|
||||
"6Ir+oW2CMy7NSwnkVZijirdjRSInA8jG5kUHSiNsLCBWazTNXrMdJj05mf5nsLIeWVmDi56tbG9bUxor",
|
||||
"LmOEwY5vpj/Bo/CAMS8N9SZlxwnbLc+vwqFeoQrCMrGjfsDnu4rqh8V6h/8sT+QZ/yNXcyxE8RwUFzVc",
|
||||
"p8DtB3QAFtNnnCoaT3kGfxtwf2Hya6S03sWc7mQb/HnUANoAXXjIdCEaCvFT0JwH4Gnm+JLcwaTJ2S0N",
|
||||
"PFRmzEkRQ9UmM8UO6c9QqisMefLc4weQnfgQlB+1oJLNZDt+iScHyJM4dqyp8xes5OH0ZdnvhLeK/PVh",
|
||||
"WMUHUl4JoJqgFpH9q4joTNQyzYtON4b0ankXK9MprZW0B4y66R1pl6g6aqnXLRggTyahF0ESrKxXetT1",
|
||||
"+x2PhGHL7SMlRckvMpNHeyTel23NOMJrnVBnmYY1phHlFrmgO3W4GqqFwc2ehhRFbT6Z8pTIQFKdVvjI",
|
||||
"P2D+igpwNbV+Eh1WslOrvfiE1TtE9rQyPeke5ntd7GVW4QN7xmZGt0ackSW/Qt0lznqvC/X4Ybhsd0gr",
|
||||
"VDLC3miWpLat+l3SonpjzdEDMbPUmWglgBp+CrHOXbjCv2BoQfr5brIdP8EKiViqYQecEDt4WlLz+ACs",
|
||||
"34fsnHsMPh29bQD96/p+p/auHWKlDsQVsPP2BB3s+kuOS1qQHR7IxiqQneRJsaSLK9U9LisfoEHgAWyr",
|
||||
"1fZd1+6FRHsZ20UACEBid2UIBz1C9wEQtQ9zcBzvJ1vAhvkSzkKYlSdQ6jD5FZ3FZIseuuYJAO+efgZY",
|
||||
"R3kSoaaj/0TvgrQ3cO05pktBD2lpXdI+G3vQJl7EQA98huETeiKQZbr3AmdlVX8ZiFZJV7nTdOzgDuTH",
|
||||
"0180G+F6GJGuORV+zQ4cWy1s4QdL0MDH9ODQ/pAsaaRiCbSAE7q2ZwD+5jUC4Bavk8oUw7l49ZYoSSMk",
|
||||
"fp8DqDfBs8WiqnB/jQ+AYaiMqLiA7Gts9inzsMfiVj6bgZdVdCznJPtSpm1GjDtoSuHhrE7mjJDQnSIy",
|
||||
"56bYeQcpbnBogT6g+08umlMD3bMmzYxh2RCbP4oPxx5CFvM2zpCKtxZdImA0ZhzTGnuYfluVt0P4zUwE",
|
||||
"YwikMdBYFPAf/55nej0QaVRUinnsF3O1l/uu2xSf0UVpfdz3IzvzReT7LdcOVkj6kSA1ln7upWgwNu4q",
|
||||
"t6fTpLRH/bByXTfsZquA/nU8P2u6Mrm2045JSyQNtZwqLHuh4SLFBeZ2sWyK2KBewSFGHJPqdlhQgm+q",
|
||||
"x8kDCWo+YyEF25Idkjdex0szRMwkLNNRylaXbNFmBxAbHM3oQcUVQrPyFaH0UbmD+SH/3fzb7zat+Z+9",
|
||||
"y/XmR2RpvsnGnHLpDa2fUBWDARbuntljdN9UraI/mrlZqojmGNeEopU0c6D63S6z7stYy8bUMuWxzHzQ",
|
||||
"88LFiyX0yTmgugabxWraJFss70EEqOFM/hysbmagc5jXMMfBOtc8w3JcLSXaohRE023RjHOg63jsz/Ml",
|
||||
"CqBs1+vLntn9aNUvrUWAFhM4gFHPSKJVKuZjHXZLTtTqkB4KRPlNe8mJAhYZLn+YrYcscqWdb/sd0q72",
|
||||
"5EnIIPgR2XLJGrJNcaNe1Mzrksju2JGNSUorJOgFjhc1mrRDt5tVSvzyd/jLrVMdpRk3efmE8zfUB0Vm",
|
||||
"/H4t9JDo6OCAopkFCtllVcJoxkMwcb77c/wEjGE4nbIY2iMr3qfG/RbVJ2Dt7yZbyWPQLpDOI/GpJlvA",
|
||||
"8Tz2XIqBcPLKE44kjYqkoxjxmGfxKHQ0sI9PNBYuoZUd+qiRkHtB59LnLbZIx4lMdyIeA2wZo/U9Pwyd",
|
||||
"JZe0xB7Qt/Qxxhlb/R5kz2qW4t+RXvAZJNRhMAAshCNwfiQPBcUFLNJDPuGcg/BZvIdZrvSg+kxKRBGZ",
|
||||
"Y7s83AX5Nbbr+ndb2W5pb1SkTZw10mktrTM8TwXGGLxNnjLtFJksW9XVLz37xupmNXAEylIOHIHAm2ro",
|
||||
"59MGkDgPBBWFz9Rg2yh+boWRveJ4KxhQkhZdABwGVrKFxWgPqUaqVslu5ZRcLqxUXYEB9k1qZRmitJYK",
|
||||
"0LKmMkDhYxYqo6bxKH5JtVLTyqTcx7uWsmTTYxTyK6yvMc7VML/dZY/BLnoIQGkKfJWkend58aAH4PIc",
|
||||
"svsuIqHqoAysAOeR7n+qidbkNp6E9VFVZ94yUjZrTsmII4KbR6kdpqoF2ZzLldRHRhvJuskqfd0hqbEA",
|
||||
"TBZO3rrSHgh57a+RrvxuyeoZVamaOanke7+kd4rN9jpYSqRLwKsq4SKd+uZYYfm9nz45xuV/jEfHDC1W",
|
||||
"ugmLgGLp2886wFgcXxwnvAjragCby8ZhVZOwmn6v7IudDwjgXc1MCyW+j5M4pfL3w7EcKKWQpHoqxJvC",
|
||||
"3QWejLFdGKfyWqRrp4eWns45rr8g5EKinAsBjDYlmnCAjifMhkIGjcy1jDGlUVOqKUUf+FVgBOaezq7n",
|
||||
"4xXIR025QCAhYI53fZBSuu9nh4XUQ/u0d0rlQpn94aU1BSVpntAhi7gSNes+BXfuiPmFs5MwPf49skDk",
|
||||
"BO2dyi+bXbqxfeZlwvfzvq87q1yn60Rj3WS69j30/I/zox4JoCpuq+x95ecF5FKP825475i/ykyu3Gul",
|
||||
"B4aR5V+amzfzSt0orunQIW3Bzin2U68X+GtExF/01QgwXHM6gFeBDxcQdqEW4PCNektiGTlAnZnP+diF",
|
||||
"6gYQ2hXXlQpub33NQYAJ8hkrn3O9Ys5bpwb20or8q4zWUusuqug81AP5dZcpwLibaZtOCJVjngoSRY63",
|
||||
"ojUzdF6fSs4o5KkTnqiDrB9qCOUvwAcF4iTVLTtibQB3QMobhcRHoPllBjqFbQI4JU95CX/VqhGj3OOq",
|
||||
"9Mya5xsxKrnMeHXT2DRIQrlMmYK6f4Bg7IivvoEsdQcSTQyeHg16SiHxe8ydzkBFFj+lH8r+oN1kO5NR",
|
||||
"OJvNJo+PpnUBYcOmqCiQ6kyk/WFAtexoB6bRnszJXyrbRVzRZjk3DSo/yZA6UGHp5eHVvXmK0KLZckb6",
|
||||
"TZNf2YK9kMtKlL1xjMSP/YHpii1W0KrJbQK6uE635wcRPof/lj5uLduOmzPFWQKoiui460SrncC+6wGz",
|
||||
"Ui9DaJTKCg+xnjTx8aSlFnUT+ZG9Rt405Y4DrHe9kmN92XbdJebU0DCj7iNbeHyIwDUM8WtzLHhu9oCl",
|
||||
"lMMN5QnbuuA9Rxf850hkCAmCL+EGth+PmlgP8wlcw5D6MB/5ikcmKK5frSTOWGV/JkRWJ/Whma4UG4Rc",
|
||||
"jpevi2nxjbWSxlr+inN339CJdwjpLGlT3vx+1PZV8C2dM5egB5rVr7rj9FrEDtz1tGhVEc/xGLW0zFVP",
|
||||
"eM9ME8uLJ+s47YasgOx+JpfreTywfmwBneRQQ8O4tA5FZPRhjCGaiXhFT1sHnspdzgbHq8si09hIJVaf",
|
||||
"WjtvzVpX3l+wZi224Z5xsFPyOW1wmmFfRbaZ4G+ndxXchodVGdJhkuhwRJnp/JUJFrUF61sSfZTShZw7",
|
||||
"aawyZx2hpuB5xtb5uTnZI7JrPgvlF4QR8VrRauD3V1ardwwoGwxsumw/V6HKZM3o+5GfMnlCpPc0U2ky",
|
||||
"SrC8OPlb3WmXZmLzDKNqGdkxjKuQmee0meZp5tw0uz/Tat1lSRNW3kVCfZZXANV25QNRoyZjj7S17orf",
|
||||
"ITviCHbMIaiZ63ZEAsd2rYX17pIPTKm5ib9D1lXCzJSmuVjp0h82sTO3C0cQGk8xZ4zq+tKMaDSSSCY6",
|
||||
"dVvZiE3aU/4W02gXoJLjmZzYUByyc2JTNVuIkgeYMlVESynsGYGY9jaglerAichNhlW4ukp0pkXXCTHC",
|
||||
"PMZyys1eZ79Xd915TbU4LQ3ElwAfEEw2WLs9tXWpOZDSxhxisW96j02pvDldM73L/+Xz/7B+Ovf/KA59",
|
||||
"YEaC6INEnntgcPEEft/rtKLA6RkOKLtLssxHcnSpYiULcLfxMhbSO+UXNOWluV1pdY3u4JNTgIlflvZA",
|
||||
"CMIp6jalJZs0oKSXKpMx3GxgWZ8mvwHCouNkW+ffYAzmx8AwwsgFBFX8IN6/bC2yqkSLKZJHkaAjqV7T",
|
||||
"ITIxItXAM276NcbhKy5AIP1RkVIJ+J1Cp/QMA16HGIiwOabpOFOPKtnK0Rxq0Etjh7EkwIjolVjYIh+z",
|
||||
"IkwL/ZUVEurPY1mYTyy8oNLb/cCJ1heoWmNXC2IHJLjSx7XBv97h2v3vProJrECYBsm+TVdjNYp6jfu0",
|
||||
"YYexnOdXAp3LQOFJV/fG2ws3rSvz16x5p9e3rvdDpz1jxb9Dxi76FLUukF//AVBzbUuMWAqZtW/3nHNt",
|
||||
"v0NWiDd9y8MyK2llaOC59HvEo4/R/mLHpmcsCPZCom8K0wSJAFZMu+fMdDvImsUi5420r7TrEg82p8+m",
|
||||
"qh5f1bjUeG1mbuY1RjQDU0zbnF07PwtVS2btfscBfbVC4D90nQEGcK3TuNR43wmjK/AEqxVFIhKExtBJ",
|
||||
"+sjs+07Xwap1JQ9eRfTO/dsQdO35XoiScGFuThRyRdi/3UPHl+N7s//AIlh4IpbyydAhAKQJxCMblsac",
|
||||
"PJj6X8cDK36WbCUbTFENJDev6TWi32nMCJjWWQ3HRvwvaYOYwPOCBUnoqTkFCzHdlEtlJJvsrvwpUtcD",
|
||||
"9JIXmrlNW1dX0XWWAjtYn7U9210PHdqliJWP9EPNut6gX19hDzdOOfPZCj3goq1UH4U/qtEOmmVSSbuY",
|
||||
"Dz95KJElQghJ4ayuY/W+ZAx9aQKQ9ArI9uQMkLnTEU+yLYVpi/GIyTQ7IpML3sAEQlp3trxFK5/W/DFu",
|
||||
"5Pfx0bd5kZgf8IaWh1J9X/MCg0fxfh1y8b+l0jdVl12poXOihV71w+hcxylZ6/f8MHrL0S2zyTox8ZLD",
|
||||
"0Kj47+RZyfEresI9gmBE41JDlCOBwECDI1fFqmbthUlKCZsE4KzRCYjKzV6Lrsg0mc2gGSg072kEjZF5",
|
||||
"SL9DKwPYCc5pTOoTiU6a3aCVm3cJVxELHLU96Q3Mcyi0u/dh8kXyAOAoMCMjwfmabNexVN8yMrKjZId7",
|
||||
"j5+AengJVJAPGKkvznTTEsXdKk468onMBkRUrjUdxfAAlrfKT/kFcz0uwOlAOnCyiZRsyQ6v2LHFElMH",
|
||||
"9Qg15rtupp4AhaFFqvCV9ijZ1ggpTop+uhBPMCvxTZikNINqmaCYZt6kk9OvJAKeF3WpkVyj2VIc+anl",
|
||||
"83YbiyZrQRl/Ygn1j/hVg66ZCNcjDmeE4ZuU8uiI1xDLFBTj51uyAzmN7BIrREHm+4ABPIv3GCSVp7Nk",
|
||||
"7Cg4fHYhpxDT2wHeMdNoZiSAUarkhQB8L2/6nfUJrT9iXe6rZiwDhP2XE8HfCffeSDBSnVwm8/sdcBXF",
|
||||
"RswCe2aCsysR6OvvHJiGdxTv5xxbdUzyf4x1sDfFEZKpMgtmwqJMJy8VnNGk8SpGiOrJuGwtesshaytX",
|
||||
"0McKIz+wV8g5e4V40cwtLzeCocIVjrqBJeHtob9OLV6Ypb4XnPkZ+/mSkvDGrIEjUU0QdRnaU2jL7gJE",
|
||||
"fIiuE1W2kCSHVTyYjOKQi3JUUhjna361Vpz1i4W0z1R312cBl9dNGMeAZcpi9hOncx/FH4AXGvhBehNP",
|
||||
"6WKU21nyqRU/gTzaUa7scvIbTsaU629TOu5S4CErn6ZY+Pnz6i3orSRuysK/XkDNPaxrUb7OF1fIEXyP",
|
||||
"uUhNo3lmGuncKxHxSajpspkZz7PCdEUHXCYm0+13mWgbEDXvMbN8YEH9NZErI26RRaVU8uttMrXOQFO+",
|
||||
"EtPqrMUoa1LVqRZnWQSt8OIk5hqfnODUsncYDSupigpV0IAOw9KDO1RQk6065jv7EghxD1OX+wR2bz/S",
|
||||
"0kqh3xHMMYSgHkN4b4fxqOuKvLD1FDVeLKnEC3gMFqkOzxZ9ye3g+b5u1evfxrkFP7ttXCZr30r2qKg6",
|
||||
"rkZia3Eo/Ws8ULf3ZyeRv2q7fLbHEOSXPjmVvGpdUvPY9lnKDXslx0+8GglindAK0R8BFsP8tMJli2W/",
|
||||
"pKoxtVjQ7EbNOV5YwhSH5jzh5bJTeeKpJboqTSeXNV55qAb50oTyoLywyBDbRQLnw3h4mQfInqJxw2pg",
|
||||
"xbvW4rtv37S0Lu3FGSv+E94teYuoUud+arEnZ6CsEIP6afTkQtv2JmvntG1PEu/7ek9vba9Ki0AZQqlS",
|
||||
"eWfmLK5LB/IgkShlhy87uSBGHFJVt6K7ScIzu61I1ar0+mUYP0+2gPkT3BxWpt7UqC7VwpscSaXylco3",
|
||||
"o1PZobqyb5PRIplKfEB6gHyxaQ2ufeuiBKwf6O72g2YO/fgEIvJShiFze2dQZ8lOfICoNAkfmVctgAxU",
|
||||
"wFUTUjFmPOIZn6ca2KtO5n+H0YUzknTZHGOZiZp6iOOG5YtkP0QM3WSk/8ssAlIr2RKKcheCPkMon3AY",
|
||||
"DxgSApmGRzIDOVRpl4wLxdphZGrDeBdm7nO54N2uMsczt7z4qzwOYgoZ59QS0Nx1kdtgAheJfoxdqqx4",
|
||||
"adXp9N7ED3lRGbPviQJDizoXMIM35nflWewICVuphSUw+w/pq4fsxvJCmdz6PLVySFfdIqK4KQBX9bSe",
|
||||
"L1hJgmQr3gfX/Ma4h0dZvJde6z4UxbTH20dyeu47jhsBRvwTLVAlZawT61makqdvCbjw6mhISx2XQ9JI",
|
||||
"rBI/LAxXhmyuIoKrZmzf12oEmpW8Vcl59fZQQWyTfTW7hLkDImwxnvC+7UVOtF7mFtYw6j5qKnzBwCD5",
|
||||
"FAsvKFZSat7sS+h2+oNdS81Tp00oaegzVvx1SrCPJYlYaYtsFVR4JZQlYQ6+B2ZHs0QxP9GAvlSOYAKW",
|
||||
"0aQ4Eyuyvmj2EV0rhMi+lD1gUoRM1Eeoy/YaAL/wQEPVlXxqMaNZyM+I7TwqRI9FZ5Ktk2074Nia5KYr",
|
||||
"ZallcCkWbNuWNwRzbwjtgivxAG4YrH4OQA5YLbDHkm2lEryNtaUmupteISwGN4pG4hk2t05pZvdlHf+e",
|
||||
"nsTmlMIrYfhPIcJm+D/O4DVQ641XvlIKij+1S4f1mbqMo0yqk8V3j1xfRTnmTr2EyLcr2bY5A4dxeidb",
|
||||
"gI8B1+ViytK7KDN2q9bPjHXD9lYId+DswTfP1NNX4+aEpoVSOKlkGSxWcq/XyCoBrSFsJrnSNxw6K4UN",
|
||||
"nwBV3u84/uyPVDEW/VtyPBven234vrmqssK8fnKhZTlxjUu/uJ13aAjG94GSk6i8GmsPcgZ5sAaBdRPr",
|
||||
"ijFOjoN4ILnFxhRwKfRkUC/0+/TSNrmj58arjBppOAmLvVysWEP8DNTbAV0PboLVEu/+WqhNQXcmcziO",
|
||||
"FJnR4rOLFj8kSs6JJsi6gVBB0OL7nNcsrZeXbM1Yix8vWng8MrWrfG9xs2aI6b4srLWFqQCYSQyGEr9s",
|
||||
"5BUcuAugqzntplMsHytX6uKaiSblBCUGmxWFBmsN/tDu6leoCNBprX5V17K+AZ1QTed5vvGSZA2ePWl0",
|
||||
"qX4DBV2PkBPsKYKtYDNx9KsMlbU4Z9Jz1RVq/ehHCF9HxuVB/PxHP7osbPZj1gDcy3eB0hiKynJcPVTl",
|
||||
"OAR/m4wlmLnlQa1JPOVZ+UgJvImlXmQ44yLdr4sK/zOEUYGXjGfuH9FJMyNk6YJPSH2nLxhLeZ+vuQMd",
|
||||
"GKIpNyxPWvhIAczWlIXEllBE4/RciaU5wKCgNRBZHRhVrGxVKGryRT3D/ZMCOTWyguZPJmnzjucCDklQ",
|
||||
"cp3/I9/yUvTQVMIV8vVxYw7EDrLwrHoJaS3KAXgQP2W3GlYlEE/k5+ntHl+0j64A44TQ/f8Nv6MwXran",
|
||||
"2LF9iF5hjfCnarlZ5NXF9sAVh2YAJBznivZmuo/yKFAUIFwzrh1GLVgJbVAlrXU8MaOvcxKtMYFzsLKb",
|
||||
"7YVpTR9NJEkHqj83LX6MNTVyWY1RINUmtBckOtezw/CuH3TGd0jIW1B/8ErVlXfBxDuQwl7gDhTHsubE",
|
||||
"RQeZeuZeZqzAeGRvcs5BIwvxc3DxDJMNuFs9Nl2fb9CpQDuIzcYEhe0m6fb8wA7Wxct0Qvdl4YTVc0Rl",
|
||||
"SozL7Z9ElAKClaIQ6RpOQqLyZK+ItIUsNsZwL5yrEBEH7M0OSzPKwD8QifcrwOyCDO5D1a2BNQUaFYPj",
|
||||
"IH7x06Z19Z1zoPD3RZXvJ2AYQ0rjdPOWxzOZBK9MUUk35NVKCTLpKSGoOi9b+Q6kzz4TuyN1rtGT5A8S",
|
||||
"T+0enAeCuRZvYCwvegMj8Eesv3xXaDS/2Bc3MktbycbgAvZZfQkvWZlNa42oAlEiv+5Sv5vaVCZY/RXG",
|
||||
"Ije5YwdeoPU+SXG+ZFNBOtUTyyl+QTp7bTuyXX/lBBaa5K+Wp77Xm7W9TuA7ndmOf9dzfbsz+wljOjKv",
|
||||
"xlvs0Sv40yu9OwY/ACOmYFd4zqBU5GNk0OvGpcb/vHWr8ze3bs1I/5k6F7TZP6f/37/WOA7Hu52veZ0Z",
|
||||
"NvqZnt2+AymXQXvVWSOn9lhemf/72r2TV+b/XmX3nYr3k99AsSF2d+Z5nQM133TYNDqwuX8bmTDAtbXP",
|
||||
"o5TKzaDXy+xaSXRcm4NHTW6r9EIP5TYPqEaFCJ1QwrQv7zoRsS2Wn47li7jZLmLsmRFLaaic49dCwzxN",
|
||||
"g+cZh1CiHhyzKehnlDy+5SH8Cd0CUJRXoim34n3s14wVfyVeI3K0h/xrbufDzkXCIboKFl00ZuC/btm9",
|
||||
"3gwWDSzFTlGNh9P7Ps7uJDUfvugGcYkdEtNNXboX0fMyHegE3PDy25IdCM1yuU92LNbfc5rV3LGmwE0v",
|
||||
"LcNRvMsli0d2niv7o1TOsWZVgV9WrtwiXowvbVrJQ+DySflmWPcvUdloWgzHPWC0DkC9bX3keB3/bti0",
|
||||
"rvR617r2CpntkKWm9db1dxngr1wOFeRfliXvpBLZ611lczFJcUzfohPF30o1BA45kZuATtYvjL9P5445",
|
||||
"D3IeAmXTT7H1ZSs+TDbRSI2PSwUtPYNR5O6PcxjzWat0Frf5o+ajuNISSQ777/dh77cjEp1LQ8Wni0f+",
|
||||
"SbNn2cabxMkv4vfKRh7UZwAUSybwNlew0Hnh0clpBnyDPgCowejV4v3RNjxBm1yabXY3KmYOheev4IOT",
|
||||
"vh4t4LwYs0CliwzVlZqCLPSE5hYeIxhB3X3IKMiSTR6oUa9B0zVftOrv3xnJROT3zqVlZkrk4qbfu8nL",
|
||||
"w1SI1EJ5JiXMKmb8/Bwwn2PFp4tzxSWuJhonhQEZRVBmJ4G7BjcRGKYjHvJyQSxMyHjSawqYHqOLC8gc",
|
||||
"t6VKfszloxM3lpiv90wlOxjEpOr804KA70TFrx+tzrr+iuPJcJSsizQexk+sqUVW4JVKxCXrLllanOa9",
|
||||
"3hKsGAFZDki4ei6931nxrtX2/TsOsRZ7Tq/fCqLFW97U4ntR1PvAc9cvWwv0bCSXrQW7SxaciPztQhQ4",
|
||||
"7eiyNW9Hq38rd3VxusltbEFWhNM+tBbZq1uRf4dAgIVa0+yYZJ5dgZWQyT4kZ/+AMapjLqziS+ecublA",
|
||||
"j+w3xjsIahU5RM2ZKkWdvVve4utz5y06phnGUNBqB6RDvMixXUjI/YalCW2jX0+pC3cM4riNkwx6SyYz",
|
||||
"YWk9P8XmI99vdW1vvUVNsm4vCrVXgPdBBiYTdoK2X1XEqR+t3qQCEZqsPVi2z/gasgWr3877kkmCHrST",
|
||||
"iuFj2V7rR1myR7ZffSTK0OPH3sfvK/qOWXgnG8WBEG0zt3MtxsFbIz3ml8m2vEtEgBdh3fssvfqFEoqq",
|
||||
"OknnbNctm6grrlttrr48aURsWBdFRjpVAvAPhwd6GpBakFGjD5JPyyeJqUyz7r+hUedPYFRfyCReOSmZ",
|
||||
"ggjOk2mhZ8Fzg0daeo8G+n6IjWxghp54Cw/ysLDLSLyMn7PplDP9e3BZoICOJbQy/f2Q51zuJf8r2VHy",
|
||||
"kmQ4AbpeMIcCNPVB8oj+U/ZU7uqjNzBJTM3orTGcISk5DWeqnNu5fnXMultIpnBmCvgrtm92uA4cZCa8",
|
||||
"fk38R1h0TvibN1iwQolx47T9NRkoVA5MT37NXEhYqz/FqUNLCFOXE87g9i9BkJHqvpmylMA+348Hl9Qs",
|
||||
"IHBKS3kVB9bi2iJCWNJaQ4fxYPryLU/2NigZewy+sxg6vyTUChHuCTpnvOfeiuPdk32u//+5K+02cc/d",
|
||||
"IB0nIO3I4GS86mMZtpph82tjYdtrgsgbm/kl0d+yXpuba/ICWm+83qR/nr8wN3f7RFcsBzzHd8lS7/Qe",
|
||||
"r9+D/oX6LFSK6t9wmVTHjKh/RJbm9VccadORNe6mN2JPFZ3PwkHgzk3zjBgD9zZAB3asKXieefedzjTn",
|
||||
"TZXzzlIQwx6cEc/ivWRbQxPmh9Hba8J9Xr/ShsbffBWZYumbC0D630C4hhFe13PhzlQOhkXDglKG27Q1",
|
||||
"RRWZdXFuThannmuvY+VcWZ6wFK3J3Xl9olwG14lxCgVIpo4p/HdhPY+KYHTpVHVJIfs5K2FmLfadVi8g",
|
||||
"y+GihUTEyj5JNlUGYw7kO4hHlzNsFEoK4DFrHR/JpFibsjOvk4kiJa+TV3RrNYiICSBZt+QYYZE7YCvv",
|
||||
"N7Vs5iMIXdC7wa+wRJNiSIFwKTtwdsn3ozAK7N45yfVRoOP/XYYUY0LAYrcfRq32qu2tkJwDRcY97oGX",
|
||||
"iIEAqC2DZcwGKWf2EYKJ0xvn0/ho5paXFnhk5WdyV8AMIpmxde8m29xe4qGbEktXy7NCojf5LF2VJmky",
|
||||
"Uq971ffVb4MpTUx5KJrkueCRhHt3s8LU11flg8FwOTHcZryfq+wgOyEz6NwUey5StJhNU7KVWJn0Qvba",
|
||||
"t/gzP+jSVTeI3Y5IByIFVbOp6lje36pAzyrl5tq+65I29Cm7XqtOGPmYnW7KNLnqEjt4jz1XyT/1teSZ",
|
||||
"O6qL3WUkcREqyNbHEE2T7eks0jWt9ZjD66oxNXmezLzo6Vz8gMWXDaJ6HqA05TUVJlHRyUbY9CklvFQd",
|
||||
"vf/fuuikS/iHmrSQ7y35dtBxvBWwuvqahVqw18gH6WOTsTvSF1xd9R1OKV9mbLxuSKOWGXyP6qp0JuhJ",
|
||||
"GHNNWnQul0AA/jseXoSzXbEEGL0rX7JjVgNM0Yh37bX8Ga9kEOkL2bT7QUC8qMUfXUSOxh1qj4iA8mHT",
|
||||
"ivcxQJmGzx+CeaSY02kjUyKOidGrTGCU4W/TENZ0ajeXmsqXVaMbsvpz0Qzafj0G9VUYm5J+NIHsXOUl",
|
||||
"308LWrkdCf8wvVaelcH8rXrH1GdFaWxd7tE5F0asiLbpiJlnTy5EE6anVF9kItFXqiVezlUDPYbdCanx",
|
||||
"w+Tz5AvmCpGuEuA63Ux2akK0KGBXVngqU9FR9IkqNQ54YZDD53CgjeC2q1SiM7jfmvoTZr6vWacJEOXL",
|
||||
"7xijsNRZC4niN4PgZX5dJnOola6/a4fROeTovet4YRUvK2xW1wmjYkTbvHhqwvPvQh1nPb5sod9uA+P7",
|
||||
"CSfXcJ3RQw+QP4F3aYIyT5t/JXXUxNjOaqoNgleR0kFZijI7E3/SqVtUis4xd8IA7DNfriq5DE6nGh+a",
|
||||
"gRj4tuHIQe/+GW0+fNmrOGxe4e4L6M3Y8b1wFvHMpZsQvF1wkb7BfloVv1Zj0JE1xvOdB/E+GDiPG1VF",
|
||||
"eCxqSe11m0T5SZgEBAibH+NgOLPbNnNuCOSYkmEvIfOruThCEoacJMFoflxfX+CPTbKOCb6jWrHc9Npc",
|
||||
"4IirJW1CEODw9tP7+pQOVzhdfDvjE16642+QNf8OEVPfOJvz4NSQ2Lqq/PBGhe3NX/qYZXnlp35YMPOq",
|
||||
"K08LSlvkEydVOgZKDE6elfNkXTKiBiy5kjnzIX/KOGReWkgUMsy4v+jtFTH2mIQDxTEU9zamYD7EqglQ",
|
||||
"5sIAJMt4JCe0YaW3aJljwGExgtsa5I+OJnRV+zpPUZJSqMBSatJPGBfJM+jeBu3eEyhZ8jIegRuOJa4w",
|
||||
"doC0Rsmg0A0ZEjtAcIhexOiO+1vblYpp40JuAviRB+8RNShXa+K5zJzcE8sFxaN4Lx5w4CNUYXnKuGeA",
|
||||
"fQSBjFRs9yH54QGv9EE12jF0QdDqg/s92YYykB65F7XaECDQVzfBUVZmwDRrJIkR88LcXGVKTHhMiyJs",
|
||||
"2IBWZzhC9hdLIqP/4smCLI3stvaVP6QYC64FQs/CaqW/6sHaaxk50Vcv7xG2IzS7RK5fpEcJ/7NUyJ07",
|
||||
"+iAal2xZ8N6Hipo9BBtoD02tZoZNUwK9MwyvqLplxXuQRfyUniVA8AWjeAlwg33aMv5B9xsWiN9Itm95",
|
||||
"U9/9eWV1qRN53720/vLrL63v/sxYGYCT47uX00YKT9RHMk0/hypJY4SShG0/CEg7Ip0W7ICC3ciK/pzF",
|
||||
"pny14gxlhdh5+byukhJfJtugPvcg8IKIQBF8oganLN2ou/fiI+s1/dEypEbpayqS9yjebVoXU/v8KN4t",
|
||||
"3SXBGgnOOd6yb94itOPP1RIQ4jwYsBpbhwAt+BUSgeHJcMnCBBQqooK0QSqThtBCmXvksZpXPwCeMXj8",
|
||||
"gFVtkmucZbL1eSZQLguf56gy4BzY1L+B0wrqR2qKByY70wajZwHm6xqdrokKqHiL/pKyCyEDUV/sKMNH",
|
||||
"UD98vPSVworJcKHI8rceRqSbkT9gjKgjkUMpOCAuqFki+YJksZHI6rDOX7CSh9OXLTVD4wCJcNRkDbw6",
|
||||
"LH4Mua4nS9S4ZDHbm9lVnAs/XwtPsM+wU5GZdHtUjX/Q64f4O8ZaMdDqcZglcG/UnwPSP9XF8Ptej6FZ",
|
||||
"hX29cFfD3P+8b7t0h72aAg/1a4a0doRm11XgQ9FHrZjHconD4PUBnHeZpy6cZLkteMO1TnjW3uOKPAw8",
|
||||
"/x5MTmZKShZePLgsqldKdbMkr8Dn9aXGSp3CeoscWZNsWU4HElLp4S1nlSppoFJpmNJspIxP2xS24apu",
|
||||
"sstUtEQ1TuwESSikEpYG5P9v8Zg8TrOMoA6awoQGrAdRP8RjeCrqh9b5mbmZuabKRf7e21fesmat+Ss3",
|
||||
"r74HQCj0TY3Q4H3jdSv+t/iLaaQExBM7tf92ASE5BCP0Lxu/veUtsq7PfNwnfdJa7rvuojVriY/7IQla",
|
||||
"H/f9yMbvmvQqtoVeGOwwf1LUqFwUiZ7ixQMLnSO76LgpKDhwlvX/XlHhAakHrAaBEd4k5Y+xigP1uG9z",
|
||||
"NQd4uT1GBo+2FrNQVUJ4saZH1pQostG0qhWS0RfoS/3r6hTIgs50osSWCQQngjQk2eLYxI14lHwRHyh1",
|
||||
"s+hv6XaaApp8cBccgc9zg/HnD6wPesS7Mn9tOp+o9ZETrXYC+65USK8CkP0BehVQVTflaYODZRds4CNw",
|
||||
"FtaIdhdv5T55uuO+EOwBMh0l3jrQlclCAyOlzkS6grUqydmu45GSYFbN5X7/qxfF1a1uLVV2/g2ZxjTt",
|
||||
"Jzun2P69gLShJrz5vPwq6zvMqiTkFJyxFt67cu7CxTfgBiqKaMo3T16Fk5nQjON3quO3Q96hmW7nr17X",
|
||||
"7Px51s+zKGTG3/VKS5mlnfgeFDPjVdAlpxem33MDBMJve9zx/BRk4jm6qE4smmDqFJnEOFE/h8cmvh74",
|
||||
"Gt0y/IFTaWHYDmaA4UhY9jGeNnUsxO+Z3ZYtQFlULfvECxAS4pnvrNftgO/GBfpg5cOYTsjDek9arAM7",
|
||||
"kk5as64UF8oDOpNY1pQnlVedmb7H50Yrmx/C1zg5b5G2UwsaRK1k3fb7+CNBrzin8xgpRarxN5WKVP8n",
|
||||
"o7uoCQmVjddyI4dRCchc7vpVw4IHbOk+Y1mvLKr7HI+UEwj6XXuNzPq9qBDT8y6JPrLXyAe9aNKYHvk1",
|
||||
"FTACdYFHUFeN0HWcYQvnXBg8qiCC/M75n3isQiQLmpclHcFkywgqvVpZiOwAJnxCRzxtGt6h56o6X+uL",
|
||||
"JI6VIlyQVItQpMk8PB19TrrEX0FjeAv57s/Ujkwep1Vrtr57WX3VSmFYb3sdsXSlZ8G/vgo0lKjWkx91",
|
||||
"s5by9Dpw8ITF+Spt6N6Z26nFAp7hYqtNnDOJXqmxRW2dWY3+YmAHi5pEyQPhnBAuHc4gg/nnWG2KR4fH",
|
||||
"3BqzHl2GSRSJ/xm5N2ml+DMmQq9OZL6pV04gHS3ZAoiCKofAK8QLGUMxJQmhTW0Sxoe5rXCBpBTNerFY",
|
||||
"JbYbrf6yyJB4jz0ySU4AeAX6XQqooX6NStHCmFZxZOxfIOwl0ArHcgMqfEkOjAfE7qwXzsYNfGKyOfWd",
|
||||
"9YK5YHQ8z1kEfDOFZTAfvlxBhErlxbnXzqxzX0MypYiVa6CP2o4PUYCH+e4XrfE/wbXyCGuX8pU+ip9g",
|
||||
"RjePfKY6l2PLtq2pitM3rRUUtU+fNJaIHZDgSj9apV2kChGRPahI+4HbuNSYBUXJ2vpEhMGxzftN8QnQ",
|
||||
"bUp/d4nyLZSYkz5wnaWAzob0EQ9OSR8x8JH0iQj8yj9MkwikT0FZyF3o9Rr3b9//vwEAAP//8NK6XVFk",
|
||||
"AQA=",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package appupdate — самообновление Android-приложения через сервер (docs/mobile.md#самообновление):
|
||||
// сервер читает последний релиз Gitea своим токеном, кэширует ответ и APK.
|
||||
// Package appupdate — раздача клиентов через сервер (docs/mobile.md#самообновление):
|
||||
// сервер читает последний релиз Gitea своим токеном, кэширует ответ и файлы.
|
||||
package appupdate
|
||||
|
||||
import (
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"pipu/api/internal/platform/httpx"
|
||||
)
|
||||
|
||||
// CodeUnavailable — обновления не настроены или релиза с APK нет.
|
||||
// CodeUnavailable — обновления не настроены или релиза с клиентами нет.
|
||||
const CodeUnavailable = "app.update_unavailable"
|
||||
|
||||
const cacheTTL = 10 * time.Minute
|
||||
@@ -73,14 +73,22 @@ type release struct {
|
||||
Assets []asset `json:"assets"`
|
||||
}
|
||||
|
||||
// Latest — сведения о последней версии.
|
||||
type clientFile struct {
|
||||
Kind, Name, URL, ChecksumURL, SHA256 string
|
||||
Size int64
|
||||
}
|
||||
|
||||
// Latest — сведения о последней версии и файлах клиентов.
|
||||
type Latest struct {
|
||||
Version string
|
||||
VersionCode int
|
||||
Notes string
|
||||
Size int64
|
||||
SHA256 string
|
||||
apkURL string
|
||||
Files map[string]clientFile
|
||||
}
|
||||
|
||||
func (l *Latest) android() (clientFile, bool) {
|
||||
f, ok := l.Files["android"]
|
||||
return f, ok && f.SHA256 != ""
|
||||
}
|
||||
|
||||
// Handler реализует app-часть gen.StrictServerInterface.
|
||||
@@ -92,7 +100,7 @@ type Handler struct {
|
||||
mu sync.Mutex
|
||||
cached *Latest
|
||||
cachedAt time.Time
|
||||
dl sync.Mutex // одна загрузка APK за раз
|
||||
dl sync.Mutex
|
||||
}
|
||||
|
||||
// NewHandler создаёт обработчик.
|
||||
@@ -100,7 +108,6 @@ func NewHandler(cfg Config, log *slog.Logger) *Handler {
|
||||
return &Handler{cfg: cfg, client: &http.Client{Timeout: 10 * time.Minute}, log: log}
|
||||
}
|
||||
|
||||
// configured — адрес и репозиторий заданы, и это не заглушка из .env.example.
|
||||
func (h *Handler) configured() bool {
|
||||
return h.cfg.GiteaURL != "" && h.cfg.Repo != "" &&
|
||||
!strings.Contains(h.cfg.GiteaURL, "example.") && !strings.HasPrefix(h.cfg.Repo, "owner/")
|
||||
@@ -125,7 +132,70 @@ func (h *Handler) get(ctx context.Context, url string) (*http.Response, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// latest — последний релиз с APK (кэш на 10 минут).
|
||||
func classifyAsset(name string) string {
|
||||
n := strings.ToLower(name)
|
||||
if strings.HasSuffix(n, ".sha256") {
|
||||
return ""
|
||||
}
|
||||
switch {
|
||||
case strings.HasSuffix(n, ".apk"):
|
||||
return "android"
|
||||
case strings.HasSuffix(n, ".exe"), strings.HasSuffix(n, ".msi"):
|
||||
return "windows"
|
||||
case strings.HasSuffix(n, ".appimage"), strings.HasSuffix(n, ".deb"), strings.HasSuffix(n, ".rpm"):
|
||||
return "linux"
|
||||
case strings.HasSuffix(n, ".dmg"), strings.Contains(n, ".app.tar"):
|
||||
return "macos"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func assetRank(kind, name string) int {
|
||||
n := strings.ToLower(name)
|
||||
switch kind {
|
||||
case "windows":
|
||||
if strings.Contains(n, "setup") {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
case "linux":
|
||||
switch {
|
||||
case strings.HasSuffix(n, ".appimage"):
|
||||
return 3
|
||||
case strings.HasSuffix(n, ".deb"):
|
||||
return 2
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func pickClientFiles(assets []asset) map[string]clientFile {
|
||||
sums := map[string]string{}
|
||||
for _, a := range assets {
|
||||
if strings.HasSuffix(strings.ToLower(a.Name), ".sha256") {
|
||||
sums[strings.TrimSuffix(a.Name, ".sha256")] = a.URL
|
||||
sums[strings.TrimSuffix(a.Name, ".SHA256")] = a.URL
|
||||
}
|
||||
}
|
||||
out := map[string]clientFile{}
|
||||
for _, a := range assets {
|
||||
kind := classifyAsset(a.Name)
|
||||
if kind == "" {
|
||||
continue
|
||||
}
|
||||
cur, ok := out[kind]
|
||||
if ok && assetRank(kind, a.Name) <= assetRank(kind, cur.Name) {
|
||||
continue
|
||||
}
|
||||
out[kind] = clientFile{Kind: kind, Name: a.Name, URL: a.URL, Size: a.Size, ChecksumURL: sums[a.Name]}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (h *Handler) latest(ctx context.Context) (*Latest, error) {
|
||||
if !h.configured() {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "gitea is not configured")
|
||||
@@ -142,7 +212,7 @@ func (h *Handler) latest(ctx context.Context) (*Latest, error) {
|
||||
if err != nil {
|
||||
h.log.WarnContext(ctx, "app update: gitea unavailable", "err", err)
|
||||
if h.cached != nil {
|
||||
return h.cached, nil // устаревший ответ лучше, чем никакого
|
||||
return h.cached, nil
|
||||
}
|
||||
return nil, apperr.NotFound(CodeUnavailable, "release is unavailable")
|
||||
}
|
||||
@@ -156,35 +226,77 @@ func (h *Handler) latest(ctx context.Context) (*Latest, error) {
|
||||
if err != nil {
|
||||
return nil, apperr.NotFound(CodeUnavailable, err.Error())
|
||||
}
|
||||
name := "pipu-music-" + version + ".apk"
|
||||
var apk, sum *asset
|
||||
for i := range rel.Assets {
|
||||
switch rel.Assets[i].Name {
|
||||
case name:
|
||||
apk = &rel.Assets[i]
|
||||
case name + ".sha256":
|
||||
sum = &rel.Assets[i]
|
||||
files := pickClientFiles(rel.Assets)
|
||||
if len(files) == 0 {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "release has no client builds")
|
||||
}
|
||||
if apk, ok := files["android"]; ok {
|
||||
if apk.ChecksumURL == "" {
|
||||
delete(files, "android")
|
||||
} else if digest, err := h.readDigest(ctx, apk.ChecksumURL); err != nil {
|
||||
h.log.WarnContext(ctx, "app update: apk checksum unavailable", "err", err)
|
||||
delete(files, "android")
|
||||
} else {
|
||||
apk.SHA256 = digest
|
||||
files["android"] = apk
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "release has no APK yet")
|
||||
}
|
||||
}
|
||||
if apk == nil || sum == nil {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "release has no APK yet")
|
||||
}
|
||||
sres, err := h.get(ctx, sum.URL)
|
||||
h.cached = &Latest{Version: version, VersionCode: code, Notes: rel.Body, Files: files}
|
||||
h.cachedAt = time.Now()
|
||||
return h.cached, nil
|
||||
}
|
||||
|
||||
func (h *Handler) readDigest(ctx context.Context, url string) (string, error) {
|
||||
sres, err := h.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "checksum is unavailable")
|
||||
return "", err
|
||||
}
|
||||
raw, err := io.ReadAll(io.LimitReader(sres.Body, 256))
|
||||
_ = sres.Body.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
digest := strings.ToLower(strings.Fields(string(raw) + " x")[0])
|
||||
if len(digest) != 64 {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "malformed checksum")
|
||||
return "", fmt.Errorf("malformed checksum")
|
||||
}
|
||||
h.cached = &Latest{Version: version, VersionCode: code, Notes: rel.Body, Size: apk.Size, SHA256: digest, apkURL: apk.URL}
|
||||
h.cachedAt = time.Now()
|
||||
return h.cached, nil
|
||||
return digest, nil
|
||||
}
|
||||
|
||||
func (h *Handler) fileURL(kind, version string) string {
|
||||
return "/api/v1/app/download/" + kind + "/" + version
|
||||
}
|
||||
|
||||
// GetAppClients реализует gen.StrictServerInterface.
|
||||
func (h *Handler) GetAppClients(ctx context.Context, _ gen.GetAppClientsRequestObject) (gen.GetAppClientsResponseObject, error) {
|
||||
l, err := h.latest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
order := []string{"windows", "macos", "linux", "android"}
|
||||
clients := make([]gen.AppClientFile, 0, len(l.Files))
|
||||
for _, kind := range order {
|
||||
f, ok := l.Files[kind]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
item := gen.AppClientFile{
|
||||
Client: gen.AppClient(kind),
|
||||
Filename: f.Name,
|
||||
Size: f.Size,
|
||||
DownloadUrl: h.fileURL(kind, l.Version),
|
||||
}
|
||||
if f.SHA256 != "" {
|
||||
item.Sha256 = &f.SHA256
|
||||
}
|
||||
clients = append(clients, item)
|
||||
}
|
||||
return gen.GetAppClients200JSONResponse{
|
||||
Version: l.Version, VersionCode: l.VersionCode, NotesMd: l.Notes, Clients: clients,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetAndroidLatest реализует gen.StrictServerInterface.
|
||||
@@ -193,15 +305,18 @@ func (h *Handler) GetAndroidLatest(ctx context.Context, _ gen.GetAndroidLatestRe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, ok := l.android()
|
||||
if !ok {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "release has no APK yet")
|
||||
}
|
||||
return gen.GetAndroidLatest200JSONResponse{
|
||||
Version: l.Version, VersionCode: l.VersionCode, NotesMd: l.Notes, Size: l.Size, Sha256: l.SHA256,
|
||||
Version: l.Version, VersionCode: l.VersionCode, NotesMd: l.Notes, Size: f.Size, Sha256: f.SHA256,
|
||||
DownloadUrl: "/api/v1/app/android/download/" + l.Version, MinSupported: h.cfg.MinSupported,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ensure скачивает APK в кэш (если его там нет) и сверяет SHA-256 из релиза.
|
||||
func (h *Handler) ensure(ctx context.Context, l *Latest) (string, error) {
|
||||
dst := filepath.Join(h.cfg.Dir, "pipu-music-"+l.Version+".apk")
|
||||
func (h *Handler) ensure(ctx context.Context, f clientFile) (string, error) {
|
||||
dst := filepath.Join(h.cfg.Dir, f.Name)
|
||||
if _, err := os.Stat(dst); err == nil {
|
||||
return dst, nil
|
||||
}
|
||||
@@ -213,12 +328,12 @@ func (h *Handler) ensure(ctx context.Context, l *Latest) (string, error) {
|
||||
if err := os.MkdirAll(h.cfg.Dir, 0o755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
res, err := h.get(ctx, l.apkURL)
|
||||
res, err := h.get(ctx, f.URL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() { _ = res.Body.Close() }()
|
||||
tmp, err := os.CreateTemp(h.cfg.Dir, ".apk-*")
|
||||
tmp, err := os.CreateTemp(h.cfg.Dir, ".dl-*")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -231,26 +346,53 @@ func (h *Handler) ensure(ctx context.Context, l *Latest) (string, error) {
|
||||
if err := tmp.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if got := hex.EncodeToString(hash.Sum(nil)); got != l.SHA256 {
|
||||
return "", fmt.Errorf("appupdate: checksum mismatch: %s != %s", got, l.SHA256)
|
||||
if f.SHA256 != "" {
|
||||
if got := hex.EncodeToString(hash.Sum(nil)); got != f.SHA256 {
|
||||
return "", fmt.Errorf("appupdate: checksum mismatch: %s != %s", got, f.SHA256)
|
||||
}
|
||||
}
|
||||
if err := os.Rename(tmp.Name(), dst); err != nil {
|
||||
return "", err
|
||||
}
|
||||
h.cleanup(dst)
|
||||
h.cleanup(f.Name)
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// cleanup оставляет в кэше только текущий APK.
|
||||
func (h *Handler) cleanup(keep string) {
|
||||
matches, _ := filepath.Glob(filepath.Join(h.cfg.Dir, "pipu-music-*.apk"))
|
||||
func (h *Handler) cleanup(keepName string) {
|
||||
matches, _ := filepath.Glob(filepath.Join(h.cfg.Dir, "pipu-music-*"))
|
||||
ver := versionFromName(keepName)
|
||||
for _, m := range matches {
|
||||
if m != keep {
|
||||
base := filepath.Base(m)
|
||||
if ver != "" && strings.Contains(base, ver) {
|
||||
continue
|
||||
}
|
||||
if base != keepName {
|
||||
_ = os.Remove(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func versionFromName(name string) string {
|
||||
m := regexp.MustCompile(`(\d+\.\d+\.\d+(?:-rc\.\d+)?)`).FindStringSubmatch(name)
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
return m[1]
|
||||
}
|
||||
|
||||
func (h *Handler) serveFile(ctx context.Context, l *Latest, kind string) (fileResponse, error) {
|
||||
f, ok := l.Files[kind]
|
||||
if !ok || (kind == "android" && f.SHA256 == "") {
|
||||
return fileResponse{}, apperr.NotFound(CodeUnavailable, "client build is unavailable")
|
||||
}
|
||||
path, err := h.ensure(ctx, f)
|
||||
if err != nil {
|
||||
h.log.ErrorContext(ctx, "app update: download failed", "err", err, "client", kind)
|
||||
return fileResponse{}, apperr.New(http.StatusBadGateway, CodeUnavailable, "could not fetch the file")
|
||||
}
|
||||
return fileResponse{path: path, name: f.Name, req: httpx.RequestFrom(ctx)}, nil
|
||||
}
|
||||
|
||||
// DownloadAndroidApk реализует gen.StrictServerInterface. Отдаётся только последняя версия.
|
||||
func (h *Handler) DownloadAndroidApk(ctx context.Context, req gen.DownloadAndroidApkRequestObject) (gen.DownloadAndroidApkResponseObject, error) {
|
||||
l, err := h.latest(ctx)
|
||||
@@ -260,22 +402,36 @@ func (h *Handler) DownloadAndroidApk(ctx context.Context, req gen.DownloadAndroi
|
||||
if req.Version != l.Version {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "only the latest version is available")
|
||||
}
|
||||
path, err := h.ensure(ctx, l)
|
||||
if err != nil {
|
||||
h.log.ErrorContext(ctx, "app update: apk download failed", "err", err)
|
||||
return nil, apperr.New(http.StatusBadGateway, CodeUnavailable, "could not fetch the APK")
|
||||
}
|
||||
return apkResponse{path: path, name: filepath.Base(path), req: httpx.RequestFrom(ctx)}, nil
|
||||
return h.serveFile(ctx, l, "android")
|
||||
}
|
||||
|
||||
type apkResponse struct {
|
||||
// DownloadAppClient реализует gen.StrictServerInterface.
|
||||
func (h *Handler) DownloadAppClient(ctx context.Context, req gen.DownloadAppClientRequestObject) (gen.DownloadAppClientResponseObject, error) {
|
||||
l, err := h.latest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.Version != l.Version {
|
||||
return nil, apperr.NotFound(CodeUnavailable, "only the latest version is available")
|
||||
}
|
||||
return h.serveFile(ctx, l, string(req.Client))
|
||||
}
|
||||
|
||||
type fileResponse struct {
|
||||
path string
|
||||
name string
|
||||
req *http.Request
|
||||
}
|
||||
|
||||
// VisitDownloadAndroidApkResponse реализует gen.DownloadAndroidApkResponseObject (Range — для докачки).
|
||||
func (a apkResponse) VisitDownloadAndroidApkResponse(w http.ResponseWriter) error {
|
||||
func (a fileResponse) VisitDownloadAndroidApkResponse(w http.ResponseWriter) error {
|
||||
return a.write(w)
|
||||
}
|
||||
|
||||
func (a fileResponse) VisitDownloadAppClientResponse(w http.ResponseWriter) error {
|
||||
return a.write(w)
|
||||
}
|
||||
|
||||
func (a fileResponse) write(w http.ResponseWriter) error {
|
||||
f, err := os.Open(a.path)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -288,7 +444,11 @@ func (a apkResponse) VisitDownloadAndroidApkResponse(w http.ResponseWriter) erro
|
||||
if a.req == nil {
|
||||
return errors.New("appupdate: request missing in context")
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/vnd.android.package-archive")
|
||||
ctype := "application/octet-stream"
|
||||
if strings.HasSuffix(strings.ToLower(a.name), ".apk") {
|
||||
ctype = "application/vnd.android.package-archive"
|
||||
}
|
||||
w.Header().Set("Content-Type", ctype)
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="`+a.name+`"`)
|
||||
http.ServeContent(w, a.req, a.name, info.ModTime(), f)
|
||||
return nil
|
||||
|
||||
@@ -16,6 +16,22 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPickClientFiles(t *testing.T) {
|
||||
files := pickClientFiles([]asset{
|
||||
{Name: "pipu-music-1.3.0.apk", Size: 10},
|
||||
{Name: "pipu-music-1.3.0.apk.sha256", Size: 65, URL: "https://gitea/sum"},
|
||||
{Name: "pipu-music_1.3.0_x64-setup.exe", Size: 20},
|
||||
{Name: "pipu-music_1.3.0_amd64.deb", Size: 11},
|
||||
{Name: "pipu-music_1.3.0_amd64.AppImage", Size: 30},
|
||||
{Name: "pipu-music_1.3.0_aarch64.dmg", Size: 40},
|
||||
})
|
||||
assert.Equal(t, "pipu-music-1.3.0.apk", files["android"].Name)
|
||||
assert.Equal(t, "https://gitea/sum", files["android"].ChecksumURL)
|
||||
assert.Equal(t, "pipu-music_1.3.0_x64-setup.exe", files["windows"].Name)
|
||||
assert.Equal(t, "pipu-music_1.3.0_amd64.AppImage", files["linux"].Name)
|
||||
assert.Equal(t, "pipu-music_1.3.0_aarch64.dmg", files["macos"].Name)
|
||||
}
|
||||
|
||||
func TestVersionCode(t *testing.T) {
|
||||
cases := map[string]int{"v0.6.1": 60_199, "1.2.0-rc.3": 1_020_003, "v10.0.0": 10_000_099}
|
||||
for tag, want := range cases {
|
||||
@@ -60,17 +76,18 @@ func TestLatestAndDownload(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "0.6.1", l.Version)
|
||||
assert.Equal(t, 60_199, l.VersionCode)
|
||||
assert.Equal(t, hex.EncodeToString(sum[:]), l.SHA256)
|
||||
android := l.Files["android"]
|
||||
assert.Equal(t, hex.EncodeToString(sum[:]), android.SHA256)
|
||||
|
||||
path, err := h.ensure(context.Background(), l)
|
||||
path, err := h.ensure(context.Background(), android)
|
||||
require.NoError(t, err)
|
||||
got, _ := os.ReadFile(path)
|
||||
assert.Equal(t, apk, got)
|
||||
|
||||
// Подменённый файл не пройдёт сверку.
|
||||
require.NoError(t, os.Remove(path))
|
||||
l.SHA256 = "00" + l.SHA256[2:]
|
||||
_, err = h.ensure(context.Background(), l)
|
||||
android.SHA256 = "00" + android.SHA256[2:]
|
||||
_, err = h.ensure(context.Background(), android)
|
||||
assert.ErrorContains(t, err, "checksum mismatch")
|
||||
_, statErr := os.Stat(filepath.Join(dir, "pipu-music-0.6.1.apk"))
|
||||
assert.True(t, os.IsNotExist(statErr))
|
||||
|
||||
@@ -566,5 +566,6 @@ func TestPublicRoutes(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, e.do(http.MethodGet, "/api/v1/server-info", nil).Code)
|
||||
assert.Equal(t, http.StatusOK, e.do(http.MethodGet, "/healthz", nil).Code)
|
||||
assert.NotEqual(t, http.StatusUnauthorized, e.do(http.MethodGet, "/api/v1/app/android/latest", nil).Code, "APK page is public")
|
||||
assert.NotEqual(t, http.StatusUnauthorized, e.do(http.MethodGet, "/api/v1/app/clients", nil).Code, "download page is public")
|
||||
assert.Equal(t, http.StatusUnauthorized, e.do(http.MethodGet, "/api/v1/unknown", nil).Code)
|
||||
}
|
||||
@@ -55,8 +55,9 @@ var publicRoutes = map[string]bool{
|
||||
"GET /api/v1/server-info": true,
|
||||
"POST /api/v1/auth/login": true,
|
||||
"POST /api/v1/auth/refresh": true,
|
||||
// Android-приложение раздаётся по ссылке /android без входа: в APK нет ничего, кроме клиента.
|
||||
// Клиенты раздаются по ссылке /download без входа: в файлах нет ничего, кроме приложения.
|
||||
"GET /api/v1/app/android/latest": true,
|
||||
"GET /api/v1/app/clients": true,
|
||||
}
|
||||
|
||||
// Что разрешено, пока пользователь обязан сменить учётные данные / пароль.
|
||||
@@ -93,7 +94,8 @@ func Middleware(svc *Service, log *slog.Logger) func(http.Handler) http.Handler
|
||||
// Аудио открывает <audio> — тоже без заголовка; ссылка подписана для пользователя.
|
||||
cover := (r.Method == http.MethodGet || r.Method == http.MethodHead) &&
|
||||
(strings.HasPrefix(r.URL.Path, "/api/v1/covers/") || strings.HasPrefix(r.URL.Path, "/api/v1/stream/") ||
|
||||
strings.HasPrefix(r.URL.Path, "/api/v1/app/android/download/"))
|
||||
strings.HasPrefix(r.URL.Path, "/api/v1/app/android/download/") ||
|
||||
strings.HasPrefix(r.URL.Path, "/api/v1/app/download/"))
|
||||
if !strings.HasPrefix(r.URL.Path, "/api/v1/") || publicRoutes[route] || cover {
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user