public async Task ConnectAsync(RobotConnectionInfo connectionInfo) { if (Client == null) { //create channel var ssl = new SslCredentials(connectionInfo.Certificate); var interceptor = new AsyncAuthInterceptor((context, metadata) => { metadata.Add("authorization", $"Bearer {connectionInfo.Token}"); return(Task.CompletedTask); }); var cred = ChannelCredentials.Create(ssl, CallCredentials.FromInterceptor(interceptor)); _channel = new Channel(connectionInfo.IpAddress, 443, cred, new ChannelOption[] { new ChannelOption("grpc.ssl_target_name_override", connectionInfo.RobotName) }); //connect to client try { await _channel.ConnectAsync(DateTime.UtcNow.AddSeconds(10)); } catch (TaskCanceledException ex) { throw new VectorConnectionException("could not connect to Vector. insure IP address is correct and that Vector is turned on", ex); } //create client Client = new ExternalInterfaceClient(_channel); IsConnected = true; } }
public void Save(RobotConnectionInfo connection) { var filePath = GetFilePath(connection.RobotName); File.WriteAllText(filePath, JsonConvert.SerializeObject(connection)); }
/// <summary> /// Required for first time use. Used to grant this device access to a Vector robot. The robot must be joined to the wifi network using the Vector Companion App before running this. /// </summary> /// <param name="robotName">Find your robot name (ex. Vector-A1B2) by placing Vector on the charger and double-clicking Vector's backpack button.</param> /// <param name="ipAddress">Find your robot ip address (ex. 192.168.42.42) by placing Vector on the charger, double-clicking Vector's backpack button, then raising and lowering his arms.If you see XX.XX.XX.XX on his face, reconnect Vector to your WiFi using the Vector Companion App.</param> /// <param name="serialNumber">Please find your robot serial number (ex. 00e20100) located on the underside of Vector, or accessible from Vector's debug screen.</param> /// <param name="userName">Enter your email. Make sure to use the same account that was used to set up your Vector through the Companion app.</param> /// <param name="password">Enter your password. Make sure to use the same account that was used to set up your Vector through the Companion app.</param> /// <returns>used to connect to the robot</returns> public static async Task <RobotConnectionInfo> GrantAsync(string robotName, string ipAddress, string serialNumber, string userName, string password) { var result = new RobotConnectionInfo(); robotName = FormatRobotName(robotName); serialNumber = FormatSerialNumber(serialNumber); //get the certificate var client = new HttpClient(); var response = await client.GetAsync(@"https://session-certs.token.global.anki-services.com/vic/" + serialNumber); if (!response.IsSuccessStatusCode) { throw new VectorAuthorizationException("invalid serial number"); } result.Certificate = await response.Content.ReadAsStringAsync(); //validate robot name var cert = new X509Certificate(Encoding.ASCII.GetBytes(result.Certificate)); var certSubject = cert.Subject.Split(',').Select(i => new KeyValuePair <string, string>(i.Split('=')[0].Trim(), i.Split('=')[1].Trim())); var commonName = certSubject.First(i => i.Key == "CN").Value; if (commonName != robotName) { throw new VectorAuthorizationException($"The name of the certificate ({commonName}) does not match the name provided robotName ({robotName}) Please verify the name, and try again."); } result.RobotName = robotName; //get session token response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Post, @"https://accounts.api.anki.com/1/sessions") { Headers = { { "User-Agent", "Vector-sdk/0.5.1" }, { "Anki-App-Key", AnkiAppKey } }, Content = new FormUrlEncodedContent(new Dictionary <string, string>() { { "username", userName }, { "password", password } }), }); if (!response.IsSuccessStatusCode) { throw new VectorAuthorizationException("invalid userName and password"); } var userSession = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()) as JObject; var sessionToken = userSession["session"]["session_token"].Value <string>(); //have robot authenticate with session token and retreive the robots client token var ssl = new SslCredentials(result.Certificate); var channel = new Channel(ipAddress, 443, ssl, new ChannelOption[] { new ChannelOption("grpc.ssl_target_name_override", robotName) }); try { await channel.ConnectAsync(DateTime.UtcNow.AddSeconds(10)); } catch (TaskCanceledException ex) { throw new VectorAuthorizationException("Timeout. Could not connect to vector. insure IP address is correct", ex); } var robotClient = new ExternalInterfaceClient(channel); var hostname = System.Net.Dns.GetHostName(); var authRequest = new UserAuthenticationRequest() { ClientName = ByteString.CopyFromUtf8(hostname), UserSessionId = ByteString.CopyFromUtf8(sessionToken) }; var authResult = await robotClient.UserAuthenticationAsync(authRequest); if (authResult.Code == UserAuthenticationResponse.Types.Code.Unauthorized) { throw new VectorAuthorizationException("unauthorized"); } result.Token = authResult.ClientTokenGuid.ToStringUtf8(); result.IpAddress = ipAddress; await channel.ShutdownAsync(); return(result); }