diff --git a/app/screen_home.go b/app/screen_home.go index 9c3e2c6..51132d7 100644 --- a/app/screen_home.go +++ b/app/screen_home.go @@ -72,7 +72,6 @@ type ScreenHome struct { func (s *ScreenHome) Init(a *App) { s.a, s.r = a, a.repo - s.r.SetLogFunc(s.Log) s.style = a.style @@ -82,6 +81,7 @@ func (s *ScreenHome) Init(a *App) { return true }) s.alert.SetCancelPressed(nil) + s.alert.SetLogger(s.Log) s.openPdsEntry = w.NewField("home.openpds.field", s.style) s.openPdsEntry.SetLabel("ID") @@ -170,6 +170,8 @@ func (s *ScreenHome) Init(a *App) { s.menuLayout.SetWidget(s.layout) s.layout.SetLogger(s.Log) s.columns.SetLogger(s.Log) + + s.r.SetLogFunc(s.Log) } func (s *ScreenHome) GetName() string { return "home" } @@ -209,14 +211,18 @@ func (s *ScreenHome) HandleKey(ev *tcell.EventKey) bool { } return s.openPdsEntry.HandleKey(ev) } + switch ev.Key() { case tcell.KeyCtrlO: return s.menuOpenPds() + case tcell.KeyCtrlA: + return s.addNewRecord() case tcell.KeyCtrlD: return s.deleteCurrentRecord() case tcell.KeyCtrlR: return s.menuRefreshPds() } + return s.menuLayout.HandleKey(ev) } func (s *ScreenHome) HandleTime(ev *tcell.EventTime) { @@ -530,12 +536,12 @@ func (s *ScreenHome) menuAuthPds() bool { time.Sleep(100) } s.alert.SetVisible(false) + s.updatePdsListing() }() } } }() return true - } func (s *ScreenHome) menuOpenPds() bool { s.menuLayout.HideMenu() @@ -622,6 +628,32 @@ func (s *ScreenHome) getPds(atId string) { }() } +func (s *ScreenHome) addNewRecord() bool { + if s.activePds == nil { + return false + } + tn, err := s.pdsListing.GetActiveNode() + if err != nil { + s.Log("error getting active node") + return true + } + tnPath := tn.GetValuePath() + if len(tnPath) != 2 { + return false + } + /* + tnLabelPath := tn.GetLabelPath() + nsid, err := syntax.ParseNSID(tnPath[0]) + if err != nil { + s.Log("error parsing NSID from %s: %w", tnPath[0], err) + return false + } + //tmplt := s.activePds.GetBlankRecordForNSID(nsid) + //s.Log("%s", tmplt) + */ + return true +} + func (s *ScreenHome) deleteCurrentRecord() bool { tn, err := s.pdsListing.GetActiveNode() if err != nil { @@ -639,17 +671,15 @@ func (s *ScreenHome) deleteCurrentRecord() bool { return false } rkey := tnPath[1] - /* - if err := s.r.DeleteRecord(s.activePds.Did, nsid, rkey); err != nil { - s.Log("error deleting record: %w", err) - } - */ s.alert.SetTitle("Confirm Deletion") s.alert.SetMessage(fmt.Sprintf("Are you sure you want to delete this record?\n%s: %s\nThis cannot be undone.", tnLabelPath[0], tnLabelPath[1])) s.alert.SetVisible(true) s.alert.SetActive(true) s.alert.SetOkPressed(func() bool { - s.r.DeleteRecord(s.activePds.Did, nsid, rkey) + if err := s.r.DeleteRecord(s.activePds.Did, nsid, rkey); err != nil { + panic(err) + s.Log("! Error Deleting Record: %s / %s / %s", s.activePds.Did, nsid, rkey) + } s.alert.SetVisible(false) s.alert.SetActive(false) return true @@ -659,7 +689,7 @@ func (s *ScreenHome) deleteCurrentRecord() bool { s.alert.SetActive(false) return true }) - s.alert.SetPos(w.Coord{X: s.w / 4, Y: s.h / 4}) s.alert.HandleResize(w.Coord{X: s.w / 4, Y: s.h / 4}.ResizeEvent()) + s.alert.SetPos(w.Coord{X: (s.w / 2) - (s.alert.GetW() / 2), Y: (s.h / 2) - (s.alert.GetH() / 2)}) return true } diff --git a/data/models/pds.go b/data/models/pds.go index 7b2472e..68f734e 100644 --- a/data/models/pds.go +++ b/data/models/pds.go @@ -60,6 +60,8 @@ type Pds struct { recordIdsToNSID map[string]syntax.NSID Records map[string]map[string]any + TIDClock syntax.TIDClock + RefreshTime time.Time } diff --git a/data/repo.go b/data/repo.go index 91557f3..1056cba 100644 --- a/data/repo.go +++ b/data/repo.go @@ -67,6 +67,11 @@ func NewRepo() (*Repo, error) { func (r *Repo) SetLogFunc(l func(string, ...any)) { r.logFunc = l r.handler = NewAppLogHandler(r.logFunc) + if viper.GetBool(KeyDebug) { + r.handler.SetLevel(slog.LevelDebug) + } else { + r.handler.SetLevel(slog.LevelWarn) + } slog.SetDefault(slog.New(r.handler)) r.Logger = slog.Default() r.Logger.Debug("New Log Func Set for slog") diff --git a/data/repo_auth.go b/data/repo_auth.go index ad53912..c2d6389 100644 --- a/data/repo_auth.go +++ b/data/repo_auth.go @@ -29,14 +29,17 @@ type AuthRepo struct { authUrl string authError error + refreshes map[syntax.DID]time.Time + Logger *slog.Logger } func NewAuthRepo(r *Repo) (*AuthRepo, error) { a := &AuthRepo{ - r: r, - context: r.context, - Logger: r.Logger, + r: r, + context: r.context, + Logger: r.Logger, + refreshes: make(map[syntax.DID]time.Time), } var err error a.oauthConfig, a.oauthClient, a.store, err = a.buildOAuthClient() @@ -131,6 +134,20 @@ func (r *AuthRepo) ListenForCallback(res chan url.Values) (int, error) { func (r *AuthRepo) HasAuth(did syntax.DID) bool { sess, err := r.GetSession(did) + if err != nil || sess == nil { + return false + } + exp := time.Now().Add(time.Hour * -12) + if tm, ok := r.refreshes[did]; ok && tm.After(exp) { + return true + } + _, err = sess.RefreshTokens(r.context) + if err != nil { + r.Logger.Debug("Failed to refresh tokens") + return false + } + r.refreshes[did] = time.Now() + return err == nil && sess != nil } diff --git a/data/repo_pds.go b/data/repo_pds.go index d6ee2d4..3440926 100644 --- a/data/repo_pds.go +++ b/data/repo_pds.go @@ -1,6 +1,7 @@ package data import ( + "fmt" "time" "git.bullercodeworks.com/brian/expds/data/models" @@ -49,7 +50,7 @@ func (r *Repo) SendToPDS(did syntax.DID) error { if err := c.Post(r.context, "com.atproto.repo.createRecord", body, &resp); err != nil { return err } - r.Logger.Debug("posted: %s :: %s", resp.Uri.Authority(), resp.Uri.RecordKey()) + r.Logger.Debug(fmt.Sprintf("posted: %s :: %s", resp.Uri.Authority(), resp.Uri.RecordKey())) return nil } @@ -68,10 +69,11 @@ func (r *Repo) DeleteRecord(did syntax.DID, collection syntax.NSID, rkey string) Cid syntax.CID `json:"cid"` Rev syntax.TID `json:"rev"` } - r.Logger.Debug("deleting record (%s)", rkey) + r.Logger.Debug(fmt.Sprintf("deleting record (%s)", rkey)) if err := c.Post(r.context, "com.atproto.repo.deleteRecord", body, &resp); err != nil { + r.Logger.Warn(fmt.Sprintf("error deleting record: %s", err.Error())) return err } - r.Logger.Debug("posted: %s :: %s", resp.Cid.String(), resp.Rev.String()) + r.Logger.Debug(fmt.Sprintf("posted: %s :: %s", resp.Cid.String(), resp.Rev.String())) return nil } diff --git a/widgets/json_content.go b/widgets/json_content.go index 3039f5c..f95c1f3 100644 --- a/widgets/json_content.go +++ b/widgets/json_content.go @@ -57,6 +57,8 @@ type JsonContent struct { vimMode bool cursor int + field *wd.Field + editKey, editVal bool editValType int @@ -84,6 +86,7 @@ func (w *JsonContent) Init(id string, style tcell.Style) { w.id = id w.style = style w.visible = true + w.field = wd.NewField(fmt.Sprintf("%s-field", id), style) w.keyMap = wd.NewKeyMap( wd.NewKey(wd.BuildEK(tcell.KeyUp), func(_ *tcell.EventKey) bool { return w.MoveUp() }), wd.NewKey(wd.BuildEK(tcell.KeyDown), func(_ *tcell.EventKey) bool { return w.MoveDown() }), @@ -148,7 +151,9 @@ func (w *JsonContent) Draw(screen tcell.Screen) { ln := len(w.contents) start, end := 0, ln-1 if ln == 0 { - return + if !w.editable { + return + } } if ln > w.h-2 { mid := h / 2 @@ -225,6 +230,12 @@ func (w *JsonContent) MinH() int { return len(w.contents) } func (w *JsonContent) SetValue(v any) error { w.value = v + if w.value == nil { + w.valueString = "" + w.contents = []string{} + w.cursor = 0 + return nil + } // Go ahead and try to build the json for v bts, err := json.MarshalIndent(v, "", " ") if err != nil { @@ -253,6 +264,7 @@ func (w *JsonContent) SetValue(v any) error { } return err } +func (w *JsonContent) ClearValue() error { return w.SetValue(nil) } func (w *JsonContent) SetBorder(brd []rune) { if len(brd) == 0 { @@ -376,48 +388,6 @@ func (w *JsonContent) getItemVal(line int) (string, error) { return "", errors.New("error finding value") } -/* -func (w *JsonContent) getItemValType(line int) int { - if line < 0 || line >= len(w.contents) { - return JsonTypeErr - } - - text := w.contents[line] - key, rest := w.getNextQuotedString(text) - rest = strings.Trim(rest, ", ") - if rest == "" { - if key != "" { - // Looks like a string value in an array - return JsonTypeString - } else rest == "true" || rest == "false" { - return JsonTypeBool - } - // see if we can parse this as a number - num, err := strconv.Atoi(rest) - if err == nil { - return JsonTypeNumber - } - return JsonType - } - if key == "" { - return "", "", errors.New("error finding quoted string") - } else if rest == "" { - // We have a 'key' value, but no 'rest' so this is likely an item in array - return "", key, nil - } - rest = strings.Trim(rest, ":, ") - if rest[0] == '{' { - - } - val, rest := w.getNextQuotedString(rest) - if val != "" { - return key, val, nil - } - // Val isn't a quoted string, - return key, rest, nil -} -*/ - func (w *JsonContent) getItemDepth(line int) int { if line < 0 || line >= len(w.contents) { return 0