// Subscribe registers handler to be invoked on any event that matches prefix topicPrefix. // // The handlers registered with Subscribe are invoked asynchronously using go when an event // matching the relevant prefix is received. func (exchange *Exchange) Subscribe(topicPrefix Topic, handler EventHandler) (Handle, error) { exchange.cond.L.Lock() defer exchange.cond.L.Unlock() if exchange.state != stateRunning { return 0, ErrInvalidState } handle, err := exchange.getHandle(topicPrefix) if err != nil { return 0, err } record := &handlerRecord{ handle: handle, handler: handler, } if item := exchange.trie.Get(patricia.Prefix(topicPrefix)); item == nil { records := []*handlerRecord{record} exchange.trie.Insert(patricia.Prefix(topicPrefix), &records) } else { records := item.(*[]*handlerRecord) *records = append(*records, record) } return record.handle, nil }
// MkPath makes a new directory under the current rootPath. The path variable // is expected to be relative to the rootPath. The diectory will both be added // to the internal representation AND be added to the real filesystem. Fails // if the specified path is a file, returns nil if the specified path already // exists. func (fs *TransientFilesystem) MkPath(path string) error { absPath := realPath(fs, path) // actually make path if absPath == fs.RootPath() { return nil } fi, err := os.Stat(absPath) if err != nil && !os.IsNotExist(err) { return ErrFileNoExist } if fi != nil && !fi.IsDir() { return ErrFileExists } doTrieGet := func() (bool, error) { fs.lock.RLock() defer fs.lock.RUnlock() if fs.trie.Match(trie.Prefix(absPath)) { if fs.trie.Get(trie.Prefix(absPath)).(os.FileInfo).IsDir() { return true, nil } else { return false, fmt.Errorf("specified path %s exists in memory as a file, but does not exist on disk", path) } } return false, nil } existsInMem, err := doTrieGet() if err != nil { return err } else if existsInMem { return nil } if err = os.MkdirAll(absPath, 0755); err != nil { return err } fi, err = os.Stat(absPath) if err != nil { return err } // insert into trie insertIntoTrie := func() error { fs.lock.Lock() defer fs.lock.Unlock() if success := fs.trie.Insert(trie.Prefix(absPath), fi); !success { return fmt.Errorf("path %s already exists in memory", path) } return nil } if err := insertIntoTrie(); err != nil { // recover if rmErr := os.RemoveAll(absPath); rmErr != nil { // wow this is bad, failure inserting into the trie, AND failure // cleaning up after ourselves return fmt.Errorf("failure creating path %s in memory: %s, and failure cleaning up alrready created path %s: %s", path, err.Error(), path, rmErr.Error()) } return err } return nil }
func main() { key := flag.String("key", "", "key in dot notation") version := flag.Bool("v", false, "show version and exit") flag.Parse() if *version { fmt.Println(Version) os.Exit(0) } if *key == "" { log.Fatal("key is required") } var reader *bufio.Reader if flag.NArg() < 1 { reader = bufio.NewReader(os.Stdin) } else { file, err := os.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } defer file.Close() reader = bufio.NewReader(file) } trie := patricia.NewTrie() for { line, err := reader.ReadString('\n') if err == io.EOF { break } if err != nil { log.Fatal(err) } doc := make(map[string]interface{}) err = json.Unmarshal([]byte(line), &doc) if err != nil { log.Fatal(err) } val, err := StringValue(*key, doc) if err != nil { log.Fatal(err) } if trie.Match(patricia.Prefix(val)) { log.Println("SKIP") continue } b, err := json.Marshal(doc) if err != nil { log.Fatal(err) } trie.Insert(patricia.Prefix(val), 1) fmt.Println(string(b)) } }
func (lm *LocationMuxer) longestMatchingPath(path string) *types.Location { pathAsPrefix := patricia.Prefix(path) var matchSoFar patricia.Prefix var matchedItem *types.Location err := lm.locationTrie.Visit(func(prefix patricia.Prefix, item patricia.Item) error { if len(prefix) > len(pathAsPrefix) { return patricia.SkipSubtree } else if len(prefix) > len(matchSoFar) && bytes.EqualFold(prefix, pathAsPrefix[:len(prefix)]) { exactMatch := len(prefix) == len(pathAsPrefix) matchedLocation := item.(*types.Location) if isLocationType(matchedLocation, exact) && !exactMatch { return nil } matchedItem = matchedLocation matchSoFar = prefix if exactMatch { return errExactMatch // not an error, just so the search is canceled } } return nil }) if err != nil && err != errExactMatch { panic(err) // an impossible error } return matchedItem }
// Get retrieves an ID from the TruncIndex. If there are multiple IDs // with the given prefix, an error is thrown. func (idx *TruncIndex) Get(s string) (string, error) { if s == "" { return "", ErrEmptyPrefix } var ( id string ) subTreeVisitFunc := func(prefix patricia.Prefix, item patricia.Item) error { if id != "" { // we haven't found the ID if there are two or more IDs id = "" return ErrAmbiguousPrefix } id = string(prefix) return nil } idx.RLock() defer idx.RUnlock() if err := idx.trie.VisitSubtree(patricia.Prefix(s), subTreeVisitFunc); err != nil { return "", err } if id != "" { return id, nil } return "", fmt.Errorf("no such id: %s", s) }
// MkFile makes a file consisting of the provided content at the given path. // If the path does not already exist, an error will be returned. If the file // already exists, an error will be returned. func (fs *TransientFilesystem) MkFile(path string, content []byte) error { if !fs.PathExists(filepath.Dir(path)) { return ErrPathNoExist } else if fs.PathExists(path) { return ErrFileExists } absPath := realPath(fs, path) if err := ioutil.WriteFile(absPath, content, 0644); err != nil { return err } doInsertTrie := func() error { fs.lock.Lock() defer fs.lock.Unlock() fi, err := os.Stat(absPath) if err != nil { return err } if success := fs.trie.Insert(trie.Prefix(absPath), fi); !success { // path already exists in trie if err := os.RemoveAll(absPath); err != nil { // this is bad return fmt.Errorf("file %s already exists in memory and error removing file %s: %s", path, path, err) } // technically this is a little misleading, as it refers to the // trie, not what's on disk, but c'est la vie return ErrFileExists } return nil } if err := doInsertTrie(); err != nil { return err } return nil }
// RmPath recursively removes a path from the filesystem. The path argument // can be either a file or directory relative to the rootPath. Returns an // error if the path does not exist, or if there was an error removing // part of the path. func (fs *TransientFilesystem) RmPath(path string) error { absPath := realPath(fs, path) switch path { case "/", "": return fmt.Errorf("unwilling to delete root filesystem path %s", fs.RootPath()) default: } doGet := func() interface{} { fs.lock.RLock() defer fs.lock.RUnlock() return fs.trie.Get(trie.Prefix(absPath)) } item := doGet() if item == nil { return ErrPathNoExist } if !item.(os.FileInfo).IsDir() { return ErrFileExists } // Make this a function so we can release the mutex ASAP doTrieDelete := func() error { fs.lock.Lock() defer fs.lock.Unlock() if deleted := fs.trie.Delete(trie.Prefix(absPath)); !deleted { return fmt.Errorf("path %s does not exist in memory", path) } return nil } if err := doTrieDelete(); err != nil { return err } if err := os.RemoveAll(absPath); err != nil { // put item back in the tree // eat the error here fs.trie.Insert(trie.Prefix(absPath), item) // possibly in an unknown state at this point. whomp whomp. return err } return nil }
// Delete removes an ID from the TruncIndex. If there are multiple IDs // with the given prefix, an error is thrown. func (idx *TruncIndex) Delete(id string) error { idx.Lock() defer idx.Unlock() if _, exists := idx.ids[id]; !exists || id == "" { return fmt.Errorf("no such id: '%s'", id) } delete(idx.ids, id) if deleted := idx.trie.Delete(patricia.Prefix(id)); !deleted { return fmt.Errorf("no such id: '%s'", id) } return nil }
func LoadDictionaries() { var newDictionaryMap = make(map[string]*patricia.Trie) var itemMap = ImportDictionaries() numPrefixes := 0 numSuggestions := 0 numDictionaries := 0 for dictionaryName, suggestItems := range itemMap { numDictionaries++ log.Print("Loading dictionary " + dictionaryName) // First see if the trie already exists var trie, ok = newDictionaryMap[dictionaryName] if !ok { trie = patricia.NewTrie() } // Great, we have a trie, now let's see if prefixes for the // suggestItems exist in the trie for _, suggestItem := range suggestItems { numSuggestions++ //Tokenize the suggested term by whitespace. Each token will become a prefix in the trie var tokens = strings.Fields(suggestItem.Term) tokens = append(tokens, suggestItem.Term) for _, token := range tokens { numPrefixes++ //TODO: use ascii folding lowerToken := strings.ToLower(token) // The values in the trie are sorted sets of SuggestItems trieItem := trie.Get([]byte(lowerToken)) if trieItem != nil { suggestItemSet := trieItem.(treeset.Set) //If the set already exists, add the new suggestion to the set suggestItemSet.Add(suggestItem) } else { // Otherwise create a new set, add the SuggestItem, and insert it into // the trie using the lowercase token for the prefix suggestItemSet := treeset.NewWith(models.SuggestItemComparator) // log.Printf("Inserting suggestion item %s (%s)", lowerToken, suggestItem.Term) suggestItemSet.Add(suggestItem) trie.Insert(patricia.Prefix([]byte(lowerToken)), *suggestItemSet) } } } newDictionaryMap[dictionaryName] = trie log.Print("Dictionary " + dictionaryName + " loaded") } //Atomic swap DictionaryMap = newDictionaryMap log.Printf("All dictionaries updated") }
// NewDefaultRouter creates a very basic WAMP router. func NewNode() Router { log.Println("Creating new Rabric Node") trie := patricia.NewTrie() r := &Realm{URI: "pd"} trie.Insert(patricia.Prefix("pd"), r) return &node{ realms: make(map[URI]Realm), sessionOpenCallbacks: []func(uint, string){}, sessionCloseCallbacks: []func(uint, string){}, root: trie, } }
// Unsubscribe cancels the event handler represented by handle. func (exchange *Exchange) Unsubscribe(handle Handle) error { exchange.cond.L.Lock() defer exchange.cond.L.Unlock() if exchange.state != stateRunning { return ErrInvalidState } topic, ok := exchange.topicForHandle[handle] if !ok { return ErrInvalidHandle } delete(exchange.topicForHandle, handle) item := exchange.trie.Get(patricia.Prefix(topic)) if item == nil { return ErrInvalidHandle } records := item.(*[]*handlerRecord) if len(*records) == 1 { if exchange.trie.Delete(patricia.Prefix(topic)) { return nil } } else { for i, record := range *records { if record.handle == handle { *records = append((*records)[:i], (*records)[i+1:]...) return nil } } } return ErrInvalidHandle }
func (suite *TheSuite) TestTransientFilesystemerCreate(c *C) { fileMap := suite.mkDirs(c, suite.tmpdir) fs := suite.mkTFS() c.Assert(fs.trie.Get(trie.Prefix("aaaaaaaaaaa")), IsNil) c.Assert(fs.trie.Get(trie.Prefix(fs.rootPath)), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["d1"])), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["f1"])), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["f2"])), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["f3"])), NotNil) }
func (idx *TruncIndex) addID(id string) error { if strings.Contains(id, " ") { return ErrIllegalChar } if id == "" { return ErrEmptyPrefix } if _, exists := idx.ids[id]; exists { return fmt.Errorf("id already exists: '%s'", id) } idx.ids[id] = struct{}{} if inserted := idx.trie.Insert(patricia.Prefix(id), struct{}{}); !inserted { return fmt.Errorf("failed to insert id: %s", id) } return nil }
func (idx *TruncIndex) addId(id string) error { if strings.Contains(id, " ") { return fmt.Errorf("Illegal character: ' '") } if id == "" { return ErrNoID } if _, exists := idx.ids[id]; exists { return fmt.Errorf("Id already exists: '%s'", id) } idx.ids[id] = struct{}{} if inserted := idx.trie.Insert(patricia.Prefix(id), struct{}{}); !inserted { return fmt.Errorf("Failed to insert id: %s", id) } return nil }
// GetFile gets the file at path and returns a FSFiler object, which both // describes the file and has a pointer to a copy of the file in a byte slice. // If the files does not exist or path is actually a directory, an error is returned. func (fs *TransientFilesystem) GetFile(path string) (FSFiler, error) { absPath := realPath(fs, path) if !fs.PathExists(path) { return nil, ErrFileNoExist } else if fi, err := os.Stat(realPath(fs, path)); err != nil || fi.IsDir() { if err != nil { return nil, err } return nil, fmt.Errorf("Specified path %s is a directory", realPath(fs, path)) } item := fs.trie.Get(trie.Prefix(absPath)) if item == nil { return nil, ErrPathNoExist } fi, _ := os.Stat(realPath(fs, path)) return &FSFile{FileInfo: fi, absPath: absPath}, nil }
func (suite *TheSuite) TestTransientFilesystem_Sync(c *C) { fs := suite.mkTFS() fileMap := suite.mkDirs(c, suite.tmpdir) if err := fs.Sync(); err != nil { c.Error(err) } c.Assert(fs.trie.Get(trie.Prefix("aaaaaaaaaaa")), IsNil) c.Assert(fs.trie.Get(trie.Prefix(fs.rootPath)), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["d1"])), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["f1"])), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["f2"])), NotNil) c.Assert(fs.trie.Get(trie.Prefix(fileMap["f3"])), NotNil) }
// Publish can be used for inserting the events into the exchange. // // This methods triggers all the relevant handlers and runs them in separate // goroutines. func (exchange *Exchange) Publish(topic Topic, event Event) error { exchange.mu.RLock() if exchange.state != stateRunning { return ErrInvalidState } exchange.trie.VisitPrefixes( patricia.Prefix(topic), func(prefix patricia.Prefix, item patricia.Item) error { for _, record := range *(item.(*[]*handlerRecord)) { exchange.runHandler(record.handler, topic, event) } return nil }) exchange.mu.RUnlock() return nil }
// Sync brings the in-memory struct and underlying file system into sync. // Walk the entire tree and recreate it from scratch. func (fs *TransientFilesystem) Sync() error { newTrie := trie.NewTrie() err := filepath.Walk(fs.RootPath(), func(path string, info os.FileInfo, err error) error { if err != nil { return err } fi, err := os.Stat(path) if err != nil { return err } if !newTrie.Insert(trie.Prefix(path), fi) { return fmt.Errorf("Path %s already exists in tree", path) } return nil }) if err != nil { return err } fs.lock.Lock() defer fs.lock.Unlock() fs.trie = newTrie return nil }
func (_ Test) Patricia() { e.InfoLog.Println("\nPatricia:") printItem := func(prefix patricia.Prefix, item patricia.Item) error { e.InfoLog.Println(string(prefix), item.(uint32)) return nil } trie := patricia.NewTrie() for i := range ExampleWords { trie.Insert(patricia.Prefix(ExampleWords[i]), ExampleUint32[i]) } trie.Set(patricia.Prefix("coca cola"), 188) e.InfoLog.Println("SubTree:") trie.VisitSubtree(patricia.Prefix("blost"), printItem) e.InfoLog.Println("Prefixes:") trie.VisitPrefixes(patricia.Prefix("borte med blesten mega"), printItem) trie.Delete(patricia.Prefix("coca cola")) trie.DeleteSubtree(patricia.Prefix("blost")) e.InfoLog.Println("What is left:") trie.Visit(printItem) }
func TwoCentsHandlerV1(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) dictionaryName := vars["dictionary"] limit := 10 limitParam := vars["limit"] if limitParam != "" { limit, _ = strconv.Atoi(limitParam) } //case-insensitive filter filter := vars["filter"] if filter != "" { filter = strings.ToLower(filter) } dictionaryTrie, found := DictionaryMap[dictionaryName] if !found { http.NotFound(w, r) return } //TODO: use ascii folding query := vars["query"] /* The values in the patricia-trie are sets of SuggestItems. patricia-trie won't return the list of nodes for you, but will invoke a function on all visited nodes. This []treeset.Set will hold the results of the visited nodes. visitorFunc will actually add those sets to that array. */ trieItems := []treeset.Set{} visitorFunc := func(prefix patricia.Prefix, item patricia.Item) error { trieItems = append(trieItems, item.(treeset.Set)) return nil } dictionaryTrie.VisitSubtree(patricia.Prefix([]byte(strings.ToLower(query))), visitorFunc) /* This set will hold the SuggestItems we pull from the front of every set retrieve from the patricia-trie. Since it's tree set, the items are sorted using the SuggestItemComparator, which compares by weight and string, guaranteeing the items within a set are ordered */ collatedSuggestionSet := treeset.NewWith(models.SuggestItemComparator) //If there were fewer suggestions than the requested limit, lower the limit totalSuggestions := 0 for _, suggestionSetItem := range trieItems { totalSuggestions += suggestionSetItem.Size() } if totalSuggestions < limit { limit = totalSuggestions } /* The results from the patrica-trie visit are all sorted sets. However, they're only sorted within the set. Since we know that they're in weight-descending order, we can reliably pick the first element from each set, and insert them into another sorted result set. After <limit> iterations, we're guaranteed to have the top weighted items in weight-descending order, and we only need to slice the array */ finalSuggestionSetPosition := 0 for finalSuggestionSetPosition < limit && collatedSuggestionSet.Size() < limit { for _, suggestionSetItem := range trieItems { if suggestionSetItem.Size() > finalSuggestionSetPosition { thisItem := suggestionSetItem.Values()[finalSuggestionSetPosition].(*models.SuggestItem) //case-insensitive filter if filter != "" { if strings.Contains(strings.ToLower(thisItem.Term), filter) { collatedSuggestionSet.Add(thisItem) } } else { collatedSuggestionSet.Add(thisItem) } } } finalSuggestionSetPosition++ } if len(collatedSuggestionSet.Values()) < limit { limit = len(collatedSuggestionSet.Values()) } suggestions := []string{} for _, suggestion := range collatedSuggestionSet.Values()[0:limit] { suggestions = append(suggestions, suggestion.(*models.SuggestItem).Term) } t := TwoCentsV1{ Suggestions: suggestions, } j, _ := json.Marshal(t) w.Header().Set("Content-Type", "application/json; charset=utf-8") if AllowedOrigin != "" { w.Header().Set("Access-Control-Allow-Origin", AllowedOrigin) } w.Write(j) }
func dodiffRecursive(firstClnt, secondClnt client.Client, ch chan DiffMessage) { firstTrie := patricia.NewTrie() secondTrie := patricia.NewTrie() wg := new(sync.WaitGroup) type urlAttr struct { Size int64 Type os.FileMode } wg.Add(1) go func(ch chan<- DiffMessage) { defer wg.Done() for firstContentCh := range firstClnt.List(true) { if firstContentCh.Err != nil { ch <- DiffMessage{ Error: firstContentCh.Err.Trace(firstClnt.URL().String()), } return } firstTrie.Insert(patricia.Prefix(firstContentCh.Content.Name), urlAttr{firstContentCh.Content.Size, firstContentCh.Content.Type}) } }(ch) wg.Add(1) go func(ch chan<- DiffMessage) { defer wg.Done() for secondContentCh := range secondClnt.List(true) { if secondContentCh.Err != nil { ch <- DiffMessage{ Error: secondContentCh.Err.Trace(secondClnt.URL().String()), } return } secondTrie.Insert(patricia.Prefix(secondContentCh.Content.Name), urlAttr{secondContentCh.Content.Size, secondContentCh.Content.Type}) } }(ch) doneCh := make(chan struct{}) defer close(doneCh) go func(doneCh <-chan struct{}) { cursorCh := cursorAnimate() for { select { case <-time.Tick(100 * time.Millisecond): if !globalQuietFlag && !globalJSONFlag { console.PrintC("\r" + "Scanning.. " + string(<-cursorCh)) } case <-doneCh: return } } }(doneCh) wg.Wait() doneCh <- struct{}{} if !globalQuietFlag && !globalJSONFlag { console.Printf("%c[2K\n", 27) console.Printf("%c[A", 27) } matchNameCh := make(chan string, 10000) go func(matchNameCh chan<- string) { itemFunc := func(prefix patricia.Prefix, item patricia.Item) error { matchNameCh <- string(prefix) return nil } firstTrie.Visit(itemFunc) defer close(matchNameCh) }(matchNameCh) for matchName := range matchNameCh { firstURLDelimited := firstClnt.URL().String()[:strings.LastIndex(firstClnt.URL().String(), string(firstClnt.URL().Separator))+1] secondURLDelimited := secondClnt.URL().String()[:strings.LastIndex(secondClnt.URL().String(), string(secondClnt.URL().Separator))+1] firstURL := firstURLDelimited + matchName secondURL := secondURLDelimited + matchName if !secondTrie.Match(patricia.Prefix(matchName)) { ch <- DiffMessage{ FirstURL: firstURL, SecondURL: secondURL, Diff: "only-in-first", } } else { firstURLAttr := firstTrie.Get(patricia.Prefix(matchName)).(urlAttr) secondURLAttr := secondTrie.Get(patricia.Prefix(matchName)).(urlAttr) if firstURLAttr.Type.IsRegular() { if !secondURLAttr.Type.IsRegular() { ch <- DiffMessage{ FirstURL: firstURL, SecondURL: secondURL, Diff: "type", } continue } } if firstURLAttr.Type.IsDir() { if !secondURLAttr.Type.IsDir() { ch <- DiffMessage{ FirstURL: firstURL, SecondURL: secondURL, Diff: "type", } continue } } if firstURLAttr.Size != secondURLAttr.Size { ch <- DiffMessage{ FirstURL: firstURL, SecondURL: secondURL, Diff: "size", } } } } }
func (r *node) Accept(client Peer) error { log.Println("Accepting a new connection from ", client) if r.closing { logErr(client.Send(&Abort{Reason: ErrSystemShutdown})) logErr(client.Close()) return fmt.Errorf("Router is closing, no new connections are allowed") } msg, err := GetMessageTimeout(client, 5*time.Second) if err != nil { return err } // pprint the incoming details if b, err := json.MarshalIndent(msg, "", " "); err != nil { fmt.Println("error:", err) } else { log.Printf("%s: %+v", msg.MessageType(), string(b)) } // log.Printf("%s: %+v", msg.MessageType(), msg) hello, _ := msg.(*Hello) // Ensure the message is valid and well constructed if _, ok := msg.(*Hello); !ok { logErr(client.Send(&Abort{Reason: URI("wamp.error.protocol_violation")})) logErr(client.Close()) return fmt.Errorf("protocol violation: expected HELLO, received %s", msg.MessageType()) } // NOT IMPLEMENTED: Authenticate the user based on their provided credentials. // Extract their domain from said credentials. If no realm exists for that domain, // create it and add it to the trie. // New implementation: check for presence of realm key := patricia.Prefix(hello.Realm) if !r.root.MatchSubtree(key) { log.Println("Realm not found. Opening new realm ", hello.Realm) // Create the new realm newRealm := &Realm{URI: hello.Realm} newRealm.init() // Insert the realm into the tree r.root.Insert(patricia.Prefix(hello.Realm), newRealm) // log.Println("Created the new realm: ", newRealm) } // Extract the correct realm for this key // Sidenote: also an example of a cast... ish realm := r.root.Get(key).(*Realm) // log.Println("Sanity check: new realm for key: ", newRet.URI) // Old implementation // realm, _ := r.realms[hello.Realm] // if _, ok := r.realms[hello.Realm]; !ok { // logErr(client.Send(&Abort{Reason: ErrNoSuchRealm})) // logErr(client.Close()) // return NoSuchRealmError(hello.Realm) // } // Old implementation: the authentication must occur before fetching the realm welcome, err := realm.handleAuth(client, hello.Details) if err != nil { abort := &Abort{ Reason: ErrAuthorizationFailed, // TODO: should this be AuthenticationFailed? Details: map[string]interface{}{"error": err.Error()}, } logErr(client.Send(abort)) logErr(client.Close()) return AuthenticationError(err.Error()) } // No auth, no missing realms. Here is new implmementaton log.Println("Creating session, assigning to realm") // log.Println(r.root) // key := patricia.Prefix(hello.Realm) // fmt.Printf("Checking for id %q here? %v\n", key, trie.MatchSubtree(key)) welcome.Id = NewID() if welcome.Details == nil { welcome.Details = make(map[string]interface{}) } // add default details to welcome message for k, v := range defaultWelcomeDetails { if _, ok := welcome.Details[k]; !ok { welcome.Details[k] = v } } if err := client.Send(welcome); err != nil { return err } log.Println("Established session:", welcome.Id) sess := Session{Peer: client, Id: welcome.Id, kill: make(chan URI, 1)} // Alert any registered listeners of a new session for _, callback := range r.sessionOpenCallbacks { go callback(uint(sess.Id), string(hello.Realm)) } // Does this block on handleSession, then fire off .Close()? // Doesn't really make sense as written. Is there a blocked goroutine // for each session created that waits for the session to terminate? go func() { realm.handleSession(sess, welcome.Details) sess.Close() for _, callback := range r.sessionCloseCallbacks { go callback(uint(sess.Id), string(hello.Realm)) } }() return nil }
// Log the whole trie func (suite *TheSuite) TrieLog(c *C, fs *TransientFilesystem) { fs.trie.VisitSubtree(trie.Prefix(""), func(prefix trie.Prefix, item trie.Item) error { c.Logf("%q: %v\n", prefix, item) return nil }) }
// PathExists checks to see that the given path exists. // The path argument is expected to be relative to the rootPath of the // TransientFilesystem. Works for files and directories. func (fs *TransientFilesystem) PathExists(path string) bool { absPath := realPath(fs, path) fs.lock.RLock() defer fs.lock.RUnlock() return fs.trie.Match(trie.Prefix(absPath)) }
func deltaSourceTargets(sourceClnt client.Client, targetClnts []client.Client) <-chan mirrorURLs { mirrorURLsCh := make(chan mirrorURLs) go func() { defer close(mirrorURLsCh) sourceTrie := patricia.NewTrie() targetTries := make([]*patricia.Trie, len(targetClnts)) wg := new(sync.WaitGroup) wg.Add(1) go func() { defer wg.Done() for sourceContentCh := range sourceClnt.List(true) { if sourceContentCh.Err != nil { mirrorURLsCh <- mirrorURLs{Error: sourceContentCh.Err.Trace()} return } if sourceContentCh.Content.Type.IsRegular() { sourceTrie.Insert(patricia.Prefix(sourceContentCh.Content.Name), sourceContentCh.Content.Size) } } }() for i, targetClnt := range targetClnts { wg.Add(1) go func(i int, targetClnt client.Client) { defer wg.Done() targetTrie := patricia.NewTrie() for targetContentCh := range targetClnt.List(true) { if targetContentCh.Err != nil { mirrorURLsCh <- mirrorURLs{Error: targetContentCh.Err.Trace()} return } if targetContentCh.Content.Type.IsRegular() { targetTrie.Insert(patricia.Prefix(targetContentCh.Content.Name), struct{}{}) } } targetTries[i] = targetTrie }(i, targetClnt) } wg.Wait() matchNameCh := make(chan string, 10000) go func(matchNameCh chan<- string) { itemFunc := func(prefix patricia.Prefix, item patricia.Item) error { matchNameCh <- string(prefix) return nil } sourceTrie.Visit(itemFunc) defer close(matchNameCh) }(matchNameCh) for matchName := range matchNameCh { sourceContent := new(client.Content) var targetContents []*client.Content for i, targetTrie := range targetTries { if !targetTrie.Match(patricia.Prefix(matchName)) { sourceURLDelimited := sourceClnt.URL().String()[:strings.LastIndex(sourceClnt.URL().String(), string(sourceClnt.URL().Separator))+1] newTargetURLParse := *targetClnts[i].URL() newTargetURLParse.Path = filepath.Join(newTargetURLParse.Path, matchName) sourceContent.Size = sourceTrie.Get(patricia.Prefix(matchName)).(int64) sourceContent.Name = sourceURLDelimited + matchName targetContents = append(targetContents, &client.Content{Name: newTargetURLParse.String()}) } } mirrorURLsCh <- mirrorURLs{ SourceContent: sourceContent, TargetContents: targetContents, } } }() return mirrorURLsCh }
func initPrefixes() *gotrie.Trie { prefixes := gotrie.NewTrie() prefixes.Insert(gotrie.Prefix("1403"), "CA") prefixes.Insert(gotrie.Prefix("1587"), "CA") prefixes.Insert(gotrie.Prefix("1780"), "CA") prefixes.Insert(gotrie.Prefix("1825"), "CA") prefixes.Insert(gotrie.Prefix("1236"), "CA") prefixes.Insert(gotrie.Prefix("1250"), "CA") prefixes.Insert(gotrie.Prefix("1604"), "CA") prefixes.Insert(gotrie.Prefix("1672"), "CA") prefixes.Insert(gotrie.Prefix("1778"), "CA") prefixes.Insert(gotrie.Prefix("1204"), "CA") prefixes.Insert(gotrie.Prefix("1431"), "CA") prefixes.Insert(gotrie.Prefix("1506"), "CA") prefixes.Insert(gotrie.Prefix("1709"), "CA") prefixes.Insert(gotrie.Prefix("1782"), "CA") prefixes.Insert(gotrie.Prefix("1902"), "CA") prefixes.Insert(gotrie.Prefix("1548"), "CA") prefixes.Insert(gotrie.Prefix("1249"), "CA") prefixes.Insert(gotrie.Prefix("1289"), "CA") prefixes.Insert(gotrie.Prefix("1343"), "CA") prefixes.Insert(gotrie.Prefix("1365"), "CA") prefixes.Insert(gotrie.Prefix("1387"), "CA") prefixes.Insert(gotrie.Prefix("1416"), "CA") prefixes.Insert(gotrie.Prefix("1437"), "CA") prefixes.Insert(gotrie.Prefix("1519"), "CA") prefixes.Insert(gotrie.Prefix("1613"), "CA") prefixes.Insert(gotrie.Prefix("1647"), "CA") prefixes.Insert(gotrie.Prefix("1705"), "CA") prefixes.Insert(gotrie.Prefix("1742"), "CA") prefixes.Insert(gotrie.Prefix("1807"), "CA") prefixes.Insert(gotrie.Prefix("1905"), "CA") prefixes.Insert(gotrie.Prefix("1782"), "CA") prefixes.Insert(gotrie.Prefix("1902"), "CA") prefixes.Insert(gotrie.Prefix("1418"), "CA") prefixes.Insert(gotrie.Prefix("1438"), "CA") prefixes.Insert(gotrie.Prefix("1450"), "CA") prefixes.Insert(gotrie.Prefix("1514"), "CA") prefixes.Insert(gotrie.Prefix("1579"), "CA") prefixes.Insert(gotrie.Prefix("1581"), "CA") prefixes.Insert(gotrie.Prefix("1819"), "CA") prefixes.Insert(gotrie.Prefix("1873"), "CA") prefixes.Insert(gotrie.Prefix("1306"), "CA") prefixes.Insert(gotrie.Prefix("1639"), "CA") prefixes.Insert(gotrie.Prefix("1867"), "CA") prefixes.Insert(gotrie.Prefix("1"), "US") prefixes.Insert(gotrie.Prefix("1242"), "BS") prefixes.Insert(gotrie.Prefix("1246"), "BB") prefixes.Insert(gotrie.Prefix("1264"), "AI") prefixes.Insert(gotrie.Prefix("1268"), "AG") prefixes.Insert(gotrie.Prefix("1284"), "VG") prefixes.Insert(gotrie.Prefix("1340"), "VI") prefixes.Insert(gotrie.Prefix("1345"), "KY") prefixes.Insert(gotrie.Prefix("1441"), "BM") prefixes.Insert(gotrie.Prefix("1473"), "GD") prefixes.Insert(gotrie.Prefix("1649"), "TC") prefixes.Insert(gotrie.Prefix("1664"), "MS") prefixes.Insert(gotrie.Prefix("1670"), "MP") prefixes.Insert(gotrie.Prefix("1671"), "GU") prefixes.Insert(gotrie.Prefix("1684"), "AS") prefixes.Insert(gotrie.Prefix("1721"), "SX") prefixes.Insert(gotrie.Prefix("1758"), "LC") prefixes.Insert(gotrie.Prefix("1767"), "DM") prefixes.Insert(gotrie.Prefix("1784"), "VC") prefixes.Insert(gotrie.Prefix("1787"), "PR") prefixes.Insert(gotrie.Prefix("1809"), "DO") prefixes.Insert(gotrie.Prefix("1829"), "DO") prefixes.Insert(gotrie.Prefix("1849"), "DO") prefixes.Insert(gotrie.Prefix("1868"), "TT") prefixes.Insert(gotrie.Prefix("1869"), "KN") prefixes.Insert(gotrie.Prefix("1876"), "JM") prefixes.Insert(gotrie.Prefix("1939"), "PR") prefixes.Insert(gotrie.Prefix("20"), "EG") prefixes.Insert(gotrie.Prefix("211"), "SS") prefixes.Insert(gotrie.Prefix("212"), "MA") prefixes.Insert(gotrie.Prefix("213"), "DZ") prefixes.Insert(gotrie.Prefix("216"), "TN") prefixes.Insert(gotrie.Prefix("218"), "LY") prefixes.Insert(gotrie.Prefix("220"), "GM") prefixes.Insert(gotrie.Prefix("221"), "SN") prefixes.Insert(gotrie.Prefix("222"), "MR") prefixes.Insert(gotrie.Prefix("223"), "ML") prefixes.Insert(gotrie.Prefix("224"), "GN") prefixes.Insert(gotrie.Prefix("225"), "CI") prefixes.Insert(gotrie.Prefix("226"), "BF") prefixes.Insert(gotrie.Prefix("227"), "NE") prefixes.Insert(gotrie.Prefix("228"), "TG") prefixes.Insert(gotrie.Prefix("229"), "BJ") prefixes.Insert(gotrie.Prefix("230"), "MU") prefixes.Insert(gotrie.Prefix("231"), "LR") prefixes.Insert(gotrie.Prefix("232"), "SL") prefixes.Insert(gotrie.Prefix("233"), "GH") prefixes.Insert(gotrie.Prefix("234"), "NG") prefixes.Insert(gotrie.Prefix("235"), "TD") prefixes.Insert(gotrie.Prefix("236"), "CF") prefixes.Insert(gotrie.Prefix("237"), "CM") prefixes.Insert(gotrie.Prefix("238"), "CV") prefixes.Insert(gotrie.Prefix("239"), "ST") prefixes.Insert(gotrie.Prefix("240"), "GQ") prefixes.Insert(gotrie.Prefix("241"), "GA") prefixes.Insert(gotrie.Prefix("242"), "CG") prefixes.Insert(gotrie.Prefix("243"), "CD") prefixes.Insert(gotrie.Prefix("244"), "AO") prefixes.Insert(gotrie.Prefix("245"), "GW") prefixes.Insert(gotrie.Prefix("246"), "IO") prefixes.Insert(gotrie.Prefix("247"), "SH") prefixes.Insert(gotrie.Prefix("248"), "SC") prefixes.Insert(gotrie.Prefix("249"), "SD") prefixes.Insert(gotrie.Prefix("250"), "RW") prefixes.Insert(gotrie.Prefix("251"), "ET") prefixes.Insert(gotrie.Prefix("252"), "SO") prefixes.Insert(gotrie.Prefix("253"), "DJ") prefixes.Insert(gotrie.Prefix("254"), "KE") prefixes.Insert(gotrie.Prefix("255"), "TZ") prefixes.Insert(gotrie.Prefix("256"), "UG") prefixes.Insert(gotrie.Prefix("257"), "BI") prefixes.Insert(gotrie.Prefix("258"), "MZ") prefixes.Insert(gotrie.Prefix("260"), "ZM") prefixes.Insert(gotrie.Prefix("261"), "MG") prefixes.Insert(gotrie.Prefix("262"), "RE") prefixes.Insert(gotrie.Prefix("263"), "ZW") prefixes.Insert(gotrie.Prefix("264"), "NA") prefixes.Insert(gotrie.Prefix("265"), "MW") prefixes.Insert(gotrie.Prefix("266"), "LS") prefixes.Insert(gotrie.Prefix("267"), "BW") prefixes.Insert(gotrie.Prefix("268"), "SZ") prefixes.Insert(gotrie.Prefix("269"), "KM") prefixes.Insert(gotrie.Prefix("27"), "ZA") prefixes.Insert(gotrie.Prefix("290"), "SH") prefixes.Insert(gotrie.Prefix("291"), "ER") prefixes.Insert(gotrie.Prefix("297"), "AW") prefixes.Insert(gotrie.Prefix("298"), "FO") prefixes.Insert(gotrie.Prefix("299"), "GL") prefixes.Insert(gotrie.Prefix("30"), "GR") prefixes.Insert(gotrie.Prefix("31"), "NL") prefixes.Insert(gotrie.Prefix("32"), "BE") prefixes.Insert(gotrie.Prefix("33"), "FR") prefixes.Insert(gotrie.Prefix("34"), "ES") prefixes.Insert(gotrie.Prefix("350"), "GI") prefixes.Insert(gotrie.Prefix("351"), "PT") prefixes.Insert(gotrie.Prefix("352"), "LU") prefixes.Insert(gotrie.Prefix("353"), "IE") prefixes.Insert(gotrie.Prefix("354"), "IS") prefixes.Insert(gotrie.Prefix("355"), "AL") prefixes.Insert(gotrie.Prefix("356"), "MT") prefixes.Insert(gotrie.Prefix("357"), "CY") prefixes.Insert(gotrie.Prefix("358"), "FI") prefixes.Insert(gotrie.Prefix("359"), "BG") prefixes.Insert(gotrie.Prefix("36"), "HU") prefixes.Insert(gotrie.Prefix("370"), "LT") prefixes.Insert(gotrie.Prefix("371"), "LV") prefixes.Insert(gotrie.Prefix("372"), "EE") prefixes.Insert(gotrie.Prefix("373"), "MD") prefixes.Insert(gotrie.Prefix("374"), "AM") prefixes.Insert(gotrie.Prefix("375"), "BY") prefixes.Insert(gotrie.Prefix("376"), "AD") prefixes.Insert(gotrie.Prefix("377"), "MC") prefixes.Insert(gotrie.Prefix("378"), "SM") prefixes.Insert(gotrie.Prefix("379"), "VA") prefixes.Insert(gotrie.Prefix("380"), "UA") prefixes.Insert(gotrie.Prefix("381"), "RS") prefixes.Insert(gotrie.Prefix("381"), "XK") prefixes.Insert(gotrie.Prefix("382"), "ME") prefixes.Insert(gotrie.Prefix("385"), "HR") prefixes.Insert(gotrie.Prefix("386"), "SI") prefixes.Insert(gotrie.Prefix("386"), "XK") prefixes.Insert(gotrie.Prefix("387"), "BA") prefixes.Insert(gotrie.Prefix("389"), "MK") prefixes.Insert(gotrie.Prefix("39"), "IT") prefixes.Insert(gotrie.Prefix("39066"), "VA") prefixes.Insert(gotrie.Prefix("40"), "RO") prefixes.Insert(gotrie.Prefix("41"), "CH") prefixes.Insert(gotrie.Prefix("420"), "CZ") prefixes.Insert(gotrie.Prefix("421"), "SK") prefixes.Insert(gotrie.Prefix("423"), "LI") prefixes.Insert(gotrie.Prefix("43"), "AT") prefixes.Insert(gotrie.Prefix("44"), "GB") prefixes.Insert(gotrie.Prefix("45"), "DK") prefixes.Insert(gotrie.Prefix("46"), "SE") prefixes.Insert(gotrie.Prefix("47"), "NO") prefixes.Insert(gotrie.Prefix("4779"), "SJ") prefixes.Insert(gotrie.Prefix("48"), "PL") prefixes.Insert(gotrie.Prefix("49"), "DE") prefixes.Insert(gotrie.Prefix("500"), "FK") prefixes.Insert(gotrie.Prefix("501"), "BZ") prefixes.Insert(gotrie.Prefix("502"), "GT") prefixes.Insert(gotrie.Prefix("503"), "SV") prefixes.Insert(gotrie.Prefix("504"), "HN") prefixes.Insert(gotrie.Prefix("505"), "NI") prefixes.Insert(gotrie.Prefix("506"), "CR") prefixes.Insert(gotrie.Prefix("507"), "PA") prefixes.Insert(gotrie.Prefix("508"), "PM") prefixes.Insert(gotrie.Prefix("509"), "HT") prefixes.Insert(gotrie.Prefix("51"), "PE") prefixes.Insert(gotrie.Prefix("52"), "MX") prefixes.Insert(gotrie.Prefix("53"), "CU") prefixes.Insert(gotrie.Prefix("54"), "AR") prefixes.Insert(gotrie.Prefix("55"), "BR") prefixes.Insert(gotrie.Prefix("56"), "CL") prefixes.Insert(gotrie.Prefix("57"), "CO") prefixes.Insert(gotrie.Prefix("58"), "VE") prefixes.Insert(gotrie.Prefix("590"), "GP") prefixes.Insert(gotrie.Prefix("591"), "BO") prefixes.Insert(gotrie.Prefix("592"), "GY") prefixes.Insert(gotrie.Prefix("593"), "EC") prefixes.Insert(gotrie.Prefix("594"), "GF") prefixes.Insert(gotrie.Prefix("595"), "PY") prefixes.Insert(gotrie.Prefix("596"), "MQ") prefixes.Insert(gotrie.Prefix("597"), "SR") prefixes.Insert(gotrie.Prefix("598"), "UY") prefixes.Insert(gotrie.Prefix("5997"), "BQ") prefixes.Insert(gotrie.Prefix("5999"), "CW") prefixes.Insert(gotrie.Prefix("60"), "MY") prefixes.Insert(gotrie.Prefix("61"), "AU") prefixes.Insert(gotrie.Prefix("62"), "ID") prefixes.Insert(gotrie.Prefix("63"), "PH") prefixes.Insert(gotrie.Prefix("64"), "NZ") prefixes.Insert(gotrie.Prefix("65"), "SG") prefixes.Insert(gotrie.Prefix("66"), "TH") prefixes.Insert(gotrie.Prefix("670"), "TL") prefixes.Insert(gotrie.Prefix("672"), "NF") prefixes.Insert(gotrie.Prefix("673"), "BN") prefixes.Insert(gotrie.Prefix("674"), "NR") prefixes.Insert(gotrie.Prefix("675"), "PG") prefixes.Insert(gotrie.Prefix("676"), "TO") prefixes.Insert(gotrie.Prefix("677"), "SB") prefixes.Insert(gotrie.Prefix("678"), "VU") prefixes.Insert(gotrie.Prefix("679"), "FJ") prefixes.Insert(gotrie.Prefix("680"), "PW") prefixes.Insert(gotrie.Prefix("681"), "WF") prefixes.Insert(gotrie.Prefix("682"), "CK") prefixes.Insert(gotrie.Prefix("683"), "NU") prefixes.Insert(gotrie.Prefix("685"), "WS") prefixes.Insert(gotrie.Prefix("686"), "KI") prefixes.Insert(gotrie.Prefix("687"), "NC") prefixes.Insert(gotrie.Prefix("688"), "TV") prefixes.Insert(gotrie.Prefix("689"), "PF") prefixes.Insert(gotrie.Prefix("690"), "TK") prefixes.Insert(gotrie.Prefix("691"), "FM") prefixes.Insert(gotrie.Prefix("692"), "MH") prefixes.Insert(gotrie.Prefix("7"), "RU") prefixes.Insert(gotrie.Prefix("76"), "KZ") prefixes.Insert(gotrie.Prefix("77"), "KZ") prefixes.Insert(gotrie.Prefix("81"), "JP") prefixes.Insert(gotrie.Prefix("82"), "KR") prefixes.Insert(gotrie.Prefix("84"), "VN") prefixes.Insert(gotrie.Prefix("850"), "KP") prefixes.Insert(gotrie.Prefix("852"), "HK") prefixes.Insert(gotrie.Prefix("853"), "MO") prefixes.Insert(gotrie.Prefix("855"), "KH") prefixes.Insert(gotrie.Prefix("856"), "LA") prefixes.Insert(gotrie.Prefix("86"), "CN") prefixes.Insert(gotrie.Prefix("880"), "BD") prefixes.Insert(gotrie.Prefix("886"), "TW") prefixes.Insert(gotrie.Prefix("90"), "TR") prefixes.Insert(gotrie.Prefix("91"), "IN") prefixes.Insert(gotrie.Prefix("92"), "PK") prefixes.Insert(gotrie.Prefix("93"), "AF") prefixes.Insert(gotrie.Prefix("94"), "LK") prefixes.Insert(gotrie.Prefix("95"), "MM") prefixes.Insert(gotrie.Prefix("960"), "MV") prefixes.Insert(gotrie.Prefix("961"), "LB") prefixes.Insert(gotrie.Prefix("962"), "JO") prefixes.Insert(gotrie.Prefix("963"), "SY") prefixes.Insert(gotrie.Prefix("964"), "IQ") prefixes.Insert(gotrie.Prefix("965"), "KW") prefixes.Insert(gotrie.Prefix("966"), "SA") prefixes.Insert(gotrie.Prefix("967"), "YE") prefixes.Insert(gotrie.Prefix("968"), "OM") prefixes.Insert(gotrie.Prefix("970"), "PS") prefixes.Insert(gotrie.Prefix("971"), "AE") prefixes.Insert(gotrie.Prefix("972"), "IL") prefixes.Insert(gotrie.Prefix("973"), "BH") prefixes.Insert(gotrie.Prefix("974"), "QA") prefixes.Insert(gotrie.Prefix("975"), "BT") prefixes.Insert(gotrie.Prefix("976"), "MN") prefixes.Insert(gotrie.Prefix("977"), "NP") prefixes.Insert(gotrie.Prefix("98"), "IR") prefixes.Insert(gotrie.Prefix("992"), "TJ") prefixes.Insert(gotrie.Prefix("993"), "TM") prefixes.Insert(gotrie.Prefix("994"), "AZ") prefixes.Insert(gotrie.Prefix("995"), "GE") prefixes.Insert(gotrie.Prefix("996"), "KG") prefixes.Insert(gotrie.Prefix("998"), "UZ") return prefixes }