Skip to content

Instantly share code, notes, and snippets.

@inhies
Created October 21, 2016 17:09
Show Gist options
  • Select an option

  • Save inhies/2c80924727fa8eba0d5465da6dbef33e to your computer and use it in GitHub Desktop.

Select an option

Save inhies/2c80924727fa8eba0d5465da6dbef33e to your computer and use it in GitHub Desktop.

Revisions

  1. inhies created this gist Oct 21, 2016.
    132 changes: 132 additions & 0 deletions topic.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,132 @@
    package main

    import (
    "log"
    "strings"
    )

    type check struct {
    Sub, Topic string
    ShouldMatch bool
    }

    func main() {
    tests := []check{
    {"myhome/groundfloor/+/temperature", "myhome/groundfloor/livingroom/temperature", true},
    {"myhome/groundfloor/+/temperature", "myhome/groundfloor/kitchen/temperature", true},
    {"myhome/groundfloor/+/temperature", "myhome/groundfloor/kitchen/brightness", false},
    {"myhome/groundfloor/+/temperature", "myhome/firstfloor/kitchen/temperature", false},
    {"myhome/groundfloor/+/temperature", "myhome/groundfloor/kitchen/fridge/temperature", false},

    {"myhome/groundfloor/#", "myhome/groundfloor/livingroom/temperature", true},
    {"myhome/groundfloor/#", "myhome/groundfloor/kitchen/temperature", true},
    {"myhome/groundfloor/#", "myhome/groundfloor/kitchen/brightness", true},
    {"myhome/groundfloor/#", "myhome/firstfloor/kitchen/temperature", false},

    {"a/b/c/d", "a/b/c/d", true},
    {"+/b/c/d", "a/b/c/d", true},
    {"a/+/c/d", "a/b/c/d", true},
    {"a/+/+/d", "a/b/c/d", true},
    {"+/+/+/+", "a/b/c/d", true},

    {"a/b/c", "a/b/c/d", false},
    {"b/+/c/d", "a/b/c/d", false},
    {"+/+/+", "a/b/c/d", false},

    {"#", "a/b/c/d", true},
    {"a/#", "a/b/c/d", true},
    {"a/b/#", "a/b/c/d", true},
    {"a/b/c/#", "a/b/c/d", true},
    {"+/b/c/#", "a/b/c/d", true},

    {"a/+/topic", "a//topic", true},
    {"+/a/topic", "/a/topic", true},
    {"#", "/a/topic", true},
    {"a/topic/+", "a/topic/", true},

    {"a/topic/#", "a/topic/", true},

    {"sport/tennis/player1/#", "sport/tennis/player1", true},
    {"sport/tennis/player1/#", "sport/tennis/player1/ranking", true},
    {"sport/tennis/player1/#", "sport/tennis/player1/score/wimbledon", true},

    {"sport/#", "sport/tennis/player1", true},
    {"sport/tennis/#", "sport/tennis/player1", true},
    {"sport/tennis#", "sport/tennis/player1", false},
    {"sport/tennis/#/ranking", "sport/tennis/player1", false},

    {"sport/tennis/+", "sport/tennis/player1", true},
    {"sport/tennis/+", "sport/tennis/player1/ranking", false},
    {"sport/+", "sport", false},
    {"sport/+", "sport/", true},

    {"+/+", "/finance", true},
    {"/+", "/finance", true},
    {"+", "/finance", false},
    }

    for i, v := range tests {
    if CheckTopic(v.Sub, v.Topic) != v.ShouldMatch {
    log.Fatalf("Failed on %v: %v", i, v)
    }
    }
    }

    // CheckTopic returns true if a message topic satisfies
    // a message subscription.
    func CheckTopic(sub, topic string) bool {
    s := strings.Split(sub, "/")
    t := strings.Split(topic, "/")

    // Check for leading '$' first, becuase we don't want to accidentally
    // match it using a wildcard later. '$' topics are reserved for the
    // broker to use and is not for clients.
    if (sub[0] == '$' && topic[0] != '$') ||
    (topic[0] == '$' && sub[0] != '$') {
    return false
    }

    // Work through the subscription section by section and see if it matches the
    // topic exatly or via wildcards.
    for i := 0; i < len(s) && i < len(t); i++ {
    switch s[i] {
    case "+":
    //Single wildcard, dont need to compare
    continue
    case "#":
    if i < len(s)-1 {
    // Invalid, # is not the last character
    return false
    }
    // Everything after this doesn't matter
    return true
    default:
    if s[i] != t[i] {
    // This section of the topic and subscription
    // dont match, so the topic is not a match for
    // the subscription
    return false

    }
    }
    }

    // If we made it this far, everything has matched so far
    if len(s) == len(t) {
    // Topic and subscription both have the same amount of sections
    // and they all matched so return true.
    return true
    } else {
    // the topic and subscription have a mismatch in the number of
    // sections, but if the last character is this wildcard, then
    // everything will match
    if s[len(s)-1] == "#" {
    return true
    }

    // Either the topic or subscription is longer than the other
    // and the wildcard is not on the end, so they are not a match
    return false
    }

    }