route.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package app
  2. import (
  3. "reflect"
  4. "regexp"
  5. "sync"
  6. )
  7. var (
  8. routes = makeRouter()
  9. )
  10. // Route associates the type of the given component to the given path.
  11. //
  12. // When a page is requested and matches the route, a new instance of the given
  13. // component is created before being displayed.
  14. func Route(path string, c Composer) {
  15. routes.route(path, c)
  16. }
  17. // RouteWithRegexp associates the type of the given component to the given
  18. // regular expression pattern.
  19. //
  20. // Patterns use the Go standard regexp format.
  21. //
  22. // When a page is requested and matches the pattern, a new instance of the given
  23. // component is created before being displayed.
  24. func RouteWithRegexp(pattern string, c Composer) {
  25. routes.routeWithRegexp(pattern, c)
  26. }
  27. type router struct {
  28. mu sync.RWMutex
  29. routes map[string]reflect.Type
  30. routesWithRegexp []regexpRoute
  31. }
  32. func makeRouter() router {
  33. return router{
  34. routes: make(map[string]reflect.Type),
  35. }
  36. }
  37. func (r *router) route(path string, c Composer) {
  38. r.mu.Lock()
  39. defer r.mu.Unlock()
  40. r.routes[path] = reflect.TypeOf(c)
  41. }
  42. func (r *router) routeWithRegexp(pattern string, c Composer) {
  43. r.mu.Lock()
  44. defer r.mu.Unlock()
  45. r.routesWithRegexp = append(r.routesWithRegexp, regexpRoute{
  46. regexp: regexp.MustCompile(pattern),
  47. compoType: reflect.TypeOf(c),
  48. })
  49. }
  50. func (r *router) createComponent(path string) (Composer, bool) {
  51. r.mu.RLock()
  52. defer r.mu.RUnlock()
  53. compoType, isRouted := r.routes[path]
  54. if !isRouted {
  55. for _, rwr := range r.routesWithRegexp {
  56. if rwr.regexp.MatchString(path) {
  57. compoType = rwr.compoType
  58. isRouted = true
  59. break
  60. }
  61. }
  62. }
  63. if !isRouted {
  64. return nil, false
  65. }
  66. compo := reflect.New(compoType.Elem()).Interface().(Composer)
  67. return compo, true
  68. }
  69. func (r *router) len() int {
  70. return len(r.routes) + len(r.routesWithRegexp)
  71. }
  72. type regexpRoute struct {
  73. regexp *regexp.Regexp
  74. compoType reflect.Type
  75. }