// Perform a B2 API request with the provided request and response objects func (c *B2) apiRequest(apiPath string, request interface{}, response interface{}) error { body, err := ffjson.Marshal(request) if err != nil { return err } defer ffjson.Pool(body) if c.Debug { log.Println("----") log.Printf("apiRequest: %s %s", apiPath, body) } err = c.tryAPIRequest(apiPath, body, response) // Retry after non-fatal errors if b2err, ok := err.(*B2Error); ok { if !b2err.IsFatal() && !c.NoRetry { if c.Debug { log.Printf("Retrying request %q due to error: %v", apiPath, err) } return c.tryAPIRequest(apiPath, body, response) } } return err }
func StartMQTTSender(MQTTServerAddress string, MQTTSendChan chan *lib.PostMessage, channel_name string) chan bool { close_chan := make(chan bool) go func() { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() var post_message *lib.PostMessage var cli *client.Client var err error cli, err = ConnectToMQTTServer(MQTTServerAddress) if err != nil { utils.Log.Println("Connect to MQTT Server failed:", err) return } for { select { case <-close_chan: close_chan <- true utils.Log.Printf("Quit MQTT Sender worker.") return case post_message = <-MQTTSendChan: message_json_buffer, err := ffjson.Marshal(post_message) if err != nil { utils.Log.Println() } err = cli.Publish(&client.PublishOptions{ QoS: mqtt.QoS0, TopicName: []byte(channel_name), Message: []byte(message_json_buffer), }) if err != nil { utils.Log.Println("Publish to MQTT Failed:", err) utils.Log.Println("Try to connect MQTT Server.") cli, err = ConnectToMQTTServer(MQTTServerAddress) if err != nil { utils.Log.Println("Connect to MQTT Server failed:", err) } } utils.Log.Printf("Send message to MQTT Server: %s, Length: %d\n", MQTTServerAddress, len(message_json_buffer)) ffjson.Pool(message_json_buffer) } } }() return close_chan }
func BenchmarkFF_Marshal_L_Pool_Parallel(b *testing.B) { var l int64 for i := 0; i < b.N; i++ { data, err := ffjson.MarshalFast(&xlStructData) if err != nil { b.Error(err) } l = int64(len(data)) ffjson.Pool(data) } b.SetBytes(l) }
// Enqueue adds job to the queue. func (c *Client) Enqueue(queue string, data ...interface{}) error { buf, err := ffjson.Marshal(backJob{Class: queue, Args: data}) if err != nil { return err } rc := c.pool.Get() defer rc.Close() defer ffjson.Pool(buf) _, err = rc.Do("RPUSH", fmt.Sprintf("%vqueue:%v", c.prefix, queue), buf) return err }
func BenchmarkFF_Marshal_S_Pool_Parallel(b *testing.B) { var l int64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { data, err := ffjson.MarshalFast(&smallStructData) if err != nil { b.Error(err) } l = int64(len(data)) ffjson.Pool(data) } }) b.SetBytes(l) }
// send a million documents func ffmillion(w http.ResponseWriter, r *http.Request) { for i := 0; i < 10000000; i++ { docId := i % docs.number item := docs.docMap[docs.docList[docId]] bytes, err := ffjson.Marshal(item) if err != nil { fmt.Fprintf(w, "Failed to marshal document %v", err) return } fmt.Fprintf(w, string(bytes)) // send data to client side fmt.Fprintf(w, "\n\n") ffjson.Pool(bytes) } }
func BenchmarkMarshalJSONNativePool(b *testing.B) { record := newLogFFRecord() buf, err := json.Marshal(&record) if err != nil { b.Fatalf("Marshal: %v", err) } b.SetBytes(int64(len(buf))) b.ResetTimer() for i := 0; i < b.N; i++ { bytes, err := ffjson.MarshalFast(record) if err != nil { b.Fatalf("Marshal: %v", err) } ffjson.Pool(bytes) } }
func OnlineUsersSimpleHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag") var online_users_simple lib.OnlineUsersSimple var channel_name string all_channel.RLock.RLock() defer all_channel.RLock.RUnlock() channel_name = req.Header.Get("channel") channel_name = strings.Trim(channel_name, " ") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } channel := GetChannel(channel_name) online_users_simple.Length = atomic.LoadUint64(&channel.RealUserCount) online_users_simple.Result = 0 buf, err := ffjson.Marshal(online_users_simple) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(buf) ffjson.Pool(buf) }
func SysStatusHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() var key string var channel *Channel var channel_status lib.ChannelStatus var channel_status_reply lib.ChannelStatusReply all_channel.RLock.RLock() defer all_channel.RLock.RUnlock() for key = range all_channel.Channels { channel = all_channel.Channels[key] channel_status.Name = channel.Name channel_status.UserCount = atomic.LoadUint64(&channel.UserCount) channel_status.RealUserCount = atomic.LoadUint64(&channel.RealUserCount) channel_status_reply.Data = append(channel_status_reply.Data, channel_status) } if len(channel_status_reply.Data) == 0 { channel_status_reply.Result = 0 channel_status_reply.Data = []lib.ChannelStatus{} } buf, err := ffjson.Marshal(channel_status_reply) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s]\n", req.RemoteAddr, err) http.Error(w, "Marshal json failed", 500) return } w.Header().Set("Content-Type", "application/json") w.Write(buf) ffjson.Pool(buf) }
func OnlineUsersHandlerWithTag(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag") var channel_name string var user_state_tag_map *lib.OnlineUsersWithTag var ok bool channel_name = req.Header.Get("channel") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } channel := GetChannel(channel_name) channel.OnlineUsersLock.RLock() general_online_users := channel.GeneralOnlineUsersPool.Get().(*lib.GeneralOnlineUsers) temp_tag_map := general_online_users.UserTags for username := range channel.OnlineUsers { state := channel.OnlineUsers[username] if ServerDebug { utils.Log.Printf("/api/users/tags: got state: %v\n", state) } if user_state_tag_map, ok = temp_tag_map[state.Tag]; !ok { user_state_tag_map = channel.OnlineUsersTagPool.Get().(*lib.OnlineUsersWithTag) temp_tag_map[state.Tag] = user_state_tag_map } temp_tag_map[state.Tag].Length += 1 temp_tag_map[state.Tag].UserList = append(temp_tag_map[state.Tag].UserList, username) } channel.OnlineUsersLock.RUnlock() general_online_users.Result = 0 general_online_users.UserTags = temp_tag_map general_online_users.Timestamp = time.Now().Unix() buf, err := ffjson.Marshal(general_online_users) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(buf) ffjson.Pool(buf) for key := range general_online_users.UserTags { general_online_users.UserTags[key].Length = 0 general_online_users.UserTags[key].UserList = make([]string, 0) channel.OnlineUsersTagPool.Put(general_online_users.UserTags[key]) // delete is safe // because we put general_online_users into pool in the below delete(general_online_users.UserTags, key) } channel.GeneralOnlineUsersPool.Put(general_online_users) }
func OnlineUsersHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() var online_users lib.OnlineUsers var channel_name string var user *User var key string var now int64 w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag") channel_name = req.Header.Get("channel") channel_name = strings.Trim(channel_name, " ") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } channel := GetChannel(channel_name) if USE_FASE_ONLINE_MAP == false { channel.ChannelRLock.RLock() channel_user_length := len(channel.Users) if channel_user_length > 0 { for key = range channel.Users { now = time.Now().Unix() user = channel.Users[key] if now-user.LastUpdate < DELAY_USER_ONLINE { online_users.UserList = append(online_users.UserList, key) } } if len(online_users.UserList) == 0 { online_users.UserList = []string{} } } else { online_users.UserList = []string{} } channel.ChannelRLock.RUnlock() } else { channel.OnlineUsersLock.RLock() for key = range channel.OnlineUsers { online_users.UserList = append(online_users.UserList, key) } channel.OnlineUsersLock.RUnlock() } online_users.Result = 0 online_users.Length = len(online_users.UserList) if online_users.Length == 0 { online_users.UserList = []string{} } buf, err := ffjson.Marshal(online_users) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(buf) ffjson.Pool(buf) }
func OnlineUsersSimpleHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag") var online_users_simple lib.OnlineUsersSimple var channel_name string var mqtt_users lib.MQTTSingleTopicUsers all_channel.RLock.RLock() defer all_channel.RLock.RUnlock() channel_name = req.Header.Get("channel") channel_name = strings.Trim(channel_name, " ") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } if Config.MQTTServerEnable == true { resp, err := http.Get("http://" + Config.MQTTServerAddress + ":18088/api/simple_topic/" + channel_name) if resp != nil { defer resp.Body.Close() } if err != nil { utils.Log.Printf("[%s] Get MQTT online users failed: %s, channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "failed to get MQTT users", 500) return } body, err := ioutil.ReadAll(resp.Body) if err != nil { utils.Log.Printf("[%s] Read MQTT response failed: %s, channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "read MQTT users failed", 500) return } err = json.Unmarshal(body, &mqtt_users) if err != nil { utils.Log.Printf("[%s] Unmarshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Unmarshal json failed", 500) return } online_users_simple.Length = mqtt_users.Length } channel := GetChannel(channel_name) online_users_simple.Length += atomic.LoadUint64(&channel.RealUserCount) online_users_simple.Result = 0 buf, err := ffjson.Marshal(online_users_simple) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(buf) ffjson.Pool(buf) }
// 处理POST消息 func MessagePostHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() var channel_name string var channel *Channel var err error var buf []byte w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag") w.Header().Set("Access-Control-Allow-Credentials", "true") channel_name = req.Header.Get("channel") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } // use byte pool buffer := byte_pool.Checkout() defer buffer.Close() buffer.ReadFrom(req.Body) body := buffer.Bytes() channel = GetChannel(channel_name) //post_message := channel.PostMessagePool.Get().(*lib.PostMessage) post_message := new(lib.PostMessage) err = ffjson.Unmarshal(body, post_message) if err != nil { utils.Log.Printf("[%s] Unmarshal json failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Unmarshal json failed", 500) return } if channel.PrepareClose == true { utils.Log.Printf("[%s] Channel: [%s] will be closed.\n", req.RemoteAddr, channel_name) http.Error(w, "channel will be closed or not exists", 500) return } message_id := utils.MakeRandomID() post_message.MessageID = message_id send_finished := false if post_message.Delay == 0 { send_finished = PostMessage(channel, post_message) } else { go PostMessage(channel, post_message) send_finished = true } post_reply := channel.PostReplyPool.Get().(*lib.PostReply) if send_finished { post_reply.Result = 0 post_reply.MessageID = message_id } else { post_reply.Result = 1 post_reply.MessageID = "message buffer of channel is full." } buf, err = ffjson.Marshal(*post_reply) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } if ServerDebug { utils.Log.Printf("Got message from [%s], message: [%s], message_id: [%s], channel: [%s]\n", req.RemoteAddr, string(body), message_id, channel_name) } w.Header().Set("Content-Type", "application/json") w.Write(buf) channel.PostReplyPool.Put(post_reply) ffjson.Pool(buf) }
// 处理Poll消息 func MessagePollHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() var channel_name string var user_id string var err error var message_list []*lib.PostMessage w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag, token, versionCode, appId") channel_name = req.Header.Get("channel") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } user_id = req.Header.Get("tourid") user_id = strings.Trim(user_id, " ") if user_id == "" { utils.Log.Printf("[%s] user_id not in header\n", req.RemoteAddr) http.Error(w, "user_id name not in header", 400) return } // support for multipoint login //user_id = user_id + ":" + utils.MakeRandomID() user_tag := req.Header.Get("tag") user_tag = strings.Trim(user_tag, " ") if user_tag == "" { user_tag = "UNKNOW" utils.Log.Printf("[%s] user_tag not in header\n", req.RemoteAddr) } if ServerDebug { utils.Log.Printf("Client [%s]: User [%s] with tag [%s]\n", req.RemoteAddr, user_id, user_tag) } wait := req.Header.Get("wait") wait = strings.Trim(wait, " ") channel := GetChannel(channel_name) if channel.PrepareClose == true { utils.Log.Printf("[%s] Channel: [%s] will be closed.\n", req.RemoteAddr, channel_name) http.Error(w, "channel will be closed", 500) return } user, err := channel.GetUser(user_id) if err != nil { user, err = channel.AddUser(user_id, user_tag) if err != nil { utils.Log.Printf("[%s] AddUser failed: [%s]\n", req.RemoteAddr, err) } } // if no new message, we wait for it if wait == "yes" { if user.NotifyChan != nil { select { case <-wheel_seconds.After(time.Duration(POLL_WAIT_TIME) * time.Second): case <-user.NotifyChan: } } } message_list_size := 0 user.SpinLock.Lock() if user.MessageBuffer != nil { for i := 0; i < Config.PollMessageSize; i++ { if user.MessageBuffer.Len() == 0 { break } e := user.MessageBuffer.Front() if e != nil { if post_message, ok := user.MessageBuffer.Remove(e).(*lib.PostMessage); ok { if atomic.LoadUint64(&post_message.Count) > 0 { // got message, decrement message reference count message_list = append(message_list, post_message) message_list_size += 1 atomic.AddUint64(&post_message.Count, ^uint64(0)) if atomic.LoadUint64(&post_message.Count) == 0 { // delete message in channel's global message cache post_message.Lock.Lock() delete(channel.MessageCache, post_message.MessageID) post_message.Lock.Unlock() } } } } } } // update user's tag when tag was changed if CHANGE_USER_STATE_IN_REAL_TIME && user_tag != "" { if user_tag != user.Tag || user.Tag == "" { if ServerDebug { utils.Log.Printf("Change user [%s] tag %s->%s\n", user_id, user.Tag, user_tag) } state := channel.UserStatePool.Get().(*UserState) state.ID = user_id state.Tag = user_tag state.State = true state.From = 1 channel.UserStateChan <- state } user.Tag = user_tag } user.LastUpdate = time.Now().Unix() user.SpinLock.Unlock() poll_message := channel.PollMessagePool.Get().(*lib.PollMessage) poll_message.Result = 0 poll_message.MessageLength = len(message_list) if len(message_list) == 0 { poll_message.MessageList = []*lib.PostMessage{} } else { poll_message.MessageList = message_list } buf, err := ffjson.Marshal(*poll_message) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } if ServerDebug == true { utils.Log.Printf("Send message to [%s], message: [%s], channel: [%s], user_id: [%s]\n", req.RemoteAddr, string(buf), channel_name, user_id) } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(buf) /* for idx := range message_list { channel.PostMessagePool.Put(message_list[idx]) } */ channel.PollMessagePool.Put(poll_message) ffjson.Pool(buf) }
func MessageDeleteHandler(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { utils.Log.Println(err) debug.PrintStack() } }() var channel_name string var user_id string var delete_message_reply lib.DeleteMessageReply w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "channel, tourid, tag, token, versionCode, appId") channel_name = req.Header.Get("channel") if channel_name == "" { utils.Log.Printf("[%s] channel name not in header\n", req.RemoteAddr) http.Error(w, "channel name not in header", 400) return } user_id = req.Header.Get("tourid") if user_id == "" { utils.Log.Printf("[%s] user_id not in header\n", req.RemoteAddr) http.Error(w, "user_id name not in header", 400) return } user_tag := req.Header.Get("tag") user_tag = strings.Trim(user_tag, " ") if user_tag == "" { user_tag = "UNKNOW" utils.Log.Printf("[%s] user: [%s] user_tag not in header\n", req.RemoteAddr, user_id) } if ServerDebug { utils.Log.Printf("Client [%s]: User [%s] with tag [%s]\n", req.RemoteAddr, user_id, user_tag) } channel := GetChannel(channel_name) user, err := channel.GetUser(user_id) if err != nil { user, err = channel.AddUser(user_id, user_tag) if err != nil { utils.Log.Printf("[%s] AddUser failed: [%s]\n", req.RemoteAddr, err) } } user.SpinLock.Lock() if user.MessageBuffer != nil { decr_message_ref(channel, user.MessageBuffer) user.MessageBuffer = user.MessageBuffer.Init() } // update user's tag when tag was changed if CHANGE_USER_STATE_IN_REAL_TIME && user_tag != "" { if user_tag != user.Tag || user.Tag == "" { if ServerDebug { utils.Log.Printf("Change user [%s] tag %s->%s\n", user_id, user.Tag, user_tag) } state := channel.UserStatePool.Get().(*UserState) state.ID = user_id state.Tag = user_tag state.State = true state.From = 1 channel.UserStateChan <- state } user.Tag = user_tag } user.SpinLock.Unlock() delete_message_reply.Result = 0 buf, err := ffjson.Marshal(delete_message_reply) if err != nil { utils.Log.Printf("[%s] Marshal JSON failed: [%s], channel: [%s]\n", req.RemoteAddr, err, channel_name) http.Error(w, "Marshal json failed", 500) return } message_buffer_len := user.MessageBuffer.Len() if ServerDebug == true { utils.Log.Printf("Delete message for [%s], channel: [%s], user_id: [%s], length: [%d]\n", req.RemoteAddr, channel_name, user_id, message_buffer_len) } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(buf) ffjson.Pool(buf) }