Michael Shipper
and 1 contributors


AnyEvent::SparkBot - Cisco Spark WebSocket Client for the AnyEvent Loop


  use Modern::Perl;
  use Data::Dumper;
  use AnyEvent::SparkBot;
  use AnyEvent::Loop;

  our $obj=new AnyEvent::SparkBot(token=>$ENV{SPARK_TOKEN},on_message=>\&cb);

  $obj->que_getWsUrl(sub { 
    my ($agent,$id,$result)=@_;

    # start here if we got a valid connection
    return $obj->start_connection if $result;

  sub cb {
    my ($sb,$result,$eventType,$verb,$json)=@_;
    return unless $eventType eq 'conversation.activity' and $verb eq 'post';

    # Data::Result Object is False when combination of EvenType and Verb are unsupprted
    if($result) {
      my $data=$result->get_data;
      my $response={
        text=>"ya.. ya ya.. I'm on it!"
      # Proxy our lookup in a Retry-After ( prevents a lot of errors )
      $obj->run_lookup('que_createMessage',(sub {},$response);
    } else {
      print "Error: $result\n";


Connects to cisco spark via a websocket. By itself this class only provides connectivty to Spark, the on_message callback is used to handle events that come in. By default No hanlder is provided.

Moo Role(s)

This module uses the following Moo role(s)


OO Arguments and accessors

Required Argument(s)

  token: The token used to authenticate the bot
  on_message: code ref used to handle incomming messages

Optional Arguments

  reconnect: default is true
  logger: null(default) or an instance of log4perl::logger
  lastConn: location to the last connection file
    # it may be a very good idea to set this value
    # default: /tmp/sparkBotLastConnect.json
  defaultUrl: https://wdm-a.wbx2.com/wdm/api/v1/devices
    # this is where we authenticate and pull the websocket url from
  deviceDesc: JSON hash, representing the client description
  agent: an instance of AnyEvent::HTTP::MultiGet
  retryTimeout: default 10, sets how long to wait afer getting a 429 error
  retryCount: default 1, sets how many retries when we get a 429 error

Timout and retry values:

  pingEvery: 60 # used to check how often we run a ping
    # pings only happen if no inbound request has come in for 
    # the interval
  pingWait: 10 
    # how long to wait for a ping response
  reconnect_sleep: 10
    # how long to wait before we try to reconnect

Objects set at runtime:

  lastConn: sets the location of the last connection file
  ping: sets an object that will wake up and do something
  lastPing: contains the last ping string value
  connection: contains the current websocket connection if any
  spark: Instance of AnyEvent::HTTP::Spark
  currentUser: Hash ref representing the current bot user

OO Methods

  • my $result=$self->new_true({qw( some data )});

    Returns a new true Data::Result object.

  • my $result=$self->new_false("why this failed")

    Returns a new false Data::Result object

  • my $self->start_connection()

    Starts the bot up.

  • $self->handle_message($connection,$message)

    Handles incoming messages

  • $self->run_lookup('que_method',$cb,@args);

    Proxies the internal $self->spark object in a method that honnors the Retry-After interval.


      $self->run_lookup('que_getMe',sub {
        my ($sb,$id,$result,$request,$response)=@_;
        return print Dumper($result->get_data) if $result;
        warn "Failed to getMe, error was; $result";
  • $self->handle_reconnect()

    Handles reconnecting to spark

  • $self->setPing()

    Sets the next ping object

  • $self->setPingWait()

    This method is called by ping, sets a timeout to wait for the response.

  • my $result=$self->getLastConn()

    Fetches the last connection info

    Returns a Data::Result Object, when true it contains the hash, when false it contains why it failed.

  • my $result=$self->saveLastConn($ref)

    Saves the last conenction, returns a Data::Result Object

    $ref is assumed to be the data strucutre intended to be serialzied into json

  • my $job_id=$self->que_deleteLastUrl($cb)

    Returns a Data::Result Object, when true it contains the url that was deleted, when false it contains why it failed.

  • my $job_id=$self->que_getWsUrl($cb)

    Gets the WebSocket URL

    Returns a Data::Result Object: When true it contains the url. When false it contains why it failed.

  • $self->log_delete_call($id,$result)

    Call back to handle logging clean up of previous session


Michael Shipper <AKALINUX@CPAN.ORG>