cli: Start implementing more RPC logic
This commit is contained in:
		
							parent
							
								
									a52de9078c
								
							
						
					
					
						commit
						6cee5d7b45
					
				
							
								
								
									
										69
									
								
								cli/cli.go
								
								
								
								
							
							
						
						
									
										69
									
								
								cli/cli.go
								
								
								
								
							|  | @ -6,7 +6,6 @@ import ( | |||
| 	"golang.org/x/net/context" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"gopkg.in/readline.v1" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"strings" | ||||
| ) | ||||
|  | @ -15,35 +14,6 @@ const ( | |||
| 	defaultAddress = "127.0.0.1:58281" | ||||
| ) | ||||
| 
 | ||||
| type Client struct { | ||||
| 	Backend rpc.RicochetCoreClient | ||||
| 	Input   *readline.Instance | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Initialize() error { | ||||
| 	stream, err := c.Backend.MonitorNetwork(context.Background(), &rpc.MonitorNetworkRequest{}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			resp, err := stream.Recv() | ||||
| 			if err == io.EOF { | ||||
| 				log.Printf("stream eof") | ||||
| 				break | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				log.Printf("stream error: %v", err) | ||||
| 				break | ||||
| 			} | ||||
| 			log.Printf("stream says: %v", resp) | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	conn, err := grpc.Dial(defaultAddress, grpc.WithInsecure()) | ||||
| 	if err != nil { | ||||
|  | @ -80,20 +50,10 @@ func main() { | |||
| 		switch words[0] { | ||||
| 		case "clear": | ||||
| 			readline.ClearScreen(readline.Stdout) | ||||
| 		case "status": | ||||
| 			r, err := c.Backend.GetServerStatus(context.Background(), &rpc.ServerStatusRequest{ | ||||
| 				RpcVersion: 1, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				log.Fatalf("could not get status: %v", err) | ||||
| 			} | ||||
| 			log.Printf("get status result: %v", r) | ||||
| 
 | ||||
| 			identity, err := c.Backend.GetIdentity(context.Background(), &rpc.IdentityRequest{}) | ||||
| 			if err != nil { | ||||
| 				log.Fatalf("could not get identity: %v", err) | ||||
| 			} | ||||
| 			log.Printf("identity: %v", identity) | ||||
| 		case "status": | ||||
| 			log.Printf("server: %v", c.ServerStatus) | ||||
| 			log.Printf("identity: %v", c.Identity) | ||||
| 
 | ||||
| 		case "connect": | ||||
| 			status, err := c.Backend.StartNetwork(context.Background(), &rpc.StartNetworkRequest{}) | ||||
|  | @ -102,6 +62,7 @@ func main() { | |||
| 			} else { | ||||
| 				log.Printf("network started: %v", status) | ||||
| 			} | ||||
| 
 | ||||
| 		case "disconnect": | ||||
| 			status, err := c.Backend.StopNetwork(context.Background(), &rpc.StopNetworkRequest{}) | ||||
| 			if err != nil { | ||||
|  | @ -109,27 +70,17 @@ func main() { | |||
| 			} else { | ||||
| 				log.Printf("network stopped: %v", status) | ||||
| 			} | ||||
| 
 | ||||
| 		case "contacts": | ||||
| 			stream, err := c.Backend.MonitorContacts(context.Background(), &rpc.MonitorContactsRequest{}) | ||||
| 			if err != nil { | ||||
| 				log.Printf("contacts error: %v", err) | ||||
| 			} else { | ||||
| 				for { | ||||
| 					event, err := stream.Recv() | ||||
| 					if err == io.EOF { | ||||
| 						break | ||||
| 					} | ||||
| 					if err != nil { | ||||
| 						log.Printf("contacts error: %v", err) | ||||
| 						break | ||||
| 					} | ||||
| 					log.Printf("contact event: %v", event) | ||||
| 				} | ||||
| 			for _, contact := range c.Contacts { | ||||
| 				log.Printf("  %s (%s)", contact.Nickname, contact.Status.String()) | ||||
| 			} | ||||
| 
 | ||||
| 		case "help": | ||||
| 			fallthrough | ||||
| 
 | ||||
| 		default: | ||||
| 			fmt.Println("Commands: clear, status, connect, disconnect, help") | ||||
| 			fmt.Println("Commands: clear, status, connect, disconnect, contacts, help") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,179 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/special/notricochet/rpc" | ||||
| 	"golang.org/x/net/context" | ||||
| 	"gopkg.in/readline.v1" | ||||
| 	"log" | ||||
| ) | ||||
| 
 | ||||
| type Client struct { | ||||
| 	Backend ricochet.RicochetCoreClient | ||||
| 	Input   *readline.Instance | ||||
| 
 | ||||
| 	ServerStatus ricochet.ServerStatusReply | ||||
| 	Identity     ricochet.Identity | ||||
| 
 | ||||
| 	// XXX threadsafety
 | ||||
| 	NetworkStatus ricochet.NetworkStatus | ||||
| 	Contacts      []*ricochet.Contact | ||||
| } | ||||
| 
 | ||||
| // XXX need to handle backend connection loss/reconnection..
 | ||||
| func (c *Client) Initialize() error { | ||||
| 	// Query server status and version
 | ||||
| 	status, err := c.Backend.GetServerStatus(context.Background(), &ricochet.ServerStatusRequest{ | ||||
| 		RpcVersion: 1, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	c.ServerStatus = *status | ||||
| 	if status.RpcVersion != 1 { | ||||
| 		return fmt.Errorf("Unsupported backend RPC version %d", status.RpcVersion) | ||||
| 	} | ||||
| 
 | ||||
| 	// Query identity
 | ||||
| 	identity, err := c.Backend.GetIdentity(context.Background(), &ricochet.IdentityRequest{}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	c.Identity = *identity | ||||
| 
 | ||||
| 	// Spawn routines to query and monitor state changes
 | ||||
| 	go c.monitorNetwork() | ||||
| 	go c.monitorContacts() | ||||
| 
 | ||||
| 	// XXX block until populated/initialized?
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *Client) monitorNetwork() { | ||||
| 	stream, err := c.Backend.MonitorNetwork(context.Background(), &ricochet.MonitorNetworkRequest{}) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Initializing network status monitor failed: %v", err) | ||||
| 		// XXX handle
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		status, err := stream.Recv() | ||||
| 		if err != nil { | ||||
| 			log.Printf("Network status monitor error: %v", err) | ||||
| 			// XXX handle
 | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		log.Printf("Network status changed: %v", status) | ||||
| 		c.NetworkStatus = *status | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *Client) monitorContacts() { | ||||
| 	stream, err := c.Backend.MonitorContacts(context.Background(), &ricochet.MonitorContactsRequest{}) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Initializing contact status monitor failed: %v", err) | ||||
| 		// XXX handle
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Populate initial contacts list
 | ||||
| 	for { | ||||
| 		event, err := stream.Recv() | ||||
| 		if err != nil { | ||||
| 			log.Printf("Contact populate error: %v", err) | ||||
| 			// XXX handle
 | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		if event.Type != ricochet.ContactEvent_POPULATE { | ||||
| 			log.Printf("Ignoring unexpected contact event during populate: %v", event) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Populate is terminated by a nil subject
 | ||||
| 		if event.Subject == nil { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		if contact := event.GetContact(); contact != nil { | ||||
| 			c.Contacts = append(c.Contacts, contact) | ||||
| 		} else if request := event.GetRequest(); request != nil { | ||||
| 			// XXX handle requests
 | ||||
| 			log.Printf("XXX contact requests not supported") | ||||
| 		} else { | ||||
| 			log.Printf("XXX invalid event") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	log.Printf("Loaded %d contacts", len(c.Contacts)) | ||||
| 
 | ||||
| 	for { | ||||
| 		event, err := stream.Recv() | ||||
| 		if err != nil { | ||||
| 			log.Printf("Contact status monitor error: %v", err) | ||||
| 			// XXX handle
 | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		contact := event.GetContact() | ||||
| 
 | ||||
| 		switch event.Type { | ||||
| 		case ricochet.ContactEvent_ADD: | ||||
| 			if contact == nil { | ||||
| 				log.Printf("Ignoring contact add event with null contact") | ||||
| 				continue | ||||
| 			} | ||||
| 			c.Contacts = append(c.Contacts, contact) | ||||
| 			log.Printf("new contact: %v", contact) | ||||
| 
 | ||||
| 		case ricochet.ContactEvent_UPDATE: | ||||
| 			if contact == nil { | ||||
| 				log.Printf("Ignoring contact update event with null contact") | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			var found bool | ||||
| 			for i, match := range c.Contacts { | ||||
| 				if match.Id == contact.Id && match.Address == contact.Address { | ||||
| 					contacts := append(c.Contacts[0:i], contact) | ||||
| 					contacts = append(contacts, c.Contacts[i+1:]...) | ||||
| 					c.Contacts = contacts | ||||
| 					found = true | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if !found { | ||||
| 				log.Printf("Ignoring contact update event for unknown contact: %v", contact) | ||||
| 			} else { | ||||
| 				log.Printf("updated contact: %v", contact) | ||||
| 			} | ||||
| 
 | ||||
| 		case ricochet.ContactEvent_DELETE: | ||||
| 			if contact == nil { | ||||
| 				log.Printf("Ignoring contact delete event with null contact") | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			var found bool | ||||
| 			for i, match := range c.Contacts { | ||||
| 				if match.Id == contact.Id && match.Address == contact.Address { | ||||
| 					c.Contacts = append(c.Contacts[0:i], c.Contacts[i+1:]...) | ||||
| 					found = true | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if !found { | ||||
| 				log.Printf("Ignoring contact delete event for unknown contact: %v", contact) | ||||
| 			} else { | ||||
| 				log.Printf("deleted contact: %v", contact) | ||||
| 			} | ||||
| 
 | ||||
| 		default: | ||||
| 			log.Printf("Ignoring unknown contact event: %v", event) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue