Skip to content

Commit

Permalink
client: track and warn unsupported GC version
Browse files Browse the repository at this point in the history
This adds a new Version field in GC definitions and warns the user when
a GC list with an unsupported version is received. This will be used in
the future to warn about upgraded GCs.

The current GC version is assumed to be version 0.

A function is added in the clients to resend the GC list, to fix issues
with the list getting out of sync in members.
  • Loading branch information
miki authored and miki-totefu committed Feb 23, 2023
1 parent cb18ccb commit dc63daf
Show file tree
Hide file tree
Showing 17 changed files with 324 additions and 6 deletions.
10 changes: 10 additions & 0 deletions brclient/appstate.go
Expand Up @@ -2339,6 +2339,16 @@ func newAppState(sendMsg func(tea.Msg), lndLogLines *sloglinesbuffer.Buffer,
})
}))

ntfns.Register(client.OnGCVersionWarning(func(user *client.RemoteUser, gc rpc.RMGroupList, minVersion, maxVersion uint8) {
as.manyDiagMsgsCb(func(pf printf) {
gcAlias, _ := as.c.GetGCAlias(gc.ID)
msg := fmt.Sprintf("Received GC list for GC %q (%s) with "+
"unsupported GC version %d", gcAlias, gc.ID, gc.Version)
pf(as.styles.err.Render(msg))
pf("Please update the client software to interact in updated GCs.")
})
}))

// Initialize client config.
cfg := client.Config{
DB: db,
Expand Down
44 changes: 44 additions & 0 deletions brclient/commands.go
Expand Up @@ -932,6 +932,50 @@ var gcCommands = []tuicmd{
gcWin.newInternalMsg(fmt.Sprintf("Renamed GC to %s", newAlias))
gcWin.alias = newAlias // FIXME: this is racing.
as.repaintIfActive(gcWin)
return nil
},
}, {
cmd: "resendlist",
usage: "<gc> [<user>]",
descr: "Resends the GC definition to the specified user or all users",
handler: func(args []string, as *appState) error {
if len(args) < 1 {
return usageError{msg: "GC cannot be empty"}
}

gcID, err := as.c.GCIDByName(args[0])
if err != nil {
return err
}

var uid *clientintf.UserID
if len(args) > 1 {
user, err := as.c.UIDByNick(args[1])
if err != nil {
return err
}
uid = &user
}

go func() {
gcWin := as.findOrNewGCWindow(gcID)
var msg *chatMsg
if uid == nil {
msg = gcWin.newInternalMsg("Resending GC list to all GC members")
} else {
nick, _ := as.c.UserNick(*uid)
msg = gcWin.newInternalMsg(fmt.Sprintf("Resending GC list to %q", nick))
}
as.repaintIfActive(gcWin)
err := as.c.ResendGCList(gcID, uid)
if err != nil {
gcWin.newHelpMsg("Unable to resent GC List: %v", err)
} else {
gcWin.setMsgSent(msg)
}
as.repaintIfActive(gcWin)
}()

return nil
},
},
Expand Down
25 changes: 25 additions & 0 deletions bruig/flutterui/bruig/lib/components/active_chat.dart
Expand Up @@ -879,6 +879,27 @@ class FileDownloadedEventW extends StatelessWidget {
}
}

class GCVersionWarnW extends StatelessWidget {
final GCVersionWarn event;
const GCVersionWarnW(this.event, {Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var bgColor = Colors.red[600];
var textColor = Colors.white;
return Container(
padding: const EdgeInsets.only(left: 41, top: 5, bottom: 5),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: bgColor,
borderRadius: const BorderRadius.all(Radius.circular(5))),
child: SelectableText(
"Received GC definitions with unsupported version ${event.version}. Please update the software to interact in this GC.",
style: TextStyle(fontSize: 9, color: textColor)));
}
}

