(ctx context.DnoteCtx)
| 1090 | } |
| 1091 | |
| 1092 | func newRun(ctx context.DnoteCtx) infra.RunEFunc { |
| 1093 | return func(cmd *cobra.Command, args []string) error { |
| 1094 | // Override APIEndpoint if flag was provided |
| 1095 | if apiEndpointFlag != "" { |
| 1096 | ctx.APIEndpoint = apiEndpointFlag |
| 1097 | } |
| 1098 | |
| 1099 | if ctx.SessionKey == "" { |
| 1100 | return errors.New("not logged in") |
| 1101 | } |
| 1102 | |
| 1103 | if err := migrate.Run(ctx, migrate.RemoteSequence, migrate.RemoteMode); err != nil { |
| 1104 | return errors.Wrap(err, "running remote migrations") |
| 1105 | } |
| 1106 | |
| 1107 | tx, err := ctx.DB.Begin() |
| 1108 | if err != nil { |
| 1109 | return errors.Wrap(err, "beginning a transaction") |
| 1110 | } |
| 1111 | |
| 1112 | syncState, err := client.GetSyncState(ctx) |
| 1113 | if err != nil { |
| 1114 | return errors.Wrap(err, "getting the sync state from the server") |
| 1115 | } |
| 1116 | lastSyncAt, err := getLastSyncAt(tx) |
| 1117 | if err != nil { |
| 1118 | return errors.Wrap(err, "getting the last sync time") |
| 1119 | } |
| 1120 | lastMaxUSN, err := getLastMaxUSN(tx) |
| 1121 | if err != nil { |
| 1122 | return errors.Wrap(err, "getting the last max_usn") |
| 1123 | } |
| 1124 | |
| 1125 | log.Debug("lastSyncAt: %d, lastMaxUSN: %d, syncState: %+v\n", lastSyncAt, lastMaxUSN, syncState) |
| 1126 | |
| 1127 | // Handle a case where server has MaxUSN=0 but local has data (server switch) |
| 1128 | var bookCount, noteCount int |
| 1129 | if err := tx.QueryRow("SELECT count(*) FROM books WHERE deleted = 0").Scan(&bookCount); err != nil { |
| 1130 | return errors.Wrap(err, "counting local books") |
| 1131 | } |
| 1132 | if err := tx.QueryRow("SELECT count(*) FROM notes WHERE deleted = 0").Scan(¬eCount); err != nil { |
| 1133 | return errors.Wrap(err, "counting local notes") |
| 1134 | } |
| 1135 | |
| 1136 | // If a client has previously synced (lastMaxUSN > 0) but the server was never synced to (MaxUSN = 0), |
| 1137 | // and the client has undeleted books or notes, allow to upload all data to the server. |
| 1138 | // The client might have switched servers or the server might need to be restored for any reasons. |
| 1139 | if syncState.MaxUSN == 0 && lastMaxUSN > 0 && (bookCount > 0 || noteCount > 0) { |
| 1140 | log.Debug("empty server detected: server.MaxUSN=%d, local.MaxUSN=%d, books=%d, notes=%d\n", |
| 1141 | syncState.MaxUSN, lastMaxUSN, bookCount, noteCount) |
| 1142 | |
| 1143 | log.Warnf("The server is empty but you have local data. Maybe you switched servers?\n") |
| 1144 | log.Debug("server state: MaxUSN = 0 (empty)\n") |
| 1145 | log.Debug("local state: %d books, %d notes (MaxUSN = %d)\n", bookCount, noteCount, lastMaxUSN) |
| 1146 | |
| 1147 | confirmed, err := ui.Confirm(fmt.Sprintf("Upload %d books and %d notes to the server?", bookCount, noteCount), false) |
| 1148 | if err != nil { |
| 1149 | tx.Rollback() |
no test coverage detected