func (self *RestAPI) buildNotificationFromKV(reqId string, kv map[string]string, logger log.Logger, remoteAddr string, service string, subs []string) (notif *push.Notification, details *ApiResponseDetails, err error) { notif = push.NewEmptyNotification() for k, v := range kv { if len(v) <= 0 { continue } switch k { case "subscriber": case "subscribers": case "service": // three keys need to be ignored case "badge": if v != "" { var e error _, e = strconv.Atoi(v) if e == nil { notif.Data["badge"] = v } else { notif.Data["badge"] = "0" } } default: notif.Data[k] = v } } if notif.IsEmpty() { logger.Errorf("RequestId=%v From=%v Service=%v NrSubscribers=%v Subscribers=\"%+v\" EmptyNotification", reqId, remoteAddr, service, len(subs), subs) details = &ApiResponseDetails{RequestId: &reqId, From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_EMPTY_NOTIFICATION} return nil, details, errors.New("empty notification") } return notif, nil, nil }
// removeMissingDeliveryPointFromServiceSubscriber removes any associations from a subscription list to a dp with missing subscriptions. func (r *PushRedisDB) removeMissingDeliveryPointFromServiceSubscriber(service, subscriber, dpName string, logger log.Logger) { // Precondition: DELIVERY_POINT_PREFIX + dp was already missing. No need to remove it. e0 := r.client.SRem(SERVICE_SUBSCRIBER_TO_DELIVERY_POINTS_PREFIX+service+":"+subscriber, dpName).Err() if e0 != nil { logger.Errorf("Error cleaning up delivery point with missing data for dp %q service %q FROM user %q's delivery points: %v", dpName, subscriber, service, e0) } e1 := r.client.Del(DELIVERY_POINT_COUNTER_PREFIX + dpName).Err() // TODO: Err instead if e1 != nil { logger.Errorf("Error cleaning up count for delivery point with missing data for delivery point %q (while processing subscriber %q, service %q): %v", dpName, subscriber, service, e1) } }
func (self *RestAPI) pushNotification(reqId string, kv map[string]string, perdp map[string][]string, logger log.Logger, remoteAddr string) { service, err := getServiceFromMap(kv, true) if err != nil { logger.Errorf("RequestId=%v From=%v Cannot get service name: %v; %v", reqId, remoteAddr, service, err) return } subs, err := getSubscribersFromMap(kv, false) if err != nil { logger.Errorf("RequestId=%v From=%v Service=%v Cannot get subscriber: %v", reqId, remoteAddr, service, err) return } if len(subs) == 0 { logger.Errorf("RequestId=%v From=%v Service=%v NoSubscriber", reqId, remoteAddr, service) return } notif := NewEmptyNotification() for k, v := range kv { if len(v) <= 0 { continue } switch k { case "subscriber": case "subscribers": case "service": // three keys need to be ignored case "badge": if v != "" { var e error _, e = strconv.Atoi(v) if e == nil { notif.Data["badge"] = v } else { notif.Data["badge"] = "0" } } default: notif.Data[k] = v } } if notif.IsEmpty() { logger.Errorf("RequestId=%v From=%v Service=%v EmptyNotification", reqId, remoteAddr, service) return } logger.Infof("RequestId=%v From=%v Service=%v Subscribers=\"%v\"", reqId, remoteAddr, service, subs) self.backend.Push(reqId, service, subs, notif, perdp, logger) return }
func (self *RestAPI) pushNotification(reqId string, kv map[string]string, perdp map[string][]string, logger log.Logger, remoteAddr string, handler ApiResponseHandler) { service, err := getServiceFromMap(kv, true) if err != nil { logger.Errorf("RequestId=%v From=%v Cannot get service name: %v; %v", reqId, remoteAddr, service, err) handler.AddDetailsToHandler(ApiResponseDetails{RequestId: &reqId, From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_CANNOT_GET_SERVICE}) return } subs, err := getSubscribersFromMap(kv, false) if err != nil { logger.Errorf("RequestId=%v From=%v Service=%v Cannot get subscriber: %v", reqId, remoteAddr, service, err) handler.AddDetailsToHandler(ApiResponseDetails{RequestId: &reqId, From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_CANNOT_GET_SUBSCRIBER}) return } if len(subs) == 0 { logger.Errorf("RequestId=%v From=%v Service=%v NoSubscriber", reqId, remoteAddr, service) handler.AddDetailsToHandler(ApiResponseDetails{RequestId: &reqId, From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_NO_SUBSCRIBER}) return } notif, details, err := self.buildNotificationFromKV(reqId, kv, logger, remoteAddr, service, subs) if err != nil { handler.AddDetailsToHandler(*details) return } logger.Infof("RequestId=%v From=%v Service=%v NrSubscribers=%v Subscribers=\"%+v\"", reqId, remoteAddr, service, len(subs), subs) self.backend.Push(reqId, remoteAddr, service, subs, notif, perdp, logger, handler) }
func (self *RestAPI) querySubscriptions(kv map[string][]string, logger log.Logger) []byte { // "subscriber" is a required parameter subscriberParam, ok := kv["subscriber"] if !ok || len(subscriberParam) == 0 { logger.Errorf("Query=Subscriptions NoSubscriber %v", kv) return []byte("[]") } var services []string // "services" is an optional parameter that can have one or more services passed in the form of a CSV servicesParam, ok := kv["services"] if ok && len(servicesParam) > 0 { services = strings.Split(servicesParam[0], ",") } return self.backend.Subscriptions(services, subscriberParam[0], logger) }
// rebuildServiceSet is used to make sure that the /subscriptions and /psps APIs work properly, on uniqush setups created before those APIs existed. func (self *RestAPI) rebuildServiceSet(logger log.Logger) []byte { err := self.backend.RebuildServiceSet() var details ApiResponseDetails if err != nil { logger.Errorf("Error in /rebuildserviceset: %v", err) errorMsg := err.Error() details = ApiResponseDetails{ Code: UNIQUSH_ERROR_GENERIC, ErrorMsg: &errorMsg, } } else { details = ApiResponseDetails{Code: UNIQUSH_SUCCESS} } json, err := json.Marshal(details) if err != nil { return []byte("Failed to encode response") } return json }
func (self *RestAPI) changePushServiceProvider(kv map[string]string, logger log.Logger, remoteAddr string, add bool) { psp, err := self.psm.BuildPushServiceProviderFromMap(kv) if err != nil { logger.Errorf("From=%v Cannot build push service provider: %v", remoteAddr, err) return } service, err := getServiceFromMap(kv, true) if err != nil { logger.Errorf("From=%v Cannot get service name: %v; %v", remoteAddr, service, err) return } if add { err = self.backend.AddPushServiceProvider(service, psp) } else { err = self.backend.RemovePushServiceProvider(service, psp) } if err != nil { logger.Errorf("From=%v Failed: %v", remoteAddr, err) return } logger.Infof("From=%v Service=%v PushServiceProvider=%v Success!", remoteAddr, service, psp.Name()) return }
func (self *RestAPI) changePushServiceProvider(kv map[string]string, logger log.Logger, remoteAddr string, add bool) ApiResponseDetails { psp, err := self.psm.BuildPushServiceProviderFromMap(kv) if err != nil { logger.Errorf("From=%v Cannot build push service provider: %v", remoteAddr, err) return ApiResponseDetails{From: &remoteAddr, Code: UNIQUSH_ERROR_BUILD_PUSH_SERVICE_PROVIDER, ErrorMsg: strPtrOfErr(err)} } service, err := getServiceFromMap(kv, true) if err != nil { logger.Errorf("From=%v Cannot get service name: %v; %v", remoteAddr, service, err) return ApiResponseDetails{From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_CANNOT_GET_SERVICE, ErrorMsg: strPtrOfErr(err)} } if add { err = self.backend.AddPushServiceProvider(service, psp) } else { err = self.backend.RemovePushServiceProvider(service, psp) } if err != nil { logger.Errorf("From=%v Failed: %v", remoteAddr, err) return ApiResponseDetails{From: &remoteAddr, Code: UNIQUSH_ERROR_GENERIC, ErrorMsg: strPtrOfErr(err)} } pspName := psp.Name() logger.Infof("From=%v Service=%v PushServiceProvider=%v Success!", remoteAddr, service, pspName) return ApiResponseDetails{From: &remoteAddr, Service: &service, PushServiceProvider: &pspName, Code: UNIQUSH_SUCCESS} }
func (self *RestAPI) changeSubscription(kv map[string]string, logger log.Logger, remoteAddr string, issub bool) { dp, err := self.psm.BuildDeliveryPointFromMap(kv) if err != nil { logger.Errorf("Cannot build delivery point: %v", err) return } service, err := getServiceFromMap(kv, true) if err != nil { logger.Errorf("From=%v Cannot get service name: %v; %v", remoteAddr, service, err) return } subs, err := getSubscribersFromMap(kv, true) if err != nil { logger.Errorf("From=%v Service=%v Cannot get subscriber: %v", remoteAddr, service, err) return } var psp *PushServiceProvider if issub { psp, err = self.backend.Subscribe(service, subs[0], dp) } else { err = self.backend.Unsubscribe(service, subs[0], dp) } if err != nil { logger.Errorf("From=%v Failed: %v", remoteAddr, err) return } if psp == nil { logger.Infof("From=%v Service=%v Subscriber=%v DeliveryPoint=%v Success!", remoteAddr, service, subs[0], dp.Name()) } else { logger.Infof("From=%v Service=%v Subscriber=%v PushServiceProvider=%v DeliveryPoint=%v Success!", remoteAddr, service, subs[0], psp.Name(), dp.Name()) } }
func (self *RestAPI) changeSubscription(kv map[string]string, logger log.Logger, remoteAddr string, issub bool) ApiResponseDetails { dp, err := self.psm.BuildDeliveryPointFromMap(kv) if err != nil { logger.Errorf("Cannot build delivery point: %v", err) return ApiResponseDetails{From: &remoteAddr, Code: UNIQUSH_ERROR_BUILD_DELIVERY_POINT, ErrorMsg: strPtrOfErr(err)} } service, err := getServiceFromMap(kv, true) if err != nil { logger.Errorf("From=%v Cannot get service name: %v; %v", remoteAddr, service, err) return ApiResponseDetails{From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_CANNOT_GET_SERVICE, ErrorMsg: strPtrOfErr(err)} } subs, err := getSubscribersFromMap(kv, true) if err != nil { logger.Errorf("From=%v Service=%v Cannot get subscriber: %v", remoteAddr, service, err) return ApiResponseDetails{From: &remoteAddr, Service: &service, Code: UNIQUSH_ERROR_CANNOT_GET_SUBSCRIBER, ErrorMsg: strPtrOfErr(err)} } var psp *push.PushServiceProvider if issub { psp, err = self.backend.Subscribe(service, subs[0], dp) } else { err = self.backend.Unsubscribe(service, subs[0], dp) } if err != nil { logger.Errorf("From=%v Failed: %v", remoteAddr, err) return ApiResponseDetails{From: &remoteAddr, Code: UNIQUSH_ERROR_GENERIC, ErrorMsg: strPtrOfErr(err)} } dpName := dp.Name() if psp == nil { logger.Infof("From=%v Service=%v Subscriber=%v DeliveryPoint=%v Success!", remoteAddr, service, subs[0], dpName) return ApiResponseDetails{From: &remoteAddr, Service: &service, Subscriber: &subs[0], DeliveryPoint: &dpName, Code: UNIQUSH_SUCCESS} } else { pspName := psp.Name() logger.Infof("From=%v Service=%v Subscriber=%v PushServiceProvider=%v DeliveryPoint=%v Success!", remoteAddr, service, subs[0], pspName, dpName) return ApiResponseDetails{From: &remoteAddr, Service: &service, Subscriber: &subs[0], DeliveryPoint: &dpName, PushServiceProvider: &pspName, Code: UNIQUSH_SUCCESS} } }
func (r *PushRedisDB) GetSubscriptions(queryServices []string, subscriber string, logger log.Logger) ([]map[string]string, error) { if len(queryServices) == 0 { definedServices, err := r.GetServiceNames() if err != nil { return nil, fmt.Errorf("GetSubscriptions: %v", err) } queryServices = definedServices } var serviceForDeliveryPointNames []string var deliveryPointNames []string for _, service := range queryServices { if service == "" { logger.Errorf("empty service defined") continue } deliveryPoints, err := r.client.SMembers(SERVICE_SUBSCRIBER_TO_DELIVERY_POINTS_PREFIX + service + ":" + subscriber).Result() if err != nil { return nil, fmt.Errorf("Could not get subscriber information") } if len(deliveryPoints) == 0 { // it is OK to not have delivery points for a service continue } for _, deliveryPointName := range deliveryPoints { deliveryPointNames = append(deliveryPointNames, deliveryPointName) serviceForDeliveryPointNames = append(serviceForDeliveryPointNames, service) } } if len(deliveryPointNames) == 0 { // Return empty map without error. return make([]map[string]string, 0), nil } deliveryPointData, err := r.mgetRawDeliveryPoints(deliveryPointNames...) if err != nil { return nil, err } // Unserialize the subscriptions. If there are any invalid subscriptions, remove them and log it. // serviceForDeliveryPointNames, deliveryPointNames, and deliveryPointData all use the same index i. var subscriptions []map[string]string for i, data := range deliveryPointData { dpName := deliveryPointNames[i] service := serviceForDeliveryPointNames[i] if data != nil { subscriptionData, err := push.UnserializeSubscription(data) if err != nil { logger.Errorf("Error unserializing subscription for delivery point data for dp %q user %q service %q data %v: %v", dpName, subscriber, service, subscriptionData, err) continue } subscriptions = append(subscriptions, subscriptionData) } else { logger.Errorf("Redis error fetching subscriber delivery point data for dp %q user %q service %q, removing...", dpName, subscriber, service) // The multi-get did not encounter an error, so this key is missing. // Try to remove this delivery point as cleanly as possible, removing counts, etc. r.removeMissingDeliveryPointFromServiceSubscriber(service, subscriber, dpName, logger) } } return subscriptions, nil }