func (c *CmdShowNotifications) Run() error { _, err := c.G().UI.GetTerminalUI().Printf("Showing notifications:\n") if err != nil { return err } display := newNotificationDisplay(c.G()) protocols := []rpc.Protocol{ keybase1.NotifySessionProtocol(display), keybase1.NotifyUsersProtocol(display), } if err := RegisterProtocols(protocols); err != nil { return err } cli, err := GetNotifyCtlClient(c.G()) if err != nil { return err } if err := cli.SetNotifications(context.TODO(), keybase1.NotificationChannels{Session: true, Users: true}); err != nil { return err } _, err = c.G().UI.GetTerminalUI().Printf("waiting for notifications...\n") if err != nil { return err } for { time.Sleep(time.Second) } }
// OnConnect implements the ConnectionHandler interface. func (k *KeybaseDaemonRPC) OnConnect(ctx context.Context, conn *rpc.Connection, rawClient rpc.GenericClient, server *rpc.Server) error { protocols := []rpc.Protocol{ keybase1.LogUiProtocol(daemonLogUI{k.daemonLog}), keybase1.IdentifyUiProtocol(daemonIdentifyUI{k.daemonLog}), keybase1.NotifySessionProtocol(k), keybase1.NotifyUsersProtocol(k), } for _, p := range protocols { err := server.Register(p) if err != nil { if _, ok := err.(rpc.AlreadyRegisteredError); !ok { return err } } } // Using conn.GetClient() here would cause problematic // recursion. c := keybase1.NotifyCtlClient{Cli: rawClient} err := c.SetNotifications(ctx, keybase1.NotificationChannels{ Session: true, Users: true, }) if err != nil { return err } // Introduce ourselves. TODO: move this to SharedKeybaseConnection // somehow? configClient := keybase1.ConfigClient{Cli: rawClient} err = configClient.HelloIAm(ctx, keybase1.ClientDetails{ Pid: os.Getpid(), ClientType: keybase1.ClientType_KBFS, Argv: os.Args, Version: VersionString(), }) if err != nil { return err } return nil }
func TestSignupLogout(t *testing.T) { tc := setupTest(t, "signup") tc2 := cloneContext(tc) tc5 := cloneContext(tc) libkb.G.LocalDb = nil // Hack the various portions of the service that aren't // properly contextified. defer tc.Cleanup() stopCh := make(chan error) svc := service.NewService(tc.G, false) startCh := svc.GetStartChannel() go func() { err := svc.Run() if err != nil { t.Logf("Running the service produced an error: %v", err) } stopCh <- err }() userInfo := randomUser("sgnup") sui := signupUI{ info: userInfo, Contextified: libkb.NewContextified(tc2.G), } tc2.G.SetUI(&sui) signup := client.NewCmdSignupRunner(tc2.G) signup.SetTest() logout := client.NewCmdLogoutRunner(tc2.G) <-startCh nh := newNotifyHandler() // Launch the server that will listen for notifications on updates, such as logout launchServer := func(nh *notifyHandler) error { cli, xp, err := client.GetRPCClientWithContext(tc5.G) if err != nil { return err } srv := rpc.NewServer(xp, nil) if err = srv.Register(keybase1.NotifySessionProtocol(nh)); err != nil { return err } if err = srv.Register(keybase1.NotifyUsersProtocol(nh)); err != nil { return err } ncli := keybase1.NotifyCtlClient{Cli: cli} if err = ncli.SetNotifications(context.TODO(), keybase1.NotificationChannels{ Session: true, Users: true, }); err != nil { return err } return nil } // Actually launch it in the background go func() { err := launchServer(nh) if err != nil { nh.errCh <- err } }() if err := signup.Run(); err != nil { t.Fatal(err) } tc2.G.Log.Debug("Login State: %v", tc2.G.LoginState()) select { case err := <-nh.errCh: t.Fatalf("Error before notify: %v", err) case u := <-nh.loginCh: if u != userInfo.username { t.Fatalf("bad username in login notifcation: %q != %q", u, userInfo.username) } tc.G.Log.Debug("Got notification of login for %q", u) } btc := client.NewCmdBTCRunner(tc2.G) btc.SetAddress("1HUCBSJeHnkhzrVKVjaVmWg2QtZS1mdfaz") if err := btc.Run(); err != nil { t.Fatal(err) } // Now let's be sure that we get a notification back as we expect. select { case err := <-nh.errCh: t.Fatalf("Error before notify: %v", err) case uid := <-nh.userCh: tc.G.Log.Debug("Got notification from user changed handled (%s)", uid) if e := libkb.CheckUIDAgainstUsername(uid, userInfo.username); e != nil { t.Fatalf("Bad UID back: %s != %s (%s)", uid, userInfo.username, e) } } // Fire a logout if err := logout.Run(); err != nil { t.Fatal(err) } // Now let's be sure that we get a notification back as we expect. select { case err := <-nh.errCh: t.Fatalf("Error before notify: %v", err) case <-nh.logoutCh: tc.G.Log.Debug("Got notification from logout handler") } if err := client.CtlServiceStop(tc2.G); err != nil { t.Fatal(err) } // If the server failed, it's also an error if err := <-stopCh; err != nil { t.Fatal(err) } // Check that we only get one notification, not two select { case _, ok := <-nh.logoutCh: if ok { t.Fatal("Received an extra logout notification!") } default: } }