Compare commits

..

No commits in common. "monodevice" and "main" have entirely different histories.

3 changed files with 127 additions and 3 deletions

View File

@ -1 +0,0 @@
golang 1.19.3

View File

@ -85,7 +85,7 @@ func initialModel(ctx *context.Context, t table.Model, initialQuery string, numE
if initialQuery != "" {
queryInput.SetValue(initialQuery)
}
return model{ctx: ctx, spinner: s, isLoading: false, table: t, runQuery: &initialQuery, queryInput: queryInput, numEntries: numEntries}
return model{ctx: ctx, spinner: s, isLoading: true, table: t, runQuery: &initialQuery, queryInput: queryInput, numEntries: numEntries}
}
func (m model) Init() tea.Cmd {
@ -199,6 +199,10 @@ func (m model) View() string {
if m.quitting {
return ""
}
loadingMessage := ""
if m.isLoading {
loadingMessage = fmt.Sprintf("%s Loading hishtory entries from other devices...", m.spinner.View())
}
warning := ""
if m.isOffline {
warning += "Warning: failed to contact the hishtory backend (are you offline?), so some results may be stale\n\n"
@ -206,7 +210,7 @@ func (m model) View() string {
if m.searchErr != nil {
warning += fmt.Sprintf("Warning: failed to search: %v\n\n", m.searchErr)
}
return fmt.Sprintf("\n%s%s\nSearch Query: %s\n\n%s\n", warning, m.banner, m.queryInput.View(), baseStyle.Render(m.table.View()))
return fmt.Sprintf("\n%s\n%s%s\nSearch Query: %s\n\n%s\n", loadingMessage, warning, m.banner, m.queryInput.View(), baseStyle.Render(m.table.View()))
}
func getRows(ctx *context.Context, columnNames []string, query string, numEntries int) ([]table.Row, int, error) {
@ -407,6 +411,32 @@ func TuiQuery(ctx *context.Context, gitCommit, initialQuery string) error {
return err
}
p := tea.NewProgram(initialModel(ctx, t, initialQuery, numEntries), tea.WithOutput(os.Stderr))
go func() {
err := RetrieveAdditionalEntriesFromRemote(ctx)
if err != nil {
p.Send(err)
}
p.Send(doneDownloadingMsg{})
}()
// Async: Process deletion requests
go func() {
err := ProcessDeletionRequests(ctx)
if err != nil {
p.Send(err)
}
}()
// Async: Check for any banner from the server
go func() {
banner, err := GetBanner(ctx, gitCommit)
if err != nil {
if IsOfflineError(err) {
p.Send(offlineMsg{})
} else {
p.Send(err)
}
}
p.Send(bannerMsg{banner: string(banner)})
}()
// Blocking: Start the TUI
err = p.Start()
if err != nil {

View File

@ -3,6 +3,7 @@ package main
import (
"bufio"
"context"
"encoding/json"
"fmt"
"log"
"os"
@ -12,6 +13,7 @@ import (
"github.com/ddworken/hishtory/client/data"
"github.com/ddworken/hishtory/client/hctx"
"github.com/ddworken/hishtory/client/lib"
"github.com/ddworken/hishtory/shared"
)
var GitCommit string = "Unknown"
@ -24,6 +26,7 @@ func main() {
switch os.Args[1] {
case "saveHistoryEntry":
ctx := hctx.MakeContext()
lib.CheckFatalError(maybeUploadSkippedHistoryEntries(ctx))
saveHistoryEntry(ctx)
case "query":
ctx := hctx.MakeContext()
@ -295,9 +298,31 @@ Supported commands:
}
func printDumpStatus(config hctx.ClientConfig) {
dumpRequests, err := getDumpRequests(config)
lib.CheckFatalError(err)
fmt.Printf("Dump Requests: ")
for _, d := range dumpRequests {
fmt.Printf("%#v, ", *d)
}
fmt.Print("\n")
}
func getDumpRequests(config hctx.ClientConfig) ([]*shared.DumpRequest, error) {
if config.IsOffline {
return make([]*shared.DumpRequest, 0), nil
}
resp, err := lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(config.UserSecret) + "&device_id=" + config.DeviceId)
if lib.IsOfflineError(err) {
return []*shared.DumpRequest{}, nil
}
if err != nil {
return nil, err
}
var dumpRequests []*shared.DumpRequest
err = json.Unmarshal(resp, &dumpRequests)
return dumpRequests, err
}
func query(ctx *context.Context, query string) {
db := hctx.GetDb(ctx)
err := lib.RetrieveAdditionalEntriesFromRemote(ctx)
@ -329,6 +354,43 @@ func displayBannerIfSet(ctx *context.Context) error {
return nil
}
func maybeUploadSkippedHistoryEntries(ctx *context.Context) error {
config := hctx.GetConf(ctx)
if !config.HaveMissedUploads {
return nil
}
if config.IsOffline {
return nil
}
// Upload the missing entries
db := hctx.GetDb(ctx)
query := fmt.Sprintf("after:%s", time.Unix(config.MissedUploadTimestamp, 0).Format("2006-01-02"))
entries, err := lib.Search(ctx, db, query, 0)
if err != nil {
return fmt.Errorf("failed to retrieve history entries that haven't been uploaded yet: %v", err)
}
hctx.GetLogger().Infof("Uploading %d history entries that previously failed to upload (query=%#v)\n", len(entries), query)
jsonValue, err := lib.EncryptAndMarshal(config, entries)
if err != nil {
return err
}
_, err = lib.ApiPost("/api/v1/submit?source_device_id="+config.DeviceId, "application/json", jsonValue)
if err != nil {
// Failed to upload the history entry, so we must still be offline. So just return nil and we'll try again later.
return nil
}
// Mark down that we persisted it
config.HaveMissedUploads = false
config.MissedUploadTimestamp = 0
err = hctx.SetConfig(config)
if err != nil {
return fmt.Errorf("failed to mark a history entry as uploaded: %v", err)
}
return nil
}
func saveHistoryEntry(ctx *context.Context) {
config := hctx.GetConf(ctx)
if !config.IsEnabled {
@ -366,6 +428,39 @@ func saveHistoryEntry(ctx *context.Context) {
}
}
// Check if there is a pending dump request and reply to it if so
dumpRequests, err := getDumpRequests(config)
if err != nil {
if lib.IsOfflineError(err) {
// It is fine to just ignore this, the next command will retry the API and eventually we will respond to any pending dump requests
dumpRequests = []*shared.DumpRequest{}
hctx.GetLogger().Infof("Failed to check for dump requests because we failed to connect to the remote server!")
} else {
lib.CheckFatalError(err)
}
}
if len(dumpRequests) > 0 {
lib.CheckFatalError(lib.RetrieveAdditionalEntriesFromRemote(ctx))
entries, err := lib.Search(ctx, db, "", 0)
lib.CheckFatalError(err)
var encEntries []*shared.EncHistoryEntry
for _, entry := range entries {
enc, err := data.EncryptHistoryEntry(config.UserSecret, *entry)
lib.CheckFatalError(err)
encEntries = append(encEntries, &enc)
}
reqBody, err := json.Marshal(encEntries)
lib.CheckFatalError(err)
for _, dumpRequest := range dumpRequests {
if !config.IsOffline {
_, err := lib.ApiPost("/api/v1/submit-dump?user_id="+dumpRequest.UserId+"&requesting_device_id="+dumpRequest.RequestingDeviceId+"&source_device_id="+config.DeviceId, "application/json", reqBody)
lib.CheckFatalError(err)
}
}
}
// Handle deletion requests
lib.CheckFatalError(lib.ProcessDeletionRequests(ctx))
}
func export(ctx *context.Context, query string) {