How to use Broker::Data in an event handler?

I'm trying to figure out if/how it is possible to use Broker::Data in an event handler as follows:

    event foo(x: Broker::Data)
      {
      print x;
      }

I'm trying to send an event via the Python bindings:

    event = broker.bro.Event("foo", broker.Data(42))
    endpoint.publish("/test", event)

However, Bro complains:

    warning: failed to convert remote event 'foo' arg #0, got integer, expected record

I tried both

    event = broker.bro.Event("foo", 42)

and a wrapped version

    event = broker.bro.Event("foo", broker.Data(42))

and even

    event = broker.bro.Event("foo", broker.Data(broker.Data(42)))

but it seems that nesting is not possible.

The use case for having a Broker::Data in the Bro event handler is that the structure of the data is varying at runtime (similar to JSON).

    Matthias

(The code is a slightly adapted version from https://github.com/bro/broker/issues/11.)

I'm trying to figure out if/how it is possible to use Broker::Data in an
event handler as follows:

    event foo(x: Broker::Data)
      {
      print x;
      }

No, but you can try to use 'any' instead of 'Broker::Data'. Examples/ideas:

# Bro code

type myvec: vector of any;

type myrec: record {
    b: count &optional;
    c: int &optional;
};

event bar(x: any)
    {
    switch ( x ) {
    case type myrec as r:
        print "record", r;
        break;
    case type string as s:
        print "string", s;
        break;
    case type int as i:
        print "int", i;
        break;
    case type count as c:
        print "count", c;
        break;
    case type myvec as v:
        {
        print "vector", v;

        for ( i in v )
            event bar(v[i]);
        }
        break;
    default:
        print "got unknown type", x;
        break;
    }
}

# Python code

endpoint.publish("/test", broker.bro.Event("bar", "one"))
endpoint.publish("/test", broker.bro.Event("bar", 2))
endpoint.publish("/test", broker.bro.Event("bar", broker.Count(3)))
endpoint.publish("/test", broker.bro.Event("bar",
        ["one", "two", broker.Count(3)]))
endpoint.publish("/test", broker.bro.Event("bar",
        ["one", None, None]))

The use case for having a Broker::Data in the Bro event handler is that
the structure of the data is varying at runtime (similar to JSON).

Should be the same idea if you use the 'any' type along with
appropriate type checking/casting.

(The code is a slightly adapted version from
Issues · bro/broker · GitHub)

This, plus a couple other bugs should now be fixed in bro + broker, so
make sure to update both if trying the above examples.

- Jon

This, plus a couple other bugs should now be fixed in bro + broker, so

make sure to update both if trying the above examples.

Great, it works now!

One more question: how would I capture a default-constructed
broker::Data() in a case statement? This would happen when I publish
just "None" on the Python side. In Bro, it shows up on the command
line as "broker::data{nil}".

    Matthias

There's no nil/null/none type in Bro, so only way I can think to do it
at the moment is:

function is_nil(x: any): bool
    {
    if ( ! (x is Broker::Data) )
        return F;

    local d = x as Broker::Data;

    if ( ! d?$data )
        return T;

    if ( cat(d$data) != "broker::data{nil}" )
        return F;

    return T;
    }

Or in switch case, it's like:

    case type Broker::Data as d:
        print "Broker::Data, expected to be nil", d?$data, d?$data ?
cat(d$data) : "nil";
        # or use the same logic from the is_nil() function above

- Jon

    case type Broker::Data as d:
        print "Broker::Data, expected to be nil", d?$data, d?$data ?
cat(d$data) : "nil";
        # or use the same logic from the is_nil() function above

This is the logic I was looking for, thanks! The generic is_nil
function might come in handy some other point.

    Matthias