void read_serial(void * cvoid, zctx_t * context, void * pipe) {
  char * buf;
  serialconfig_t * config = (serialconfig_t*)cvoid;
  
  FILE * in = config->in; // fopen("/dev/ttyO1", "r");

  size_t nbytes=2047;
  //  Prepare our context and publisher
  buf = (char *) malloc(nbytes+1) ;
  fprintf(stderr, "bound\n");
  // first line is always garbage
  getline(&buf, &nbytes, in);
  child_handshake(pipe);
  zsocket_destroy(context, pipe);
  void* socket = zsocket_new(context, ZMQ_PUB);
  zsocket_bind(socket, "inproc://raw_serial");
  
  while ( getline(&buf, &nbytes, in) != -1 ) {
#ifdef DEBUG
    puts("line:");
    puts(buf);

#endif
    zmsg_t * msg = zmsg_new();
    zmsg_pushstr(msg, buf); // does buf need to be copied?
    zmsg_send(&msg, socket);
  }
  fprintf(stderr, "error reading from stdin\n");
  zsocket_destroy(context, socket);
}
Beispiel #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);

}
Beispiel #3
0
void generic_worker(void * cvoid, zctx_t * context, void * pipe) {
  workerconfig_t *config = (workerconfig_t*) cvoid;

  rulepackage_t rpkg;
  child_handshake(pipe);


  rpkg.channel = config->channel;
  rpkg.actions = zhash_new();
  rpkg.triggers = zhash_new();
  rpkg.context = context;
  rpkg.base_config = config->base_config;

  // FIX this needs to be initialised differently for each channel
  // normal channels will always have the "value" service,
  // but (for instance) the Camera channel has the "photo" service

  // zhash_t * services = zhash_new();
  
  char * ninja = config->base_config->uuid;
  rpkg.servicename = malloc(strlen(ninja) +
                            strlen(rpkg.channel) + 4);
  sprintf(rpkg.servicename, "n:%s:%s", ninja,rpkg.channel);

  channeldb_t *db = db_init(rpkg.servicename);

  zclock_log("%s worker preparing rules...", rpkg.servicename);

  zclock_log("%s worker reloading rules from db...", rpkg.servicename);
  db_reload_rules(db, &rpkg);

  //  reload_rules_db(context, db, rpkg.servicename, channel, rules, config->base_config);
  zclock_log("%s worker checking rules with server...", rpkg.servicename);
  char * reup = config->base_config->reup_endpoint;
  if(!reup) {
    zclock_log("E: NO REUP CONNECTION DEFINED! Probably dealing with an old server.");
  } else {
    void * reup_sock = zsocket_new(rpkg.context, ZMQ_DEALER);

    zclock_log("connecting to %s", reup);
    zsocket_connect(reup_sock, reup);
    zlist_t * rules = fetch_rules(reup_sock, rpkg.servicename);
    zmsg_t *tmp;
    while(tmp=zlist_pop(rules)) {
      // handle_command(tmp, NULL, &rpkg, db); // FIXME what do we do
                                               // with the reply?
    }
  }

  db_display_rules(db) ;


  zclock_log("%s worker connecting...", rpkg.servicename);
  mdwrk_t *session = mdwrk_new (config->base_config->broker_endpoint, rpkg.servicename, 0);
  zclock_log("%s worker connected!", rpkg.servicename);
  zmsg_t *reply = NULL;
  while (1) {
    zclock_log("%s worker waiting for work.", rpkg.servicename);
    zmsg_t *request = mdwrk_recv (session, &reply);

    if (request == NULL)
      break;              //  Worker was interrupted
    reply = zmsg_new();
    handle_command(request, reply,  &rpkg, db);
  }
  db_destroy(db);
  mdwrk_destroy (&session);
  return;
}
Beispiel #4
0
void generic_worker(void * cvoid, zctx_t * context, void * pipe) {
  workerconfig_t *config = (workerconfig_t*) cvoid;
  zhash_t * rules = zhash_new();

  child_handshake(pipe);
  zmsg_t *reply = NULL;
  void * rule_pipe = NULL;
  char * ninja = config->base_config->identity;
  char * channel = config->channel;

  char * servicename = malloc(strlen(ninja) +
                              strlen(channel) + 2);
  sprintf(servicename, "%s:%s", ninja,channel);

  // sqlite stuff
  int rc;
  char * tail = NULL;
  sqlite3 *db = init_db(servicename);
  sqlite3_stmt * insert_stmt;
  zclock_log("%s worker preparing rules...", servicename);
  sqlite3_prepare_v2(db, "insert into rules VALUES (@RULEID, @TRIGGER_NAME, @TARGET_WORKER, @AUTH, @ADDINS);", 512, &insert_stmt, NULL);
  zclock_log("%s worker reloading rules...", servicename);
  reload_rules(context, db, servicename, channel, rules);
  zclock_log("%s worker connecting...", servicename);
  mdwrk_t *session = mdwrk_new (config->base_config->broker_endpoint, servicename, 0);
  zclock_log("%s worker connected!", servicename);

  while (1) {
    zclock_log("%s worker waiting for work.", servicename);
    zmsg_t *request = mdwrk_recv (session, &reply);

    if (request == NULL)
      break;              //  Worker was interrupted

    char * command = zmsg_popstr(request);
    char * rule_id = zmsg_popstr(request);

    zclock_log("%s worker servicing request %s for rule %s", servicename,command,rule_id);
    reply = zmsg_new();
    if (strcmp(command, "AddTrigger") == 0) {
      zclock_log("new trigger!");
      if (zhash_lookup(rules, rule_id)) {
        // already have a rule with that id! WTF??
        // FIXME should probably delete this and reinstate
        zclock_log("Received duplicate rule %s, ignoring", rule_id);
        zmsg_destroy(&request);

        zmsg_pushstr(reply, "duplicate");
      } else {
        triggerconfig_t * tconf = malloc(sizeof(triggerconfig_t));
        create_triggerconfig(tconf, request, channel, rule_id);
        char * created = create_trigger(rules, rule_id, context, tconf);
        if(NULL == created) {
          // happy path, so add to db
          sqlite3_bind_text(insert_stmt, 1, tconf->rule_id, -1, SQLITE_TRANSIENT);
          sqlite3_bind_text(insert_stmt, 2, tconf->trigger_name, -1, SQLITE_TRANSIENT);
          sqlite3_bind_text(insert_stmt, 3, tconf->target_worker, -1, SQLITE_TRANSIENT);
          sqlite3_bind_text(insert_stmt, 4, tconf->auth, -1, SQLITE_TRANSIENT);
          sqlite3_bind_text(insert_stmt, 5, tconf->addins, -1, SQLITE_TRANSIENT);
          sqlite3_step(insert_stmt);
          sqlite3_clear_bindings(insert_stmt);
          sqlite3_reset(insert_stmt);

          zmsg_pushstr(reply, "ok");
        } else {
          zclock_log("create_trigger failed: %s", created);
          zmsg_pushstr(reply, created);
        }
        free(created);

      }
    } else if (strcmp(command,"RemoveRule") == 0) {

      if (rule_pipe=zhash_lookup(rules, rule_id)) {
        // found it
        zclock_log("rule %s exists, removing.", rule_id);
        send_sync("Destroy",rule_pipe);
        zclock_log("rule %s waiting for OK from pipe", rule_id);
        recv_sync("ok", rule_pipe);
        zsocket_destroy(context, rule_pipe);
        zhash_delete(rules, rule_id);
        zmsg_pushstr(reply, "ok");
        zclock_log("rule %s completely destroyed", rule_id);
      } else {
        // not there!
        zclock_log("Received delete trigger request for nonexistent rule %s, ignoring", rule_id);
        zmsg_pushstr(reply, "rule not found");
      }
    } else if (strcmp(command, "AddMonitor")==0) {
      // unconditionally fork a monitor for each line
      // they'll die when they get a channel change
      int i;
      for(i=1; i<4; i++) { 
        monitorconfig_t * mconf = malloc(sizeof(monitorconfig_t));
        mconf->line_id = i;
        mconf->source_worker = servicename;
        mconf->out_socket = config->base_config->portwatcher_endpoint;
        mconf->channel = channel;
        void * monitor_pipe = zthread_fork(context, watch_port, (void*)mconf);
        send_sync("ping", monitor_pipe);
        recv_sync("pong", monitor_pipe);
        zsocket_destroy(context, monitor_pipe);
      }
      zmsg_pushstr(reply, "ok");
    } else {
      zclock_log("Can't handle command %s: ignoring", command);
    }
    zmsg_destroy(&request);
  }
  mdwrk_destroy (&session);
  return;
}
Beispiel #5
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);
}