Connecting

Once you've created a connector, it's time to connect to a server!

As all connector setup was done via the Connector setup, this is now just down to dealing with whether the connection process actually worked or not.

  • For embedded connectors in the reference implementation, connection will always succeed, as long as the client and server are from the same library version (See below for issues involving compatibility). Hopefully, that is a situation that will rarely if ever happen.
  • For external connectors, connections can fail due to usual connection issues (wrong address, server not up, network not on, etc...). There is also a chance that the client and server could have a version mismatch. We'll cover this in the next section.
  • Rust
  • C#
  • Javascript
use tokio::io::{self, BufReader, AsyncBufReadExt};
use buttplug::{
  client::{ButtplugClient, ButtplugClientError},
  connector::ButtplugInProcessClientConnector,
  core::errors::ButtplugError,
};

async fn wait_for_input() {
  BufReader::new(io::stdin()).lines().next_line().await.unwrap();
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
  // After you've created a connector, the connection looks the same no
  // matter what, though the errors thrown may be different.
  let connector = ButtplugInProcessClientConnector::default();

  // If you'd like to try a remote network connection, comment the
  // connector line above and uncomment the one below. Note that you'll
  // need to turn off SSL on whatever server you're using.

  // let connector: ButtplugRemoteConnector<_, ButtplugClientJSONSerializer, _, _> = ButtplugRemoteConnector::new(
  //     ButtplugWebsocketClientTransport::new_insecure_connector("ws://localhost:12345/buttplug")
  // );

  // Now we connect. If anything goes wrong here, we'll get an Err with either
  //
  // - A ButtplugClientConnectionError if there's a problem with
  //   the Connector, like the network address being wrong, server not
  //   being up, etc.
  // - A ButtplugHandshakeError if there is a client/server version
  //   mismatch.
  let client = ButtplugClient::new("Example Client");
  if let Err(e) = client.connect(connector).await {
    match e {
      ButtplugClientError::ButtplugConnectorError(error) => {
        // If our connection failed, because the server wasn't turned on,
        // SSL/TLS wasn't turned off, etc, we'll just print and exit
        // here.
        println!("Can't connect, exiting! Message: {}", error);
        wait_for_input().await;
        return Ok(());
      }
      ButtplugClientError::ButtplugError(error) => match error {
        ButtplugError::ButtplugHandshakeError(error) => {
          // This means our client is newer than our server, and we need to
          // upgrade the server we're connecting to.
          println!("Handshake issue, exiting! Message: {}", error);
          wait_for_input().await;
          return Ok(());
        }
        error => {
          println!("Unexpected error type! {}", error);
          wait_for_input().await;
          return Ok(());
        }
      }
    }
  };

  // We're connected, yay!
  println!("Connected! Check Server for Client Name.");

  wait_for_input().await;

  // And now we disconnect as usual
  client.disconnect().await?;

  Ok(())
}

Client/Server Compatibility

To keep up with new hardware capabilities and the needs of users, the Buttplug protocol spec is versioned. Any time any message changes, the version number of the spec is incremented by 1. When the Connect function is called from a reference client, a "handshake" process occurs where the Client and Server trade their spec version with each other.

Maintaining backward compatibility with applications that may be abandoned (something that is rare in sex software) is a core tenant of Buttplug. Buttplug reference servers try to support all versions of the spec. Older clients should always be able to connect to newer servers.

If a client is running a newer version of the spec than the server, a connection error will be thrown, because otherwise the client can send messages that the server doesn't know what to do with. In this case, it is assumed that there will be a new version of the server library or software available that the client can upgrade to.

What to Expect on Successful Connect

Once you're connected, you really don't need to think about whether you're using an embedded or remote connector anymore. In most cases, connectors are only used for the initial connection setup, then you can pretty much forget about them after that. Everything will look exactly the same across all connector types from here on out.

So now that you know how to get a Buttplug session running, you're ready to enumerate and control devices!