func (this *Counter) ReadNotificationItem(input *ReadNotificationInput, reply *CountNotification) (err error) { defer func() { if x := recover(); x != nil { utils.PrintfStackAndError("Error: %+v \n For:", x.(error), input) } }() var myCount *qortexapi.MyCount serv, err := MakeWsService(input.OrganizationId, input.ReaderId) if err != nil { utils.PrintStackAndError(err) return } if myCount, err = serv.ReadNotificationItem(input.NotificationItemId, input.GroupId); err != nil { utils.PrintStackAndError(err) return } if serv.OnlineUser == nil { return } newReply := CountNotification{ Method: COUNTER_READ_NOTIFICATION, MyCount: myCount, NewMessageNumber: len(serv.OnlineUser.NewMessageIds), } serv.OnlineUser.SendReply(newReply) return }
func CreateNews(input *duoerlapi.NewsInput) (originInput *duoerlapi.NewsInput, err error) { originInput = input newsId, err := utils.ToObjectId(input.Id) if err != nil { utils.PrintStackAndError(err) return } brandId, err := utils.ToObjectId(input.BrandId) if err != nil { utils.PrintStackAndError(err) return } authorId, err := utils.ToObjectId(input.AuthorId) if err != nil { utils.PrintStackAndError(err) return } dbNews := &news.News{ Id: newsId, BrandId: brandId, Article: *articles.NewArticle(input.Title, input.Content, authorId), } if err = dbNews.Save(); err != nil { utils.PrintStackAndError(err) return } return }
func UpdateNews(input *duoerlapi.NewsInput) (originInput *duoerlapi.NewsInput, err error) { originInput = input newsId, err := utils.ToObjectId(input.Id) if err != nil { utils.PrintStackAndError(err) return } brandId, err := utils.ToObjectId(input.BrandId) if err != nil { utils.PrintStackAndError(err) return } dbNews, err := news.FindById(newsId) if err != nil { utils.PrintStackAndError(err) return } dbNews.BrandId = brandId dbNews.Title = input.Title dbNews.Content = input.Content if err = dbNews.Save(); err != nil { utils.PrintStackAndError(err) return } return }
func ShowNews(newsIdHex, userIdHex string) (apiNews *duoerlapi.News, err error) { newsId, err := utils.ToObjectId(newsIdHex) if err != nil { utils.PrintStackAndError(err) return } dbNews, err := news.FindById(newsId) if err != nil { utils.PrintStackAndError(err) return } brand, err := brands.FindById(dbNews.BrandId) if err != nil { utils.PrintStackAndError(err) return } author, err := users.FindById(dbNews.AuthorId) if err != nil { utils.PrintStackAndError(err) return } apiNews = toApiNews(dbNews, brand, author) return }
func InitConsumers() (err error) { // Put consumers here consumers := []Consumer{ &nfts.EntryNtfsConsumer{}, } for _, consumer := range consumers { topic, channel := consumer.TopicAndChannel() reader, err := nsq.NewReader(topic, channel) if err != nil { utils.PrintStackAndError(err) return err } reader.AddHandler(consumer) err = reader.ConnectToLookupd(configs.NsqLookupAdddr) if err != nil { utils.PrintStackAndError(err) return err } } return }
// Make the service object in web socket connection func MakeWsService(orgIdHex, userIdHex string) (wsService *WsService, err error) { userId, err := utils.ToObjectId(userIdHex) if err != nil { utils.PrintStackAndError(err) return } activeOrg, err := MyActiveOrg(orgIdHex) if err != nil { utils.PrintStackAndError(err) return } wsService = new(WsService) onlineUser, err := activeOrg.GetOnlineUserById(userId) if err != nil { utils.PrintStackAndError(err) return } wsService.OnlineUser = onlineUser wsService.LoggedInUser = onlineUser.User wsService.CurrentOrg = activeOrg.Organization wsService.AllDBs = activeOrg.AllDBs return }
// Entrance that builds and maintains the websocket connection for users func BuildConnection(conn *websocket.Conn) { defer func() { if err := recover(); err != nil { log.Printf("********** WebSocket Error: %+v ***********\n", err) debug.PrintStack() } }() orgIdHex := conn.Request().URL.Query().Get("o") if orgIdHex == "" { return } wsCookie := "" for _, cc := range conn.Request().Cookies() { if cc.Name == "qortex" { wsCookie = cc.Value break } } if wsCookie == "" { return } member, _ := getSessionMember(wsCookie) if member == nil { return } activeOrg, err := MyActiveOrg(orgIdHex) if err != nil { utils.PrintStackAndError(err) return } user, err := users.FindById(activeOrg.Organization.Database, member.Id) if err != nil { utils.PrintStackAndError(err) return } onlineUser := activeOrg.GetOrInitOnlineUser(user, conn) log.Printf("----> New websocket connection for: %s, %+v running totally", user.Email, len(onlineUser.WsConns)) // Holding the connection jsonrpc.ServeConn(conn) // Cut current connection and clean up related resources onlineUser.KillWebsocket(conn) }
func MyActiveOrg(orgIdHex string) (activeOrg *ws.ActiveOrg, err error) { mu.Lock() defer mu.Unlock() // Validation: The org id should be valid orgId, err := utils.ToObjectId(orgIdHex) if err != nil { utils.PrintStackAndError(err) return } // Already running in the map activeOrg, exist := activeOrgMap[orgIdHex] if exist { return } // Should init the org and put into map for further use org, err := organizations.FindById(orgId) if err != nil { utils.PrintStackAndError(err) return } // Find and maintain all dbs for handling shared groups allDBs := []*mgodb.Database{org.Database} embedOrgs, err := organizations.FindByIds(org.EmbededOrgIds) if err != nil { utils.PrintStackAndError(err) return } for _, embedOrg := range embedOrgs { allDBs = append(allDBs, embedOrg.Database) } // Init the activeOrg and put it into the map activeOrg = &ws.ActiveOrg{ OrgId: orgIdHex, Organization: org, OnlineUsers: make(map[bson.ObjectId]*ws.OnlineUser), Broadcast: make(chan ws.GenericPushingMessage), CloseSign: make(chan bool), AllDBs: allDBs, } go runActiveOrg(activeOrg) activeOrgMap[orgIdHex] = activeOrg return }
func (this *Counter) ReadEntry(input *ReadEntryInput, reply *CountNotification) (err error) { defer func() { if x := recover(); x != nil { utils.PrintfStackAndError("Error: %+v \n For:", x.(error), input) } }() if !input.isValid() { return } var myCount *qortexapi.MyCount serv, err := MakeWsService(input.OrganizationId, input.ReaderId) if err != nil { utils.PrintStackAndError(err) return } var method string switch { case input.isReadEntry(): method = COUNTER_READ_ENTRY myCount, err = serv.ReadEntry(input.EntryId, input.GroupId) case input.isReadMyMessage(): method = COUNTER_READ_MESSAGE myCount, err = serv.ReadMyMessage(input.ConversationId) default: return } if err != nil { utils.PrintStackAndError(err) return } if serv.OnlineUser == nil { return } newReply := CountNotification{ Method: method, EntryId: input.EntryId, GroupId: input.GroupId, MyCount: myCount, NewMessageNumber: serv.OnlineUser.ClearNewMessageId(), } serv.OnlineUser.SendReply(newReply) return }
func (this *OnlineUser) SendReply(reply GenericPushingMessage) { defer func() { if err := recover(); err != nil { utils.PrintStackAndError(err.(error)) } }() this.Send <- reply }
func (this *Pulse) Send(input *PulseInput, reply *string) (err error) { defer func() { if e := recover(); e != nil { utils.PrintStackAndError(e.(error)) } }() *reply = "Pulse.Get" return }
func GetNewsInBrand(brandIdHex string) (apiNews []*duoerlapi.News, err error) { brandId, err := utils.ToObjectId(brandIdHex) if err != nil { utils.PrintStackAndError(err) return } newz, err := news.FindSomeByBrandId(brandId) if err != nil { utils.PrintStackAndError(err) return } for _, dbNews := range newz { apiNews = append(apiNews, toApiNews(dbNews, nil, nil)) } return }
func (this *EntryNtfsConsumer) HandleMessage(msg *nsq.Message) (err error) { entryTopicData := new(nsqproducers.EntryTopicData) err = json.Unmarshal(msg.Body, &entryTopicData) if err != nil { utils.PrintStackAndError(err) return } services.SendEntryNotification(entryTopicData) return }
func (this *Counter) Refresh(input *RefreshInput, reply *CountNotification) (err error) { defer func() { if x := recover(); x != nil { utils.PrintfStackAndError("Error: %+v \n For:", x.(error), input) } }() reply.Method = COUNTER_REFRESH serv, err := MakeWsService(input.OrganizationId, input.LoggedInUserId) if err != nil { utils.PrintStackAndError(err) return } reply.MyCount, err = serv.GetMyCount() if err != nil { utils.PrintStackAndError(err) return } return }
func EditNews(user *users.User, newsIdHex string) (newsInput *duoerlapi.NewsInput, err error) { newsId, err := utils.ToObjectId(newsIdHex) if err != nil { utils.PrintStackAndError(err) return } dbNews, err := news.FindById(newsId) if err != nil { utils.PrintStackAndError(err) return } if dbNews.AuthorId != user.Id { err = global.PermissionDeniedError return } newsInput = toNewsInput(dbNews) return }
func SendEntryNotification(entryTopicData *nsqproducers.EntryTopicData) (err error) { serv, err := MakeWsService(entryTopicData.OrgId, entryTopicData.UserId) if err != nil { utils.PrintStackAndError(err) return } apiEntry := entryTopicData.ApiEntry currentOrg := serv.CurrentOrg currentUser := serv.LoggedInUser // TODO: the db should be group db, not current org db db := currentOrg.Database entry, err := entries.FindById(db, bson.ObjectIdHex(apiEntry.Id)) if err != nil { utils.PrintStackAndError(err) return } var entity notifications.Entity switch entryTopicData.Status { case nsqproducers.TOPIC_STATUS_CREATE, nsqproducers.TOPIC_STATUS_DELETE, nsqproducers.TOPIC_STATUS_UPDATE: entity = notifications.MakeEntryEntity(db, currentOrg, currentUser, entry) case nsqproducers.TOPIC_STATUS_LIKE, nsqproducers.TOPIC_STATUS_REMOVE_LIKE: hasLiked := (entryTopicData.Status == nsqproducers.TOPIC_STATUS_LIKE) entity = notifications.NewLikeEntity(currentOrg, currentUser, entry, hasLiked) } // currentTime := time.Now() causedEntry := entity.CausedEntry() causedEntries := entity.CausedEntries() eventMap := entity.Events(db) // Save or delete notification items if err := entity.HandleNotificationItems(db, eventMap); err != nil { utils.PrintStackAndError(err) // dont' return } orgIds := entity.GetToNotifyOrgIds() // Build organization map for shared group user orgMap := make(map[string]*organizations.Organization) orgs, err := organizations.FindByIds(utils.TurnPlainIdsToObjectIds(orgIds)) if err == nil { for _, org := range orgs { orgMap[org.Id.Hex()] = org } } onlineUsers := GetOnlineUsersByOrgIds(orgIds) emailToUserMap := make(map[string]bool) // Handle event for each user for toUserId, event := range eventMap { // If it is Qortex Support, then the key of the eventMap is "userId-organizationId", // which is used to differentiate same user in different organizations toUserId = strings.Split(toUserId, "-")[0] toUserObjectId := bson.ObjectIdHex(toUserId) orgId := bson.ObjectIdHex(event.ToUser.OriginalOrgId) // don't notify anything to sender if currentUser.Id == toUserObjectId && entity.NotNotifySelf() { continue } if entity.NeedResetUserCount() { if causedEntries != nil { for _, causedEntry := range causedEntries { notifications.ResetCount(db, toUserObjectId, causedEntry.GroupId, orgId) } } else { // Reset user mycount for event user notifications.ResetCount(db, toUserObjectId, causedEntry.GroupId, orgId) } } onlineUser := pickOnlineUser(toUserObjectId, onlineUsers) if onlineUser == nil { // Don't send mail multi times to the same member when posting a Qortex Support _, exist := emailToUserMap[toUserId] if !exist && event.NeedToSendNotificationMail() { // Send Mail if user offline, only work in Dev and Production // serv.SendNotificationMail(event, apiEntry, currentTime, orgMap) } } else if entity.NeetToSendRealtimeNotification(onlineUser.User) { makeAndPushEventReply(currentUser, event, entity, onlineUser) } emailToUserMap[toUserId] = true } return }