func NewHandler(a *giles.Archiver, config *giles.BOSSWAVE) *BOSSWaveHandler { bwh := &BOSSWaveHandler{ a: a, bw: bw.ConnectOrExit(config.Address), namespace: config.Namespace, stop: make(chan bool), requests: make(map[string]*ArchiveRequest), } bwh.bw.OverrideAutoChainTo(true) bwh.vk = bwh.bw.SetEntityFileOrExit(config.Entityfile) bwh.svc = bwh.bw.RegisterService(bwh.namespace, "s.giles") bwh.iface = bwh.svc.RegisterInterface("0", "i.archiver") queryChan, err := bwh.bw.Subscribe(&bw.SubscribeParams{ URI: bwh.iface.SlotURI("query"), }) if err != nil { log.Error(errors.Wrap(err, "Could not subscribe")) } log.Noticef("Listening on %s", bwh.iface.SlotURI("query")) log.Noticef("Listening on %s", bwh.iface.SlotURI("subscribe")) util.NewWorkerPool(queryChan, bwh.listenQueries, 1000).Start() bwh.iface.SubscribeSlot("subscribe", bwh.listenCQBS) v, e := views.CreateView(bwh.bw, views.Expression{ NamespaceList: config.ListenNS, N: &views.EqualsNode{Key: views.String("giles")}, }) if e != nil { log.Error(errors.Wrap(e, "Could not create view")) } go func() { for msg := range v.Subscribe() { go bwh.handleArchiveRequest(msg) } }() return bwh }
func (uri *URIArchiver) Listen(a *giles.Archiver) { util.NewWorkerPool(uri.metadataChan, func(msg *bw.SimpleMessage) { a.AddData(uri.GetMetadata(msg)) }, 1000).Start() for msg := range uri.subscription { for _, po := range msg.POs { if !po.IsType(uri.PO, uri.PO) { continue } // for each of the major types, unmarshal it into some generic type // and apply the object builder stuff. // For now, assume it is msgpack var thing interface{} err := po.(bw.MsgPackPayloadObject).ValueInto(&thing) if err != nil { log.Error(errors.Wrap(err, "Could not unmarshal msgpack object")) } err = a.AddData(uri.GetSmapMessage(thing)) if err != nil { log.Error(errors.Wrap(err, "Could not add data")) } } } }
func (vm *ViewManager) subscribeNamespaces(expr Expression) { var ( persistedMetadata chan *bw.SimpleMessage ) for _, namespace := range expr.NamespaceList { // canonicalize the namespace uri := strings.TrimSuffix(namespace, "/") + "/*/!meta/+" // check if we are already subscribed to the namespace vm.nsL.RLock() _, found := vm.namespaceSubscriptions[namespace] vm.nsL.RUnlock() if found { continue } // if we are not subscribed to the namespace, we need to resolve the namespace into // its actual VK, because that is what will be in the URIs we receive on subscriptions. // We may actually end up getting the naked VK in the namespace, but it is more likely // that we will receive an alias which we will have to resolve. // resolve namespace ro, _, err := vm.client.ResolveRegistry(namespace) if err != nil { log.Fatal(errors.Wrapf(err, "Could not resolve namespace %s", namespace)) } // OKAY so the issue here is that bw2's objects package is vendored, and runs into // conflict when used with the bw2bind package. So, we cannot import the objects // package. We only need the objects package to get the *objects.Entity object from // the RoutingObject interface we get from calling ResolveRegistry. The reason why we // need an Entity object is so we can call its GetVK() method to get the namespace VK // that is mapped to by the alias we threw into ResolveRegistry. // Because the underlying object actually is an entity object, we can use the reflect // package to just call the method directly without having to import the objects // package to do the type conversion (e.g. ro.(*object.Entity).GetVK()). // The rest is just reflection crap: call the method using f.Call() using []reflect.Value // to indicate an empty arguments list. We use [0] to get the first (and only) result, // and call .Bytes() to return the underlying byte array returned by GetVK(). We // then interpret it using base64 urlsafe encoding to get the string value. f := reflect.ValueOf(ro).MethodByName("GetVK") nsvk := base64.URLEncoding.EncodeToString(f.Call([]reflect.Value{})[0].Bytes()) vm.namespaceAliases[namespace] = nsvk log.Noticef("Resolved alias %s -> %s", namespace, nsvk) log.Noticef("Subscribe to %s", uri) // subscribe to all !meta tags on that namespace vm.namespaceSubscriptions[namespace], err = vm.client.Subscribe(&bw.SubscribeParams{ URI: uri, }) if err != nil { log.Fatal(errors.Wrapf(err, "Could not subscribe to namespace %s", uri)) } log.Debugf("Subscribed to namespace %s", uri) // handle the subscriptions sub := vm.namespaceSubscriptions[namespace] util.NewWorkerPool(sub, func(msg *bw.SimpleMessage) { for _, rec := range GetRecords(msg) { if err := vm.db.Insert(rec); err != nil { log.Error(errors.Wrap(err, "Could not insert record")) } } vm.checkViews() }, 1000).Start() // Subscriptions only give us metadata messages that appear AFTER the subscription begins, // so we execute a query to get all metadata messages that were there already persistedMetadata, err = vm.client.Query(&bw.QueryParams{ URI: uri, }) if err != nil { log.Fatal(errors.Wrapf(err, "Could not query namespace %s", uri)) } util.NewWorkerPool(persistedMetadata, func(msg *bw.SimpleMessage) { for _, rec := range GetRecords(msg) { if err := vm.db.Insert(rec); err != nil { log.Error(errors.Wrap(err, "Could not insert record")) } } vm.checkViews() }, 1000).Start() } }