123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- // Package version provides a runner to check the latest version of the application.
- package version
- import (
- "bytes"
- "context"
- "encoding/json"
- "net/http"
- "time"
- "github.com/pkg/errors"
- "golang.org/x/exp/slog"
- storepb "github.com/usememos/memos/proto/gen/store"
- "github.com/usememos/memos/server/profile"
- "github.com/usememos/memos/server/version"
- "github.com/usememos/memos/store"
- )
- type Runner struct {
- Store *store.Store
- Profile *profile.Profile
- }
- func NewRunner(store *store.Store, profile *profile.Profile) *Runner {
- return &Runner{
- Store: store,
- Profile: profile,
- }
- }
- // Schedule checker every 8 hours.
- const runnerInterval = time.Hour * 8
- func (r *Runner) Run(ctx context.Context) {
- ticker := time.NewTicker(runnerInterval)
- defer ticker.Stop()
- for {
- select {
- case <-ticker.C:
- r.RunOnce(ctx)
- case <-ctx.Done():
- return
- }
- }
- }
- func (r *Runner) RunOnce(ctx context.Context) {
- r.Check(ctx)
- }
- func (r *Runner) Check(ctx context.Context) {
- latestVersion, err := r.GetLatestVersion()
- if err != nil {
- return
- }
- if !version.IsVersionGreaterThan(latestVersion, version.GetCurrentVersion(r.Profile.Mode)) {
- return
- }
- versionUpdateActivityType := store.ActivityTypeVersionUpdate
- list, err := r.Store.ListActivities(ctx, &store.FindActivity{
- Type: &versionUpdateActivityType,
- })
- if err != nil {
- return
- }
- shouldNotify := true
- if len(list) > 0 {
- latestVersionUpdateActivity := list[0]
- if latestVersionUpdateActivity.Payload != nil && version.IsVersionGreaterOrEqualThan(latestVersionUpdateActivity.Payload.VersionUpdate.Version, latestVersion) {
- shouldNotify = false
- }
- }
- if !shouldNotify {
- return
- }
- // Create version update activity and inbox message.
- activity := &store.Activity{
- CreatorID: store.SystemBotID,
- Type: store.ActivityTypeVersionUpdate,
- Level: store.ActivityLevelInfo,
- Payload: &storepb.ActivityPayload{
- VersionUpdate: &storepb.ActivityVersionUpdatePayload{
- Version: latestVersion,
- },
- },
- }
- if _, err := r.Store.CreateActivity(ctx, activity); err != nil {
- return
- }
- hostUserRole := store.RoleHost
- users, err := r.Store.ListUsers(ctx, &store.FindUser{
- Role: &hostUserRole,
- })
- if err != nil {
- return
- }
- if len(users) == 0 {
- return
- }
- hostUser := users[0]
- if _, err := r.Store.CreateInbox(ctx, &store.Inbox{
- SenderID: store.SystemBotID,
- ReceiverID: hostUser.ID,
- Status: store.UNREAD,
- Message: &storepb.InboxMessage{
- Type: storepb.InboxMessage_VERSION_UPDATE,
- ActivityId: &activity.ID,
- },
- }); err != nil {
- slog.Error("failed to create inbox", slog.String("error", err.Error()))
- }
- }
- func (*Runner) GetLatestVersion() (string, error) {
- response, err := http.Get("https://www.usememos.com/api/version")
- if err != nil {
- return "", errors.Wrap(err, "failed to make http request")
- }
- defer response.Body.Close()
- buf := &bytes.Buffer{}
- _, err = buf.ReadFrom(response.Body)
- if err != nil {
- return "", errors.Wrap(err, "fail to read response body")
- }
- version := ""
- if err = json.Unmarshal(buf.Bytes(), &version); err != nil {
- return "", errors.Wrap(err, "fail to unmarshal get version response")
- }
- return version, nil
- }
|