From 200cb59b0e0156a6f62506dd70c440858e2898f0 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Thu, 12 Feb 2026 06:39:06 -0600 Subject: [PATCH] Remove conflict origs --- app/screen_home.go.orig | 531 ---------------------------------------- data/repo_auth.go.orig | 139 ----------- 2 files changed, 670 deletions(-) delete mode 100644 app/screen_home.go.orig delete mode 100644 data/repo_auth.go.orig diff --git a/app/screen_home.go.orig b/app/screen_home.go.orig deleted file mode 100644 index 2c1a81e..0000000 --- a/app/screen_home.go.orig +++ /dev/null @@ -1,531 +0,0 @@ -/* -Copyright © Brian Buller - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -package app - -import ( - "fmt" - "log/slog" - "net/url" - "strings" - "time" - - "git.bullercodeworks.com/brian/expds/data" - "git.bullercodeworks.com/brian/expds/data/models" - wd "git.bullercodeworks.com/brian/expds/widgets" - w "git.bullercodeworks.com/brian/tcell-widgets" - "github.com/bluesky-social/indigo/atproto/syntax" - "github.com/gdamore/tcell" - "github.com/skratchdot/open-golang/open" - "github.com/spf13/viper" - "golang.design/x/clipboard" -) - -type ScreenHome struct { - a *App - r *data.Repo - w, h int - style tcell.Style - - alert *w.Alert - - menuLayout *w.TopMenuLayout - - openPdsEntry *w.Field - - layout *w.LinearLayout - columns *w.LinearLayout - - activePds *models.Pds - pdsListing *wd.TreeBrowser - jsonContent *wd.JsonContent - status *wd.StatusBar - stPathBlock *wd.StatusBlock - - cli *w.Cli - - doOpen bool - isLoading bool - loading *w.Spinner - - cursor int -} - -func (s *ScreenHome) Init(a *App) { - s.a, s.r = a, a.repo - s.r.SetLogFunc(s.Log) - - s.style = a.style - - s.alert = w.NewAlert("expds.alert", s.style) - - s.openPdsEntry = w.NewField("home.openpds.field", s.style) - s.openPdsEntry.SetLabel("ID") - s.openPdsEntry.SetActive(true) - s.openPdsEntry.SetPos(w.Coord{X: 3, Y: 1}) - s.openPdsEntry.SetSize(w.Coord{X: 20, Y: 1}) - s.doOpen = true - - s.isLoading = false - s.loading = w.NewSpinner("home.loading", s.style) - s.loading.SetVisible(true) - s.loading.SetPos(w.Coord{X: 2, Y: 1}) - - s.menuLayout = w.NewTopMenuLayout("home.toplayout", s.style) - s.initMenu() - - s.cli = w.NewCli("home.cli", s.style) - s.initCli() - s.cli.SetVisible(false) - - s.layout = w.NewLinearLayout("home.layout", s.style) - - s.columns = w.NewLinearLayout("home.layout.columns", s.style) - s.columns.SetOrientation(w.LinLayH) - - //s.pdsListing = w.NewSimpleListWithHelp("pdslisting", s.style) - s.pdsListing = wd.NewTreeBrowser("pdslisting", s.style) - s.pdsListing.SetBorder([]rune{'─', '┬', '│', '┴', '─', '└', '│', '┌', '├', '─', '┤', '┬', '│', '┴', '┼'}) - - s.pdsListing.SetTitle(strings.Repeat(" ", 30)) - s.pdsListing.SetOnSelect(s.selectPdsListingEntry) - s.pdsListing.SetOnChange(s.changePdsList) - s.pdsListing.SetVimMode(viper.GetBool(data.KeyVimMode)) - s.pdsListing.SetLogger(s.Log) - - s.jsonContent = wd.NewJsonContent("jsoncontent", s.style) - km := s.jsonContent.GetKeyMap() - km.Add( - w.NewKey(w.BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool { - // Init returns an error if the package is not ready for use. - err := clipboard.Init() - if err != nil { - s.Log("Error initializing clipboard: %s", err.Error()) - return true - } - clipboard.Write(clipboard.FmtText, []byte(s.jsonContent.GetSelectedValue())) - return true - }), - w.NewKey(w.BuildEKr('O'), func(ev *tcell.EventKey) bool { - url := fmt.Sprintf("https://%s/xrpc/com.atproto.sync.getBlob?did=did:plc:pqwuemo2ic5tqmpwrajb2phi&cid=%s", s.activePds.AtId.String(), s.jsonContent.GetSelectedValue()) - open.Run(url) - return true - }), - ) - s.jsonContent.SetKeyMap(km) - s.jsonContent.SetBorder( - []rune{'─', '┐', '│', '┘', '─', '─', ' ', '─', '├', '─', '┤', '┬', '│', '┴', '┼'}, - ) - - statusStyle := s.style.Background(tcell.ColorDarkSlateGray) - s.status = wd.NewStatusBar("home.statusbar", statusStyle) - s.status.SetPos(w.Coord{X: 0, Y: s.a.GetH() - 1}) - s.status.SetLogger(s.Log) - s.stPathBlock = wd.NewStatusBlock("home.statusbar.block", statusStyle.Foreground(tcell.ColorDarkSlateGray).Background(tcell.ColorOrange)) - s.stPathBlock.SetType(wd.SBTypePath) - s.stPathBlock.SetParts([]string{"No PDS Loaded"}) - s.status.Add(s.stPathBlock) - - s.columns.AddAll(s.pdsListing, s.jsonContent) - - s.layout.AddAll(s.columns) - s.layout.SetLogger(s.Log) - s.layout.SetWeight(s.columns, 4) - s.menuLayout.SetWidget(s.layout) - s.layout.SetLogger(s.Log) - s.columns.SetLogger(s.Log) -} - -func (s *ScreenHome) GetName() string { return "home" } -func (s *ScreenHome) HandleResize(ev *tcell.EventResize) { - s.w, s.h = ev.Size() - s.menuLayout.HandleResize(w.Coord{X: s.w, Y: s.h - 1}.ResizeEvent()) - s.alert.HandleResize(ev) - - s.status.SetPos(w.Coord{X: 0, Y: s.h - 1}) - s.status.HandleResize(w.Coord{X: s.w, Y: 1}.ResizeEvent()) -} - -func (s *ScreenHome) HandleKey(ev *tcell.EventKey) bool { -<<<<<<< HEAD - if s.showAlert { - handled := s.alert.HandleKey(ev) - s.alert.SetMessage(fmt.Sprintf("Alert Handled? %v -> %s", handled, ev.Name())) - return handled - } -======= ->>>>>>> 367d62ff009186e5aa584fd069dd57aaf7d46a8a - if ev.Key() == tcell.KeyF12 { - s.toggleCli() - return true - } - m := s.menuLayout.Menu() - if ev.Key() == tcell.KeyEscape { - return s.menuLayout.HandleKey(ev) - } else if m.Active() { - return s.menuLayout.HandleKey(ev) - } - - if s.doOpen { - if ev.Key() == tcell.KeyCtrlU { - s.openPdsEntry.SetValue("") - return true - } - - if ev.Key() == tcell.KeyEnter { - return s.cliGetPds("getpds", s.openPdsEntry.Value()) - } - return s.openPdsEntry.HandleKey(ev) - } - - return s.menuLayout.HandleKey(ev) -} -func (s *ScreenHome) HandleTime(ev *tcell.EventTime) { - s.menuLayout.HandleTime(ev) - s.loading.HandleTime(ev) - s.status.HandleTime(ev) -} -func (s *ScreenHome) Draw() { - if s.doOpen { - s.menuLayout.SetStyle(s.style.Foreground(tcell.ColorGray)) - } - s.menuLayout.SetStyle(s.style) - m := s.menuLayout.Menu() - s.a.DrawWidget(s.menuLayout) - if s.doOpen && !m.Active() { - s.a.DrawWidget(s.openPdsEntry) - } - - // These are outside of the menuLayout - if s.isLoading { - s.a.DrawWidget(s.loading) - } - s.a.DrawWidget(s.status) -} -func (s *ScreenHome) Exit() error { return nil } -func (s *ScreenHome) Log(t string, a ...any) { - s.cli.Log(t, a...) - s.showCli() -} - -func (s *ScreenHome) initMenu() { - s.menuLayout.SetActive(true) - wrk := "[ ]" - if viper.GetBool(data.KeyVimMode) { - wrk = "[X]" - } - vimText := fmt.Sprintf("%s Vim Mode", wrk) - wrk = "[ ]" - if viper.GetBool(data.KeyRecNmInfer) { - wrk = "[X]" - } - inferRecNm := fmt.Sprintf("%s Infer Record Names", wrk) - s.menuLayout.AddMenuItems( - s.menuLayout.CreateMenuItem("file", "File", nil, 'f', - s.menuLayout.CreateMenuItem("file.openpds", "Open PDS", func() bool { - s.menuLayout.ToggleMenu() - s.doOpen = true - s.pdsListing.SetTitle(strings.Repeat(" ", 30)) - return true - }, 'o'), - s.menuLayout.CreateMenuItem("file.reloadpds", "Reload PDS", func() bool { - s.menuLayout.ToggleMenu() - if s.activePds == nil { - return false - } - return s.cliGetPds("getpds", s.activePds.AtId.String()) - }, 'r'), - s.menuLayout.CreateMenuItem("file.exit", "Exit", func() bool { - s.a.Exit() - return true - }, 'x'), - ), - s.menuLayout.CreateMenuItem("settings", "Settings", nil, 's', - s.menuLayout.CreateMenuItem("settings.vimmode", vimText, func() bool { - s.menuLayout.ToggleMenu() - viper.Set(data.KeyVimMode, !viper.GetBool(data.KeyVimMode)) - viper.WriteConfig() - s.update() - return true - }, 'v'), - s.menuLayout.CreateMenuItem("settings.inferrecnm", inferRecNm, func() bool { - s.menuLayout.ToggleMenu() - viper.Set(data.KeyRecNmInfer, !viper.GetBool(data.KeyRecNmInfer)) - viper.WriteConfig() - s.update() - return true - }, 'r'), - ), - ) -} - -func (s *ScreenHome) update() { - if s.doOpen { - s.menuLayout.SetWidget(s.openPdsEntry) - } else { - s.menuLayout.SetWidget(s.layout) - } - s.pdsListing.SetVimMode(viper.GetBool(data.KeyVimMode)) - s.jsonContent.SetVimMode(viper.GetBool(data.KeyVimMode)) - vimMI := s.menuLayout.FindItem("settings.vimmode") - wrk := "[ ]" - if viper.GetBool(data.KeyVimMode) { - wrk = "[X]" - } - vimMI.SetLabel(fmt.Sprintf("%s Vim Mode", wrk)) - recNmInf := s.menuLayout.FindItem("settings.inferrecnm") - wrk = "[ ]" - if viper.GetBool(data.KeyRecNmInfer) { - wrk = "[X]" - } - recNmInf.SetLabel(fmt.Sprintf("%s Infer Record Names", wrk)) - - miReload := s.menuLayout.FindItem("file.reloadpds") - if s.activePds == nil { - miReload.SetDisabled(true) - miReload.SetStyle(s.style.Foreground(tcell.ColorGray)) - } else { - miReload.SetDisabled(false) - miReload.SetStyle(s.style.Foreground(tcell.ColorLime)) - } -} - -func (s *ScreenHome) initCli() { - s.cli.SetVisible(true) - s.cli.AddCommand(w.NewCliCommand("getpds", s.cliGetPds)) - s.cli.AddCommand(w.NewCliCommand("authpds", s.cliAuthPds)) - s.cli.AddCommand(w.NewCliCommand("backuppds", s.cliBackupPds)) - s.cli.AddCommand(w.NewCliCommand("sendstatus", s.cliSendStatus)) -} - -func (s *ScreenHome) toggleCli() { - if s.layout.Contains(s.cli) { - s.layout.Delete(s.cli) - s.layout.ActivateWidget(s.columns) - } else { - s.layout.Add(s.cli) - s.cli.SetVisible(true) - s.layout.ActivateWidget(s.cli) - } -} -func (s *ScreenHome) hideCli() { - s.cli.SetVisible(false) - if s.layout.Contains(s.cli) { - s.layout.Delete(s.cli) - } -} -func (s *ScreenHome) showCli() { - s.cli.SetVisible(true) - if !s.layout.Contains(s.cli) { - s.layout.Add(s.cli) - } -} - -func (s *ScreenHome) cliGetPds(args ...string) bool { - s.isLoading = true - if len(args) < 1 { - s.Log("No id given.") - s.Log("Usage: 'getpds '") - s.isLoading = false - return true - } - go func() { - defer func() { s.isLoading = false }() - var pds *models.Pds - var err error - if s.activePds != nil && string(s.activePds.AtId) == args[1] { - pds, err = s.r.ReloadPds(args[1]) - } else { - pds, err = s.r.GetPDS(args[1]) - } - if err != nil { - s.Log(err.Error()) - return - } else if pds == nil { - s.Log("PDS (%s) Not Found.", args[1]) - return - } - s.doOpen = false - slog.Default().Debug(fmt.Sprintf("Retrieved: %s (%s) at %s", pds.AtId, pds.Did, time.Now().Format(time.RFC3339))) - s.activePds = pds - s.updatePdsListing() - n, err := s.pdsListing.GetActiveNode() - if err == nil && n != nil { - s.changePdsList(n) - } - - s.layout.ActivateWidget(s.columns) - s.columns.ActivateWidget(s.pdsListing) - }() - return true -} - -func (s *ScreenHome) cliAuthPds(args ...string) bool { - if s.activePds == nil { - s.Log("No active PDS.") - return true - } - s.isLoading = true - go func() { - defer func() { s.isLoading = false }() - atid := s.activePds.AtId.String() - callbackRes := make(chan url.Values, 1) - listenPort, err := s.r.Auth.ListenForCallback(callbackRes) - if err != nil { - s.Log("Error Instantiating HTTP Server for Callback: %w", err) - return - } - s.Log("Listening on %d", listenPort) - var authUrl string - authUrl, err = s.r.Auth.StartAuthFlow(listenPort, atid, callbackRes) - if err != nil { - s.Log("Error starting auth flow: %w", err) - } -<<<<<<< HEAD - s.alert.SetTitle("Authentication Started") - s.alert.SetMessage(fmt.Sprintf("OAuth Process Started.\nIf a browser window didn't open, you can open this URL manually:\n%s", authUrl)) - s.alert.SetVisible(true) - s.alert.SetActive(true) - s.showAlert = true -======= - s.Log("Authentication Started") - s.Log(fmt.Sprintf("OAuth Process Started.\nIf a browser window didn't open, you can open this URL manually:\n%s", strings.ReplaceAll(authUrl, "%", "%%"))) ->>>>>>> 367d62ff009186e5aa584fd069dd57aaf7d46a8a - }() - return true -} - -func (s *ScreenHome) cliBackupPds(args ...string) bool { - if s.activePds == nil { - s.Log("No active PDS.") - return true - } - s.isLoading = true - go func() { - defer func() { s.isLoading = false }() - nm, sz, err := s.activePds.Backup() - if err != nil { - s.Log("Error: %w", err) - return - } - s.Log("Backup Created: %s (%d bytes)", nm, sz) - }() - return true -} - -func (s *ScreenHome) cliSendStatus(args ...string) bool { - if s.activePds == nil { - s.Log("No active PDS.") - return true - } - s.isLoading = true - go func() { - defer func() { s.isLoading = false }() - if !s.r.Auth.HasAuth(s.activePds.Did) { - s.Log("Not authorized. Run `authpds`") - return - } - err := s.r.SendToPDS(s.activePds.Did) - if err != nil { - s.Log("Error sending status: %w", err) - } - }() - return true -} - -func (s *ScreenHome) updatePdsListing() { - s.pdsListing.SetTitle(fmt.Sprintf("─ %s (%s)", s.activePds.AtId.String(), s.activePds.Did.String())) - s.pdsListing.Clear() - nsidList := s.activePds.NSIDStringList() - var tree []*wd.TreeNode - for i, v := range nsidList { - t := wd.NewTreeNode(v, v) - nsid := s.activePds.NSIDs[i] - rIds := s.activePds.GetRecordIdsFor(nsid) - for j := range rIds { - label := rIds[j] - if viper.GetBool(data.KeyRecNmInfer) { - if rec, ok := s.activePds.Records[rIds[j]]; ok { - for k := range rec { - if k == "name" || k == "title" || k == "label" || k == "displayName" { - if f, ok := rec[k].(string); ok { - label = fmt.Sprintf("%s (%s)", f, rIds[j]) - break - } - } - } - } - } - - c := wd.NewTreeNode(label, rIds[j]) - t.AddChild(c) - } - tree = append(tree, t) - } - s.pdsListing.SetTree(tree) - s.layout.ActivateWidget(s.columns) - s.columns.ActivateWidget(s.pdsListing) - s.pdsListing.SetActive(true) - s.pdsListing.SetFocusable(true) - s.hideCli() -} - -func (s *ScreenHome) selectPdsListingEntry(tn *wd.TreeNode) bool { - if !s.updateJsonView(tn) { - return false - } - if tn.HasChildren() { - tn.ToggleExpand() - s.pdsListing.UpdateList() - } else { - s.columns.ActivateWidget(s.jsonContent) - } - - return true -} - -func (s *ScreenHome) changePdsList(tn *wd.TreeNode) bool { - upd := s.updateJsonView(tn) - upd = s.updateStatusPathBlock(tn) - return upd -} -func (s *ScreenHome) updateStatusPathBlock(tn *wd.TreeNode) bool { - s.stPathBlock.SetParts(tn.GetLabelPath()) - return true -} - -func (s *ScreenHome) updateJsonView(tn *wd.TreeNode) bool { - // TODO: Update JSON View - if tn.Depth() == 0 { - nsid, err := syntax.ParseNSID(tn.Value()) - if err != nil { - s.Log("error parsing NSID from %s: %w", tn.Value(), err) - return false - } - recordIds := s.activePds.GetRecordIdsFor(nsid) - s.jsonContent.SetValue(recordIds) - return true - } else { - s.jsonContent.SetValue(s.activePds.Records[tn.Value()]) - } - - return true -} diff --git a/data/repo_auth.go.orig b/data/repo_auth.go.orig deleted file mode 100644 index b029995..0000000 --- a/data/repo_auth.go.orig +++ /dev/null @@ -1,139 +0,0 @@ -package data - -import ( - "context" - "errors" - "fmt" - "log/slog" - "net" - "net/http" - "net/url" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/bluesky-social/indigo/atproto/auth/oauth" - "github.com/bluesky-social/indigo/atproto/syntax" - "github.com/spf13/viper" -) - -type AuthRepo struct { - r *Repo - oauthClient *oauth.ClientApp - oauthConfig *oauth.ClientConfig - store *SqliteStore - context context.Context - -<<<<<<< HEAD - session *oauth.ClientSessionData - authError error -======= - session *oauth.ClientSessionData - - Logger *slog.Logger ->>>>>>> 367d62ff009186e5aa584fd069dd57aaf7d46a8a -} - -func NewAuthRepo(r *Repo) (*AuthRepo, error) { - a := &AuthRepo{ - r: r, - context: r.context, - Logger: r.Logger, - } - var err error - a.oauthConfig, a.oauthClient, a.store, err = a.buildOAuthClient() - if err != nil { - return nil, err - } - return a, nil -} - -// Build the OAuthClient connected to our sqlite db -func (r *AuthRepo) buildOAuthClient() (*oauth.ClientConfig, *oauth.ClientApp, *SqliteStore, error) { - config := oauth.ClientConfig{ - ClientID: "https://expds.bullercodeworks.com/oauth-client-metadata.json", - Scopes: []string{"atproto", "repo:*", "blob:*/*"}, - UserAgent: "expds", - } - - store, err := NewSqliteStore(&SqliteStoreConfig{ - DatabasePath: r.prepareDbPath(), - SessionExpiryDuration: time.Hour * 24 * 90, - SessionInactivityDuration: time.Hour * 24 * 14, - AuthRequestExpiryDuration: time.Minute * 30, - }) - if err != nil { - return nil, nil, nil, err - } - - oauthClient := oauth.NewClientApp(&config, store) - return &config, oauthClient, store, nil -} - -func (r *AuthRepo) StartAuthFlow(port int, identifier string, callbackRes chan url.Values) (string, error) { - r.oauthConfig.CallbackURL = fmt.Sprintf("http://127.0.0.1:%d/callback", port) - authUrl, err := r.oauthClient.StartAuthFlow(r.context, identifier) - if err != nil { - return "", fmt.Errorf("error logging in: %w", err) - } - if !strings.HasPrefix(authUrl, "https://") { - return "", fmt.Errorf("non-https authUrl") - } - go func() { - exec.Command("xdg-open", authUrl).Start() - r.session, r.authError = r.oauthClient.ProcessCallback(r.context, <-callbackRes) - }() - return authUrl, nil -} - -// Follows XDG conventions and creates the directories if necessary. -// By default, on linux, this will be "~/.local/share/go-oauth-cli-app/oauth_sessions.sqlite3" -func (r *AuthRepo) prepareDbPath() string { - return filepath.Join(viper.GetString(KeyDataDir), "expds.sqlite3") -} - -// HTTP Server listening for OAuth Response -func (r *AuthRepo) ListenForCallback(res chan url.Values) (int, error) { - listener, err := net.Listen("tcp", ":0") - if err != nil { - return 0, err - } - - mux := http.NewServeMux() - server := &http.Server{ - Handler: mux, - } - - mux.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) { - res <- req.URL.Query() - w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.WriteHeader(200) - w.Write([]byte("

expds

You can safely close this window and return to your application.

\n")) - go server.Shutdown(r.context) - }) - - go func() { - err := server.Serve(listener) - if !errors.Is(err, http.ErrServerClosed) { - panic(err) - } - r.Logger.Debug("Server Shut Down") - }() - - return listener.Addr().(*net.TCPAddr).Port, nil -} - -func (r *AuthRepo) HasAuth(did syntax.DID) bool { - sess, err := r.GetSession(did) - return err == nil && sess != nil -} - -func (r *AuthRepo) GetSession(did syntax.DID) (*oauth.ClientSession, error) { - sess, err := r.store.GetMostRecentSessionFor(r.context, did) - if err != nil { - return nil, fmt.Errorf("error getting most recent session: %w", err) - } - r.Logger.Warn(fmt.Sprintf("GetSession(): Resuming Session: %s (%s)", sess.SessionID, sess.AccountDID)) - return r.oauthClient.ResumeSession(r.context, sess.AccountDID, sess.SessionID) -}