示例#1
0
void trigger(void *cvoid, 
             zctx_t * context, 
             void * control) {
  triggerconfig_t * c = (triggerconfig_t*) cvoid;
  //set up msgpack stuff
  zclock_log("watch_port started!");
  msgpack_zone mempool;
  msgpack_zone_init(&mempool, 2048);

  // TODO
  char * user_id = "17"; 
  // TODO get broker in somehow
  char * broker = "tcp://au.ninjablocks.com:5773";

  mdcli_t * client = mdcli_new(broker, 1); //VERBOSE

  triggermemory_t trigger_memory;
  msgpack_object * addins_obj = parse_msgpack(&mempool, c->addins);

  if(!parse_addins(addins_obj, &trigger_memory)) {
    //bad message
    zclock_log("bad trigger definition");
    msgpack_object_print(stdout, *addins_obj);
    send_sync("bad trigger", control);
    return;
  }
  zclock_log("Creating trigger: target %s, rule_id %s, name %s", 
             c->target_worker, c->rule_id, c->trigger_name);
  dump_trigger(&trigger_memory);
  triggerfunction trigger_func;
  if(!(trigger_func = find_trigger(c->channel, c->trigger_name))) {

    zclock_log("no trigger found for channel %s, trigger %s",
               c->channel, c->trigger_name);
    send_sync("no such trigger", control);
    return;
  }

  void * line = zsocket_new(context, ZMQ_SUB);


  // what line are we on?
  // this comes in the addins. 
  char * linesocket = to_linesocket(trigger_memory.line_id);
  zclock_log("trigger is connecting to listen on %s", linesocket);
  zsocket_connect(line, linesocket);

  zsockopt_set_unsubscribe(line, "");
  zsockopt_set_subscribe(line, "VALUE");
  recv_sync("ping", control);
  send_sync("pong", control);
  
  zmq_pollitem_t items [] = {
    { line, 0, ZMQ_POLLIN, 0 },
    { control, 0, ZMQ_POLLIN, 0 }
  };
  while(1) {
    // listen on control and line
    zmq_poll (items, 2, -1);
    if (items[1].revents & ZMQ_POLLIN) {
      zclock_log("rule %s received message on control pipe", c->rule_id);
      // control message
      // really only expecting DESTROY
      zmsg_t * msg = zmsg_recv(control);
      char * str = zmsg_popstr(msg);
      zmsg_destroy(&msg);
      
      if (strcmp("Destroy", str) == 0) {
        zclock_log("rule %s will quit on request", c->rule_id);
        free(str);
        send_sync("ok", control);
        zclock_log("rule %s quitting on request", c->rule_id);
        break;
      } else  {
        zclock_log("unexpected command %s for rule %s", str, c->rule_id);
        free(str);
        send_sync("ok", control);
      }
    }

    if (items[0].revents & ZMQ_POLLIN) {
      // serial update
      zmsg_t * msg = zmsg_recv(line);
      zframe_t * cmd = zmsg_pop(msg);
      if(zframe_streq(cmd, "CHANNEL_CHANGE")) {
        // TODO
        // must have been dormant to have gotten this
        char * new_channel = zmsg_popstr(msg);

        if(strcmp(c->channel, new_channel) == 0) {
        // oh, happy day! We're relevant again.
        // reactivate and start looking at reset levels.
          zclock_log("line %d: changed channel from %s to %s: trigger coming back to life", trigger_memory.line_id, c->channel, new_channel);
          zsockopt_set_subscribe(line, "VALUE");
          zsockopt_set_unsubscribe(line, "CHANNEL_CHANGE");
        }
        free(new_channel);
      } else if (zframe_streq(cmd, "VALUE")) {
        zframe_t * vframe = zmsg_pop(msg);
        int value;
        memcpy(&value, zframe_data(vframe), sizeof(int));
        char * update_channel = zmsg_popstr(msg);

        if(strcmp(c->channel, update_channel) != 0) {
          // channel changed,  go dormant
          // this is legit according to my tests at
          // https://gist.github.com/2042350

          zclock_log("line %d: changed channel from %s to %s: trigger going dormant", trigger_memory.line_id, c->channel, update_channel);
          zsockopt_set_subscribe(line, "CHANNEL_CHANGE");
          zsockopt_set_unsubscribe(line, "VALUE");
        } 
        
        else if(trigger_func(&trigger_memory, value)) {
          send_trigger(client, c->target_worker, c->rule_id, value, user_id);
        }           

        free(update_channel);
      } else {
        // shouldn't ever happen.
        zclock_log("shouldn't have received command %s\n", zframe_strdup(cmd));
      }
      zmsg_destroy(&msg);
      zframe_destroy(&cmd);
    }
    
  }

  msgpack_zone_destroy(&mempool);
}
示例#2
0
void watch_port(void *cvoid, 
                zctx_t * context, 
                void * pipe ) {
  zclock_log("watch_port started!");
  monitorconfig_t * config = (monitorconfig_t*) cvoid;
  dump_monitorconfig(config);

  void * linein = zsocket_new(context, ZMQ_SUB);
  char * listen_socket = to_linesocket(config->line_id);
  char line_id[16];
  snprintf(line_id, 15, "%d", config->line_id);
  zsocket_connect(linein, listen_socket);
  zsockopt_set_unsubscribe(linein, "");
  zsockopt_set_subscribe(linein, "CLEAR_MONITORS");
  zsockopt_set_subscribe(linein, "VALUE");
  // have set up subscription, can signal parent that we're ok.
  child_handshake(pipe);
  zsocket_destroy(context, pipe); // no longer require pipe

  void * lineout = zsocket_new(context, ZMQ_PUB);
  zsocket_connect(lineout, config->out_socket);
  time_t until = time(NULL) + 60;
  while(time(NULL)<until) {
    zmsg_t * msg = zmsg_recv(linein);
    if(!msg) {
      zclock_log("monitor quitting!");
      return;
    }
    zframe_t * cmd = zmsg_pop(msg);
    if(zframe_streq(cmd, "CLEAR_MONITORS")) {
      zclock_log("ephemeral monitor quitting");
      zmsg_destroy(&msg);
      zframe_destroy(&cmd);
      break;
    } else if (zframe_streq(cmd, "VALUE")) {
      // TODO perhaps some rate limiting necessary
      assert(zmsg_size(msg) == 2);
      
      zframe_t * value = zmsg_pop(msg);
      int res = *(int*)zframe_data(value);
      char * new_channel = zmsg_popstr(msg);

      if(strcmp(new_channel, config->channel)!=0) {
        zclock_log("monitor on %d: listening for %s, channel changed to %s quitting",
                   config->line_id, config->channel, new_channel);
        zmsg_destroy(&msg);
        zframe_destroy(&cmd);
        break;
      }

      zmsg_t * to_send = zmsg_new();

      char buf[1024];
      snprintf(buf,1023, "%d", res);
      zmsg_pushstr(to_send, buf);
      zmsg_pushstr(to_send, line_id);
      zmsg_pushstr(to_send, config->source_worker);
      zclock_log("%s sending line %s -> %s", config->source_worker, line_id, buf);
      zmsg_send(&to_send, lineout);
      // don't destroy value frame, now owned by zmsg
    }
    // else ignore
    zmsg_destroy(&msg);
    zframe_destroy(&cmd);
  }
  zclock_log("monitor on %d: listening for %s, expiring naturally",
             config->line_id, config->channel);
  //cleanup
  zsocket_destroy(context, linein);
  zsocket_destroy(context, lineout);

}
示例#3
0
void line_listener(void * cvoid, zctx_t * context, void * pipe) {
  lineconfig_t * config = (lineconfig_t*)  cvoid;
  // atm, topic == outpipe, but this is coincidental...
  zmsg_t * msg;
  dump_lineconfig(config);
  channel_memory_t channel_memory = { strdup("unknown"),
                                      strdup("unknown"),
                                      0 };
  // void * monitor_controller = zsocket_new(config->context, ZMQ_PUB);
  //  zsocket_bind(monitor_controller, "inproc://monitor_controller");
  //  int trigger_capacity = 1;
  
  void * lineout = zsocket_new(context, ZMQ_PUB);
  char * outpipe = to_linesocket(config->line_id);
  zclock_log("binding line |%s|", outpipe);
  zsocket_bind(lineout, outpipe);

  void * subscriber = zsocket_new(context, ZMQ_SUB);
  zclock_log("subscribing to line |%d|", config->line_id);
  zsockopt_set_unsubscribe(subscriber, "");

  char * topic = to_line(config->line_id);
  // 
  zsockopt_set_subscribe(subscriber, topic);
  zclock_log("subscribing to literal line |%s|", topic);
  zsocket_connect(subscriber, "inproc://line");

  child_handshake(pipe);
  zsocket_destroy(context, pipe);

  while(1) {
    msg = zmsg_recv(subscriber);
    if(!msg) {
      zclock_log("line quitting!");
      return;
    }
        
    // zmsg_dump(msg);
    char * recv_topic = zmsg_popstr(msg);
    // zclock_log("line got topic\nreceived: %s\nexpected: %s\n", recv_topic, config->topic);
    //fflush(stdout);
    assert(strcmp(recv_topic, topic)==0);
    free(recv_topic);
    assert(zmsg_size(msg) == 2);
      
    char * channel = zmsg_popstr(msg);
    zmsg_t * out = zmsg_new();
    // originally, I thought it was a neat trick to not mention the
    // channel in every message. unfortunately, this screws up the
    // case where a new trigger gets introduced: at the beginning, it
    // has no idea what the channel currently is.

    // rather than trying to micro-optimise, let's just keep repeating
    // the channel in the value update too.

    if (port_changed(channel, &channel_memory)) {
      zmsg_pushstr(out, channel_memory.current_channel);
      zmsg_pushstr(out, "CHANNEL_CHANGE");
      zmsg_send(&out, lineout);
    }
    // only send a value if we're all settled down
    if(strcmp(channel, channel_memory.current_channel)==0) {
      out = zmsg_new();
      zmsg_pushstr(out, channel_memory.current_channel);
      zmsg_push(out, zmsg_pop(msg));
      zmsg_pushstr(out, "VALUE");
      zmsg_send(&out, lineout);
    }
    free(channel);
    zmsg_destroy(&msg);
    
  }
  free(config);
}