class Event extends StatelessWidget {
final ChatEventModel event;
final ChatModel chat;
Expand Down Expand Up @@ -936,6 +957,10 @@ class Event extends StatelessWidget {
return PostSubscriptionEventW(event.event as PostSubscriptionResult);
}

if (event.event is GCVersionWarn) {
return GCVersionWarnW(event.event as GCVersionWarn);
}

var theme = Theme.of(context);
var textColor = theme.focusColor;
return Container(
Expand Down
2 changes: 2 additions & 0 deletions bruig/flutterui/bruig/lib/models/client.dart
Expand Up @@ -215,6 +215,8 @@ class ChatModel extends ChangeNotifier {
}
})();
}

Future<void> resendGCList() async => await Golib.resendGCList(id);
}

class ClientModel extends ChangeNotifier {
Expand Down
14 changes: 14 additions & 0 deletions bruig/flutterui/bruig/lib/models/menus.dart
Expand Up @@ -203,5 +203,19 @@ List<ChatMenuItem> buildGCMenu(ChatModel chat) {
"Rename GC",
(context, chats) => showRenameModalBottom(context, chats.active!),
),
ChatMenuItem(
"Resend GC List",
(context, chats) async {
var msg = SynthChatEvent("Resending GC list to members");
msg.state = SCE_sending;
chat.append(ChatEventModel(msg, null));
try {
await chat.resendGCList();
msg.state = SCE_sent;
} catch (exception) {
msg.error = Exception("Unable to resend GC list: $exception");
}
},
),
];
}
24 changes: 24 additions & 0 deletions bruig/flutterui/plugin/lib/definitions.dart
Expand Up @@ -1336,6 +1336,25 @@ class InvoiceGenFailed {
_$InvoiceGenFailedFromJson(json);
}

@JsonSerializable()
class GCVersionWarn extends ChatEvent {
final String id;
@JsonKey(defaultValue: "")
final String alias;
final int version;
@JsonKey(name: "min_version")
final int minVersion;
@JsonKey(name: "max_version")
final int maxVersion;

GCVersionWarn(
this.id, this.alias, this.version, this.minVersion, this.maxVersion)
: super(id,
"Received GC list with unsupported $version (min $minVersion, max $maxVersion). Please update the client software.");
factory GCVersionWarn.fromJson(Map<String, dynamic> json) =>
_$GCVersionWarnFromJson(json);
}

mixin NtfStreams {
StreamController<RemoteUser> ntfAcceptedInvites =
StreamController<RemoteUser>();
Expand Down Expand Up @@ -1871,6 +1890,9 @@ abstract class PluginPlatform {

Future<RatchetDebugInfo> userRatchetInfo(String uid) async =>
RatchetDebugInfo.fromJson(await asyncCall(CTUserRatchetDebugInfo, uid));

Future<void> resendGCList(String gcid) async =>
await asyncCall(CTResendGCList, gcid);
}

const int CTUnknown = 0x00;
Expand Down Expand Up @@ -1964,6 +1986,7 @@ const int CTLNRestoreMultiSCB = 0x63;
const int CTLNSaveMultiSCB = 0x64;
const int CTListUsersLastMsgTimes = 0x65;
const int CTUserRatchetDebugInfo = 0x66;
const int CTResendGCList = 0x67;

const int notificationsStartID = 0x1000;

Expand Down Expand Up @@ -1996,3 +2019,4 @@ const int NTUserPostsList = 0x101a;
const int NTUserContentList = 0x101b;
const int NTPostSubscriptionResult = 0x101c;
const int NTInvoiceGenFailed = 0x101d;
const int NTGCVersionWarn = 0x101e;
18 changes: 18 additions & 0 deletions bruig/flutterui/plugin/lib/definitions.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions bruig/flutterui/plugin/lib/desktop.dart
Expand Up @@ -271,6 +271,11 @@ mixin BaseDesktopPlatform on NtfStreams {
NTInvoiceGenFailed, InvoiceGenFailed.fromJson(payload)));
break;

case NTGCVersionWarn:
var event = GCVersionWarn.fromJson(payload);
ntfChatEvents.add(event);
break;

default:
print("Received unknown notification ${cmd.toRadixString(16)}");
}
Expand Down
24 changes: 20 additions & 4 deletions bruig/golib/command_handlers.go
Expand Up @@ -189,6 +189,18 @@ func handleInitClient(handle uint32, args InitClient) error {
notify(NTInvoiceGenFailed, ntf, nil)
}))

