//---------------------------------------------------------- // 组播包 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 }
//---------------------------------------------------------- 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) } }
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) }
//---------------------------------------------------------- 组播 // 发消息到一组**给定的**目标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 }
//---------------------------------------------------------- 本地广播一条动态消息 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 }
//---------------------------------------------------------- 全服广播一条动态消息 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 }
//---------------------------------------------------------- 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) } }
//---------------------------------------------------------- 异步消息发送 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 }
//----------------------------------------------- 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() } } }
func Inspect(id int32, output io.Writer) { sess := gsdb.QueryOnline(id) fmt.Fprintf(output, "%+v\n", sess) }