func decodeCaseACK(c *client.Conn, fields client.Fields, statusCode int, errorText string) (client.Packet, error) { if len(errorText) > 0 { return nil, &client.ServerError{ MessageType: "ack", Origin: c.Origin(), Message: errorText, StatusCode: statusCode, } } return nil, nil }
func decodeServerInvalidACK(c *client.Conn, fields client.Fields, statusCode int, errorText string) (client.Packet, error) { if len(errorText) == 0 { return nil, nil } updates, hasUpdates := fields["updates"].([]interface{}) if !hasUpdates { return nil, &client.IncompleteError{ MessageType: "ack", Origin: c.Origin(), Field: "updates"} } reply := ServerInvalidACK{ Updates: make([]client.Update, len(updates)), StatusCode: statusCode, } for index, field := range updates { var ( update map[string]interface{} channelId string version float64 ok bool ) if update, ok = field.(map[string]interface{}); !ok { return nil, &client.IncompleteError{MessageType: "ack", Origin: c.Origin(), Field: "update"} } if channelId, ok = update["channelID"].(string); !ok { return nil, &client.IncompleteError{MessageType: "ack", Origin: c.Origin(), Field: "channelID"} } if version, ok = update["version"].(float64); !ok { return nil, &client.IncompleteError{MessageType: "ack", Origin: c.Origin(), Field: "version"} } reply.Updates[index] = client.Update{ChannelId: channelId, Version: int64(version)} } return reply, nil }
func decodeUnregisterReply(c *client.Conn, fields client.Fields, statusCode int, errorText string) (client.Packet, error) { if len(errorText) > 0 { return nil, &client.ServerError{"unregister", c.Origin(), errorText, statusCode} } channelId, hasChannelId := fields["channelID"].(string) if !hasChannelId { return nil, &client.IncompleteError{"register", c.Origin(), "channelID"} } reply := ServerUnregister{ StatusCode: statusCode, ChannelId: channelId, } return reply, nil }
func roundTrip(conn *client.Conn, deviceId, channelId, endpoint string, version int64) (err error) { stopChan, errChan := make(chan bool), make(chan error) defer close(stopChan) go func() { err := client.Notify(endpoint, version) if err != nil { err = fmt.Errorf("Error sending update %d on channel %q: %s", version, channelId, err) } select { case <-stopChan: case errChan <- err: } }() go func() { var ( pendingAccepts []client.Update err error ) timeout := time.After(15 * time.Second) for ok := true; ok; { var packet client.Packet select { case ok = <-stopChan: case <-timeout: ok = false err = client.ErrTimedOut case packet, ok = <-conn.Packets: if !ok { err = client.ErrChanClosed break } updates, _ := packet.(client.ServerUpdates) if len(updates) == 0 { continue } pendingAccepts = append(pendingAccepts, updates...) var ( update client.Update hasUpdate bool ) for _, update = range updates { if update.ChannelId == channelId && update.Version >= version { hasUpdate = true break } } if !hasUpdate { continue } ok = false if update.Version != version { err = fmt.Errorf("Wrong update version: got %d; want %d", update.Version, version) break } } } if acceptErr := conn.AcceptBatch(pendingAccepts); acceptErr != nil { err = fmt.Errorf("Error acknowledging updates: %s", acceptErr) } select { case <-stopChan: case errChan <- err: } }() for i := 0; i < 2; i++ { if err := <-errChan; err != nil { return err } } return nil }
func decodeCaseACK(c *client.Conn, fields client.Fields, statusCode int, errorText string) (client.Packet, error) { if len(errorText) > 0 { return nil, &client.ServerError{"ack", c.Origin(), errorText, statusCode} } return nil, nil }
func decodePing(c *client.Conn, fields client.Fields, statusCode int, errorText string) (client.Packet, error) { if len(errorText) > 0 { return nil, &client.ServerError{"ping", c.Origin(), errorText, statusCode} } return ServerPing{statusCode}, nil }