Example #1
0
// PushMsg implements the Channel PushMsg method.
func (c *SeqChannel) PushMsg(key string, m *myrpc.Message, expire uint) (err error) {
	client := myrpc.MessageRPC.Get()
	if client == nil {
		return ErrMessageRPC
	}
	c.mutex.Lock()
	// private message need persistence
	// if message expired no need persistence, only send online message
	// rewrite message id
	//m.MsgId = c.timeID.ID()
	m.MsgId = id.Get()
	if m.GroupId != myrpc.PublicGroupId && expire > 0 {
		args := &myrpc.MessageSavePrivateArgs{Key: key, Msg: m.Msg, MsgId: m.MsgId, Expire: expire}
		ret := 0
		if err = client.Call(myrpc.MessageServiceSavePrivate, args, &ret); err != nil {
			c.mutex.Unlock()
			log.Error("%s(\"%s\", \"%v\", &ret) error(%v)", myrpc.MessageServiceSavePrivate, key, args, err)
			return
		}
	}
	// push message
	if err = c.writeMsg(key, m); err != nil {
		c.mutex.Unlock()
		log.Error("c.WriteMsg(\"%s\", m) error(%v)", key, err)
		return
	}
	c.mutex.Unlock()
	return
}
Example #2
0
File: rpc.go Project: humortian/im
// PushPrivates expored a method for publishing a user multiple private message for the channel.
// because of it`s going asynchronously in this method, so it won`t return an error to caller.
func (c *CometRPC) PushPrivates(args *myrpc.CometPushPrivatesArgs, rw *myrpc.CometPushPrivatesResp) error {
	if args == nil {
		return myrpc.ErrParam
	}
	bucketMap := make(map[*ChannelBucket]*batchChannel, Conf.ChannelBucket)
	for _, key := range args.Keys {
		// get channel
		ch, bp, err := UserChannel.New(key)
		if err != nil {
			log.Error("UserChannel.New(\"%s\") error(%v)", key, err)
			// log failed keys.
			rw.FKeys = append(rw.FKeys, key)
			continue
		}
		if bucket, ok := bucketMap[bp]; !ok {
			bucketMap[bp] = &batchChannel{
				Keys: []string{key},
				Chs:  map[string]Channel{key: ch},
			}
		} else {
			// ignore duplicate key
			if _, ok := bucket.Chs[key]; !ok {
				bucket.Chs[key] = ch
				bucket.Keys = append(bucket.Keys, key)
			}
		}
	}
	// every bucket start a goroutine, return till all bucket gorouint finish
	wg := &sync.WaitGroup{}
	wg.Add(len(bucketMap))
	// stored every gorouint failed keys
	fKeysList := make([][]string, len(bucketMap))
	ti := 0
	for tb, tm := range bucketMap {
		go func(b *ChannelBucket, m *batchChannel, i int) {
			defer wg.Done()
			c := myrpc.MessageRPC.Get()
			if c == nil {
				// static slice is thread-safe
				// log all keys
				fKeysList[i] = m.Keys
				log.Debug("fkeys len:%d", len(m.Keys))
				return
			}
			b.Lock()
			defer b.Unlock()
			timeId := id.Get()
			//			msg := &myrpc.Message{Msg: args.Msg, MsgId: timeId}
			// private message need persistence
			// if message expired no need persistence, only send online message
			// rewrite message id
			resp := &myrpc.MessageSavePrivatesResp{}
			if args.Expire > 0 {
				args := &myrpc.MessageSavePrivatesArgs{Keys: m.Keys, Msg: args.Msg, MsgId: timeId, Expire: args.Expire}
				if err := c.Call(myrpc.MessageServiceSavePrivates, args, resp); err != nil {
					log.Error("%s(\"%v\", \"%v\", &ret) error(%v)", myrpc.MessageServiceSavePrivates, m.Keys, args, err)
					// static slice is thread-safe
					fKeysList[i] = m.Keys
					log.Debug("fkeys len:%d", len(m.Keys))
					return
				}
				fKeysList[i] = resp.FKeys
				log.Debug("fkeys len:%d", len(resp.FKeys))
			}
			// delete the failed keys
			for _, fk := range resp.FKeys {
				delete(m.Chs, fk)
			}
			// get all channels from batchChannel chs.
			//			for key, ch := range m.Chs {
			//				if err := ch.WriteMsg(key, msg); err != nil {
			//					// ignore online push error, cause offline msg succeed
			//					log.Error("ch.WriteMsg(\"%s\", \"%s\") error(%v)", key, string(msg.Msg), err)
			//					continue
			//				}
			//			}
		}(tb, tm, ti)
		ti++
	}
	wg.Wait()
	// merge all failed keys
	for _, k := range fKeysList {
		rw.FKeys = append(rw.FKeys, k...)
	}
	return nil
}