Skip to content

Commit

Permalink
fix: remove deprecated domain sharding functionality (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
sherwinski authored Jun 14, 2019
1 parent a2e040e commit d91eb78
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 154 deletions.
42 changes: 0 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,45 +43,3 @@ func main() {
```

That's it at a basic level. More fun features though!

### Sharding Hosts
**Warning: Domain Sharding has been deprecated and will be removed in the next major release**<br>
To find out more, see our [blog post](https://blog.imgix.com/2019/05/03/deprecating-domain-sharding) explaining the decision to remove this feature.

This client supports sharding hosts, by CRC or just by Cycle.

**Cycle** is a simple round-robin algorithm. For each request, it picks the
host subsequent to the host for the previous request. Like this:

```go
client := Client{
hosts: []string{"1.imgix.net", "2.imgix.net"},
shardStrategy: imgix.ShardStrategyCycle,
}
client.Host("/myImage.jpg") // => uses 1.imgix.net
client.Host("/myImage.jpg") // => uses 2.imgix.net
client.Host("/myImage.jpg") // => uses 1.imgix.net... and so on.
```

**CRC** uses the CRC32 hashing algorithm paired with the input path to
determine the host. This allows you to ensure that an image request will
always hit the same host. It looks like this:

```go
client := Client{
hosts: []string{"1.imgix.net", "2.imgix.net"},
shardStrategy: imgix.ShardStrategyCRC,
}

// If you have the same path, you'll always get the same host.
client.Host("/myImage.jpg") // => uses 1.imgix.net
client.Host("/myImage.jpg") // => uses 1.imgix.net
client.Host("/myImage.jpg") // => uses 1.imgix.net... and so on.

// Now, a request for another image may find itself with a different host:
client.Host("/1/wedding.jpg") // => uses 2.imgix.net
client.Host("/1/wedding.jpg") // => uses 2.imgix.net
client.Host("/1/wedding.jpg") // => uses 2.imgix.net... and so on.
```

The default sharding is **Cycle**.
87 changes: 14 additions & 73 deletions imgix.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,83 +5,40 @@ import (
"encoding/base64"
"encoding/hex"
"fmt"
"hash/crc32"
"net/url"
"regexp"
"strings"
"unicode/utf8"
)

// Deprecated: Domain Sharding has been deprecated and will be removed in the next major release
type ShardStrategy string

const (
// Deprecated: Domain Sharding has been deprecated and will be removed in the next major release
ShardStrategyCRC = ShardStrategy(":crc")

// Deprecated: Domain Sharding has been deprecated and will be removed in the next major release
ShardStrategyCycle = ShardStrategy(":cycle")
)

// Matches http:// and https://
var RegexpHTTPAndS = regexp.MustCompile("https?://")

// Regexp for all characters we should escape in a URI passed in.
var RegexUrlCharactersToEscape = regexp.MustCompile("([^ a-zA-Z0-9_.-])")

// Create a new Client with the given hosts, with HTTPS enabled.
func NewClient(hosts ...string) Client {
return Client{hosts: hosts, secure: true}
// Create a new Client with the given domain, with HTTPS enabled.
func NewClient(domain string) Client {
return Client{domain: domain, secure: true}
}

// Create a new Client with the given host and token. HTTPS enabled.
func NewClientWithToken(host string, token string) Client {
return Client{hosts: []string{host}, secure: true, token: token}
// Create a new Client with the given domain and token. HTTPS enabled.
func NewClientWithToken(domain string, token string) Client {
return Client{domain: domain, secure: true, token: token}
}

// The Client is used to build URLs.
type Client struct {
hosts []string
token string
secure bool
shardStrategy ShardStrategy

// For use with ShardStrategyCycle
cycleIndex int
}

// The sharding strategy used by this client.
// Panics if the sharding strategy is not supported by this library.
//
// Deprecated: Domain Sharding has been deprecated and will be removed in the next major release
func (c *Client) ShardStrategy() ShardStrategy {
switch c.shardStrategy {
case ShardStrategyCRC, ShardStrategyCycle:
return c.shardStrategy
case "":
c.shardStrategy = ShardStrategyCycle
return c.shardStrategy
default:
panic(fmt.Errorf("shard strategy '%s' is not supported", c.shardStrategy))
}
domain string
token string
secure bool
}

// Returns whether HTTPS should be used.
func (c *Client) Secure() bool {
return c.secure
}

// Returns a host at the given index.
// Panics if there are no hosts.
//
// Deprecated: Domain Sharding has been deprecated and will be removed in the next major release
func (c *Client) Hosts(index int) string {
if len(c.hosts) == 0 {
panic(fmt.Errorf("hosts must be provided"))
}
return c.hosts[index]
}

// Returns the URL scheme to use. One of 'http' or 'https'.
func (c *Client) Scheme() string {
if c.Secure() {
Expand All @@ -91,20 +48,9 @@ func (c *Client) Scheme() string {
}
}

// Returns the host for the given path.
//
// Deprecated: Domain Sharding has been deprecated and will be removed in the next major release
func (c *Client) Host(path string) string {
var host string
switch c.ShardStrategy() {
case ShardStrategyCRC:
host = c.Hosts(c.crc32BasedIndexForPath(path))
case ShardStrategyCycle:
host = c.Hosts(c.cycleIndex)
c.cycleIndex = (c.cycleIndex + 1) % len(c.hosts)
}

return RegexpHTTPAndS.ReplaceAllString(host, "")
// Returns the domain for the given path.
func (c *Client) Domain() string {
return RegexpHTTPAndS.ReplaceAllString(c.domain, "") // Strips out the scheme if exists
}

// Creates and returns the URL signature in the form of "s=SIGNATURE" with
Expand Down Expand Up @@ -132,7 +78,7 @@ func (c *Client) SignatureForPathAndParams(path string, params url.Values) strin
return "s=" + hex.EncodeToString(hasher.Sum(nil))
}

// Builds the full URL to the image (including the host) with no params.
// Builds the full URL to the image (including the domain) with no params.
func (c *Client) Path(imgPath string) string {
return c.PathWithParams(imgPath, url.Values{})
}
Expand All @@ -145,7 +91,7 @@ func (c *Client) Path(imgPath string) string {
func (c *Client) PathWithParams(imgPath string, params url.Values) string {
u := url.URL{
Scheme: c.Scheme(),
Host: c.Host(imgPath),
Host: c.Domain(),
}

urlString := u.String()
Expand Down Expand Up @@ -192,11 +138,6 @@ func (c *Client) PathWithParams(imgPath string, params url.Values) string {
return urlString
}

func (c *Client) crc32BasedIndexForPath(path string) int {
crc := crc32.ChecksumIEEE([]byte(path))
return int(crc) % len(c.hosts)
}

// Base64-encodes a parameter according to imgix's Base64 variant requirements.
// https://docs.imgix.com/apis/url#base64-variants
func base64EncodeParameter(param string) string {
Expand Down
42 changes: 3 additions & 39 deletions imgix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func testClient() Client {
return NewClient("prod.imgix.net", "stag.imgix.net", "dev.imgix.net")
return NewClient("prod.imgix.net")
}

func testClientWithToken() Client {
Expand Down Expand Up @@ -104,42 +104,6 @@ func TestClientFullyQualifiedUrlPathWithParams(t *testing.T) {
assert.Equal(t, "https://my-social-network.imgix.net/http%3A%2F%2Favatars.com%2Fjohn-smith.png?h=300&w=400&s=a201fe1a3caef4944dcb40f6ce99e746", c.PathWithParams("http://avatars.com/john-smith.png", params))
}

func TestClientFallbackShardStrategy(t *testing.T) {
c := testClient()
assert.Equal(t, ShardStrategy(""), c.shardStrategy)
assert.Equal(t, ShardStrategyCycle, c.ShardStrategy())
}

func TestClientHostUsingCRC(t *testing.T) {
c := testClient()
c.shardStrategy = ShardStrategyCRC
assert.Equal(t, "prod.imgix.net", c.Host("/1/users.jpg"))
assert.Equal(t, "dev.imgix.net", c.Host("/2/ellothere.png"))
}

func TestClientHostUsingCycle(t *testing.T) {
c := testClient()
c.shardStrategy = ShardStrategyCycle
assert.Equal(t, "prod.imgix.net", c.Host("/1/users.jpg"))
assert.Equal(t, "stag.imgix.net", c.Host("/1/users.jpg"))
assert.Equal(t, "dev.imgix.net", c.Host("/1/users.jpg"))
assert.Equal(t, "prod.imgix.net", c.Host("/1/users.jpg"))
}

func TestClientShardStrategyValidation(t *testing.T) {
defer func() {
if r := recover(); r != nil {
e, ok := r.(error)
assert.True(t, ok)
assert.EqualError(t, e, "shard strategy 'hellothere' is not supported")
}
}()

c := testClient()
c.shardStrategy = ShardStrategy("hellothere")
c.ShardStrategy()
}

func TestClientHostsCountValidation(t *testing.T) {
defer func() {
if r := recover(); r != nil {
Expand All @@ -150,6 +114,6 @@ func TestClientHostsCountValidation(t *testing.T) {
}()

c := testClient()
c.hosts = []string{}
c.Hosts(1)
c.domain = string("")
c.Domain()
}

0 comments on commit d91eb78

Please sign in to comment.