ntfns.Register(client.OnGCVersionWarning(func(user *client.RemoteUser, gc rpc.RMGroupList, minVersion, maxVersion uint8) {
alias, _ := c.GetGCAlias(gc.ID)
warn := GCVersionWarn{
ID: gc.ID,
Alias: alias,
Version: gc.Version,
MinVersion: minVersion,
MaxVersion: maxVersion,
}
notify(NTGCVersionWarn, warn, nil)
}))

cfg := client.Config{
DB: db,
Dialer: clientintf.NetDialer(args.ServerAddr, logBknd.logger("CONN")),
Expand Down Expand Up @@ -1252,15 +1264,19 @@ func handleClientCmd(cc *clientCtx, cmd *cmd) (interface{}, error) {

case CTUserRatchetDebugInfo:
var args clientintf.UserID
if err := cmd.decode(&args); err != nil {
return nil, err
}

ru, err := c.UserByID(args)
if err != nil {
return nil, err
}
return ru.RatchetDebugInfo(), nil

case CTResendGCList:
var args zkidentity.ShortID
if err := cmd.decode(&args); err != nil {
return nil, err
}

return nil, c.ResendGCList(args, nil)
}

return nil, nil
Expand Down
2 changes: 2 additions & 0 deletions bruig/golib/commands.go
Expand Up @@ -100,6 +100,7 @@ const (
CTLNSaveMultiSCB = 0x64
CTListUsersLastMsgTimes = 0x65
CTUserRatchetDebugInfo = 0x66
CTResendGCList = 0x67

NTInviteReceived = 0x1001
NTInviteAccepted = 0x1002
Expand Down Expand Up @@ -130,6 +131,7 @@ const (
NTUserContentList = 0x101b
NTRemoteSubChanged = 0x101c
NTInvoiceGenFailed = 0x101d
NTGCVersionWarn = 0x101e
)

type cmd struct {
Expand Down
8 changes: 8 additions & 0 deletions bruig/golib/definitions.go
Expand Up @@ -267,3 +267,11 @@ type InvoiceGenFailed struct {
DcrAmount float64 `json:"dcr_amount"`
Err string `json:"err"`
}

type GCVersionWarn struct {
ID zkidentity.ShortID `json:"id"`
Alias string `json:"alias"`
Version uint8 `json:"version"`
MinVersion uint8 `json:"min_version"`
MaxVersion uint8 `json:"max_version"`
}
10 changes: 8 additions & 2 deletions client/client.go
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/companyzero/bisonrelay/client/clientintf"
"github.com/companyzero/bisonrelay/client/internal/gcmcacher"
"github.com/companyzero/bisonrelay/client/internal/lowlevel"
"github.com/companyzero/bisonrelay/client/internal/singlesetmap"
"github.com/companyzero/bisonrelay/client/timestats"
"github.com/companyzero/bisonrelay/rpc"
"github.com/companyzero/bisonrelay/zkidentity"
Expand Down Expand Up @@ -222,6 +223,10 @@ type Client struct {
// gcAliasMap maps a local gc name to a global gc id.
gcAliasMtx sync.Mutex
gcAliasMap map[string]zkidentity.ShortID

// gcWarnedVersions tracks GCs for which the warning about an
// incompatible version has been issued.
gcWarnedVersions *singlesetmap.Map[zkidentity.ShortID]
}

// New creates a new CR client with the given config.
Expand Down Expand Up @@ -296,8 +301,9 @@ func New(cfg Config) (*Client, error) {
rul: newRemoteUserList(),
ntfns: ntfns,

abLoaded: make(chan struct{}),
newUsersChan: make(chan *RemoteUser),
abLoaded: make(chan struct{}),
newUsersChan: make(chan *RemoteUser),
gcWarnedVersions: &singlesetmap.Map[zkidentity.ShortID]{},
}

// Use the GC message cacher to collect gc messages for a few seconds
Expand Down

0 comments on commit dc63daf

Please sign in to comment.