Example #1
0
File: db.go Project: upwrd/sift
func upsertBaseComponentTx(tx *sqlx.Tx, deviceID types.DeviceID, name string, c types.Component) (int64, error) {
	base := c.GetBaseComponent()
	existingBaseComp, found := getBaseComponentTx(tx, deviceID, name)
	if !found {
		// not found: do insert
		q := "INSERT INTO component (device_id, name, make, model, type) VALUES (?, ?, ?, ?, ?)"
		res, err := tx.Exec(q, deviceID, name, base.Make, base.Model, c.Type())
		if err != nil {
			return 0, fmt.Errorf("error inserting component: %v", err)
		}
		id, err := res.LastInsertId() // Get ID from insert
		if err != nil || id == 0 {
			return 0, fmt.Errorf("error or zero-value ID (id: %v, err: %v)", id, err)
		}
		Log.Debug("inserted component", "id", id, "base_component", base, "stmt", q)
		return id, nil
	}

	// found: do update
	q := "UPDATE component SET make=?, model=?, type=? WHERE id=?;"
	_, err := tx.Exec(q, base.Make, base.Model, c.Type(), existingBaseComp.ID)
	if err != nil {
		return 0, fmt.Errorf("error updating base component: %v", err)
	}
	Log.Debug("updated component", "base", base, "query", q, "update_err", err)
	return existingBaseComp.ID, err
}
Example #2
0
// PostComponent will notify all listeners of a change to the provided
// Component. The specific type of change should by provided in the
// ActionsMask.
func (n *Notifier) PostComponent(id types.ComponentID, comp types.Component, amask ActionsMask) {
	nchans := make(map[chan interface{}]struct{}) // A list of channels to notify

	// Get all of the notification channels that match this component & action
	n.lock.RLock()
	defer n.lock.RUnlock()

	// Get notification channels listening for components with matching IDs
	if filterList, ok := n.componentListenersFilteredByID[id]; ok {
		for nchan, atypes := range filterList {
			// atypes == 0 means the filter is listening to all actions
			// atypes & atype should be nonzero if atypes contains the bit representing atype
			if atypes == 0 || atypes&amask != 0 {
				nchans[nchan] = struct{}{}
			}
		}
	}

	// Get notification channels listening for components with matching types
	if filterList, ok := n.componentListenersFilteredByType[comp.Type()]; ok {
		for nchan, atypes := range filterList {
			// atypes == 0 means the filter is listening to all actions
			// atypes & atype should be nonzero if atypes contains the bit representing atype
			if atypes == 0 || atypes&amask != 0 {
				nchans[nchan] = struct{}{}
			}
		}
	}

	// Get notification channels listening for all components
	for nchan, atypes := range n.unfilteredComponentListeners {
		// atypes == 0 means the filter is listening to all actions
		// atypes & atype should be nonzero if atypes contains the bit representing atype
		if atypes == 0 || atypes&amask != 0 {
			nchans[nchan] = struct{}{}
		}
	}

	// Get notification channels listening for any-and-all notifications
	for nchan, atypes := range n.allNotificationListeners {
		// atypes == 0 means the filter is listening to all actions
		// atypes & atype should be nonzero if atypes contains the bit representing atype
		if atypes == 0 || atypes&amask != 0 {
			nchans[nchan] = struct{}{}
		}
	}

	n.log.Debug("channels during PostComponent", "componentListenersFilteredByID", n.componentListenersFilteredByID, "componentListenersFilteredByType", n.componentListenersFilteredByType, "unfilteredComponentListeners", n.unfilteredComponentListeners, "allNotificationListeners", n.allNotificationListeners)
	n.log.Debug("matching (but not yet authorized) channels", "nchans", nchans)

	// Post to authorized channels
	cnotif := ComponentNotification{
		ID:        id,
		Component: comp,
		Action:    amask,
	}
	for nchan := range nchans {
		if token, ok := n.authTokenByChannel[nchan]; ok {
			if n.authorizor.Authorize(token, "components:-unimplemented-data-type:") {
				n.doPost(nchan, cnotif)
			}
		}
	}
}