Beispiel #1
0
//----------------------------------------------------------
// 组播包
func SYS_multicast(sess *Session, obj *IPCObject) []byte {
	DEBUG("RECEIVED SYS_MULTICAST")
	realmsg := &IPCObject{}
	err := json.Unmarshal(obj.Object, realmsg)
	if err != nil {
		ERR("SYS_multicast cannot decode msg", err, obj.Object)
		return nil
	}

	// 投递closure
	send := func(MQ chan IPCObject) {
		defer func() {
			recover()
		}()
		MQ <- *realmsg
	}

	// 循环投递
	DEBUG("SERVICE:", realmsg.Service)
	for _, v := range obj.AuxIDs {
		peer := gsdb.QueryOnline(v)
		if peer != nil {
			// if target userid is SYS_USR, it's possible that SYS_USR's MQ is full,
			// and deadlock will happen, so, we use GO!
			if v == SYS_USR {
				go send(peer.MQ)
			} else {
				send(peer.MQ)
			}
		}
	}

	DEBUG("MULTICAST Delivered to", len(obj.AuxIDs), "users")
	return nil
}
//----------------------------------------------------------
// 广播包
// 只由 SYS_USR 接收
// 外部只需要调用Broadcast函数即可
func SYS_broadcast(sess *Session, obj *IPCObject) []byte {
	// 解包
	DEBUG("RECEIVED SYS_BROADCAST")
	realmsg := &IPCObject{}
	err := json.Unmarshal(obj.Object, realmsg)
	if err != nil {
		ERR("SYS_broadcast cannot decode msg", err, obj.Object)
		return nil
	}

	// 投递closure
	send := func(MQ chan IPCObject) {
		defer func() {
			recover()
		}()
		MQ <- *realmsg
	}

	// 循环投递
	DEBUG("SERVICE", realmsg.Service)
	users := gsdb.ListAll()
	for _, v := range users {
		peer := gsdb.QueryOnline(v)
		if peer != nil {
			if v != SYS_USR { // 广播包不能投递给系统玩家
				send(peer.MQ)
			}
		}
	}

	DEBUG("BROADCAST Delivered to", len(users), "users")
	return nil
}
Beispiel #3
0
//---------------------------------------------------------- p2p send from src_id to dest_id
func Send(src_id, dest_id int32, service int16, multicast bool, object interface{}) (ret bool) {
	if multicast {
		return _multicast(src_id, dest_id, service, object)
	}

	// convert the OBJECT to json, LEVEL-1 encapsulation
	val, err := json.Marshal(object)
	if err != nil {
		log.Println("cannot marshal object to json", err)
		return false
	}

	req := &IPCObject{SrcID: src_id, DestID: dest_id, Service: service, Object: val, Time: time.Now().Unix()}

	// first try local delivery, if dest_id is not in the same server, just forward to HUB server.
	peer := gsdb.QueryOnline(dest_id)
	if peer != nil {
		defer func() {
			if x := recover(); x != nil {
				ret = false
				forward_tbl.Push(req)
			}
		}()

		select {
		case peer.MQ <- *req:
		case <-time.After(time.Second):
			panic("deadlock") // rare case, when both chan is full
		}
		return true
	} else {
		// convert req to json again, LEVEL-2 encapsulation
		return hub_client.Forward(req)
	}
}
Beispiel #4
0
func InspectField(id int32, field string, output io.Writer) {
	fields := strings.Split(field, ".")
	fields = fields[1:]

	sess := gsdb.QueryOnline(id)
	node := reflect.ValueOf(sess).Elem()

	if sess == nil {
		fmt.Fprintln(output, "user offline")
		return
	}

	for _, v := range fields {
		node = node.FieldByName(v)

		switch node.Kind() {
		case reflect.Ptr, reflect.Interface:
			if !node.IsNil() {
				node = node.Elem()
			} else {
				fmt.Fprintln(output, "<nil>")
				return
			}
		}

		if !node.IsValid() {
			fmt.Fprintln(output, "no such field")
			return
		}
	}

	Print(output, node)
}
Beispiel #5
0
//---------------------------------------------------------- 组播
// 发消息到一组**给定的**目标ID
func Multicast(ids []int32, service int16, object interface{}) (ret bool) {
	// object序列化
	val, err := json.Marshal(object)
	if err != nil {
		ERR("cannot marshal object to json", err)
		return false
	}

	// 内容包
	content := &IPCObject{
		Service: service,
		Object:  val,
		Time:    time.Now().Unix(),
	}

	content_json, _ := json.Marshal(content)

	// 封装为Multicast包
	mc := &IPCObject{
		AuxIDs:  ids,
		Service: SYS_MULTICAST,
		Object:  content_json,
		Time:    time.Now().Unix(),
	}

	// 投递到HUB
	hub_client.Forward(mc)

	// 投递到本地SYS_ROUTINE
	peer := gsdb.QueryOnline(SYS_USR)
	peer.MQ <- *mc
	return true
}
Beispiel #6
0
//---------------------------------------------------------- 本地广播一条动态消息
func Localcast(service int16, object interface{}) (ret bool) {
	obj, ok := _create_broadcast_ipcobject(service, object)
	if !ok {
		return false
	}

	// 只投递到本地SYS_ROUTINE
	peer := gsdb.QueryOnline(SYS_USR)
	peer.MQ <- *obj
	return true
}
Beispiel #7
0
//---------------------------------------------------------- 全服广播一条动态消息
func Broadcast(service int16, object interface{}) (ret bool) {
	obj, ok := _create_broadcast_ipcobject(service, object)
	if !ok {
		return false
	}

	// 投递到HUB
	hub_client.Forward(obj)

	// 投递到本地SYS_ROUTINE
	peer := gsdb.QueryOnline(SYS_USR)
	peer.MQ <- *obj
	return true
}
Beispiel #8
0
//---------------------------------------------------------- deliver an IPCObject to a user
func _deliver(obj *IPCObject) {
	sess := gsdb.QueryOnline(obj.DestID)
	if sess != nil {
		func() {
			defer func() {
				if x := recover(); x != nil {
					forward_tbl.Push(obj)
				}
			}()

			sess.MQ <- *obj
		}()
	} else {
		forward_tbl.Push(obj)
	}
}
Beispiel #9
0
//---------------------------------------------------------- 异步消息发送
func Send(src_id, dest_id int32, service int16, object interface{}) (ret bool) {
	// 况序列化被传输对象为json
	val, err := json.Marshal(object)
	if err != nil {
		ERR("cannot marshal object to json", err)
		return false
	}
	// Send函数不能投递到SYS_USR
	if dest_id == SYS_USR {
		ERR("cannot Send to SYS_USR")
		return false
	}

	// 打包为IPCObject
	req := &IPCObject{SrcID: src_id,
		DestID:  dest_id,
		Service: service,
		Object:  val,
		Time:    time.Now().Unix()}

	peer := gsdb.QueryOnline(dest_id)
	if peer != nil { // 如果玩家在本服务器
		// 对方的channel 可能会close, 需要处理panic的情况
		defer func() {
			if x := recover(); x != nil {
				ret = false
				forward_tbl.Push(req)
			}
		}()
		select {
		case peer.MQ <- *req:
		case <-time.After(time.Second):
			panic("deadlock") // rare case, when both chans are full.
		}
		return true
	} else { // 通过HUB转发IPCObject
		return hub_client.Forward(req)
	}

	return false
}
Beispiel #10
0
//----------------------------------------------- receive message from hub
func HubReceiver(conn net.Conn) {
	defer conn.Close()

	header := make([]byte, 2)
	seq_id := make([]byte, 8)

	for {
		// header
		n, err := io.ReadFull(conn, header)
		if n == 0 && err == io.EOF {
			break
		} else if err != nil {
			log.Println("error receiving header:", err)
			break
		}

		// packet seq_id uint32
		n, err = io.ReadFull(conn, seq_id)
		if n == 0 && err == io.EOF {
			break
		} else if err != nil {
			log.Println("error receiving seq_id:", err)
			break
		}

		// read big-endian header
		seqval := binary.BigEndian.Uint64(seq_id)
		size := binary.BigEndian.Uint16(header) - 8
		data := make([]byte, size)
		n, err = io.ReadFull(conn, data)

		if err != nil {
			log.Println("error receiving msg:", err)
			break
		}

		// two kinds of IPC:
		// a). Hub Sends to GS, sequence number is not required (set to 0), just forwarding to session
		// b). Call, sequence number is needed, send will wake up blocking-chan.
		//
		if seqval == 0 {
			obj := &IPCObject{}
			err := json.Unmarshal(data, obj)
			if err != nil {
				log.Println("unable to decode received IPCObject")
				continue
			}

			sess := gsdb.QueryOnline(obj.DestID)
			if sess == nil {
				// if the user is disconnected
				forward_tbl.Push(obj)
			} else {
				func() {
					defer func() {
						if x := recover(); x != nil {
							log.Println("forward: deliver to MQ failed.")
							forward_tbl.Push(obj)
						}
					}()

					sess.MQ <- *obj
				}()
			}
		} else {
			_wait_ack_lock.Lock()
			if ack, ok := _wait_ack[seqval]; ok {
				ack <- data
				delete(_wait_ack, seqval)
			} else {
				log.Printf("Illegal packet sequence number [%x] from HUB", seqval)
			}
			_wait_ack_lock.Unlock()
		}
	}
}
Beispiel #11
0
func Inspect(id int32, output io.Writer) {
	sess := gsdb.QueryOnline(id)
	fmt.Fprintf(output, "%+v\n", sess)
}