github.com/sdqri/sequined@v0.0.0-20240421190656-fc6bf956f4d8/internal/graphmultiplexer/graph_multiplexer.go (about) 1 package graphmultiplexer 2 3 import ( 4 "fmt" 5 "net" 6 "net/http" 7 "time" 8 9 dsh "github.com/sdqri/sequined/internal/dashboard" 10 ggr "github.com/sdqri/sequined/internal/graphgenerator" 11 hyr "github.com/sdqri/sequined/internal/hyperrenderer" 12 obs "github.com/sdqri/sequined/internal/observer" 13 ) 14 15 type Middleware func(http.HandlerFunc) http.HandlerFunc 16 17 type GraphMux struct { 18 Root *hyr.Webpage 19 RouteMap map[string]hyr.HyperRenderer 20 Observer *obs.Observer 21 22 *http.ServeMux 23 middlewareChain []Middleware 24 GraphHandlerFunc http.HandlerFunc 25 } 26 27 type GraphMuxOption func(*GraphMux) 28 29 func New(root *hyr.Webpage, opts ...GraphMuxOption) (*GraphMux, error) { 30 routeMap := hyr.CreatePathMap(root) 31 32 mux := GraphMux{ 33 Root: root, 34 RouteMap: routeMap, 35 36 ServeMux: http.NewServeMux(), 37 middlewareChain: make([]Middleware, 0), 38 } 39 40 for _, opt := range opts { 41 opt(&mux) 42 } 43 44 if mux.Observer != nil { 45 mux.middlewareChain = append(mux.middlewareChain, VisitLoggerMiddleware(&mux)) 46 47 var err error 48 hyr.Traverse(mux.Root, func(node hyr.HyperRenderer) bool { 49 currentPage, ok := node.(*hyr.Webpage) 50 if !ok { 51 err = ggr.ErrUnexpectedNodeType 52 return true 53 } 54 mux.logNodeCreation(currentPage) 55 return false 56 }) 57 if err != nil { 58 return nil, err 59 } 60 } 61 62 mux.GraphHandlerFunc = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 63 mux.HandleGraphHttpRequest(w, r) 64 }) 65 66 for _, mw := range mux.middlewareChain { 67 mux.GraphHandlerFunc = mw(mux.GraphHandlerFunc) 68 } 69 70 mux.Handle("/", mux.GraphHandlerFunc) 71 72 return &mux, nil 73 } 74 75 func WithObserver(observer *obs.Observer) GraphMuxOption { 76 return func(mux *GraphMux) { 77 mux.Observer = observer 78 } 79 } 80 81 func WithMiddleware(mw Middleware) GraphMuxOption { 82 return func(mux *GraphMux) { 83 mux.middlewareChain = append(mux.middlewareChain, mw) 84 } 85 } 86 87 func (mux *GraphMux) Use(mw Middleware) { 88 mux.GraphHandlerFunc = mw(mux.GraphHandlerFunc) 89 } 90 91 func (mux *GraphMux) HandleGraphHttpRequest(w http.ResponseWriter, r *http.Request) { 92 page, ok := mux.RouteMap[r.URL.Path] 93 if ok { 94 err := page.Render(w) 95 if err != nil { 96 fmt.Println(err.Error()) 97 } 98 } else { 99 http.NotFound(w, r) 100 } 101 } 102 103 func (mux *GraphMux) SyncGraph(updateChan chan ggr.UpdateMessage, errChan chan error) { 104 for { 105 select { 106 case updateMsg, ok := <-updateChan: 107 if !ok { 108 //TODO: not do 109 } 110 mux.RouteMap = hyr.CreatePathMap(mux.Root) 111 switch updateMsg.Type { 112 case ggr.UpdateTypeCreate: 113 mux.logNodeCreation(updateMsg.Webpage) 114 case ggr.UpdateTypeDelete: 115 mux.logNodeDeletion(updateMsg.Webpage) 116 } 117 // case err, ok <- errChan: 118 119 } 120 } 121 } 122 123 func (mux *GraphMux) logNodeCreation(webpage hyr.HyperRenderer) { 124 if mux.Observer != nil { 125 mux.Observer.LogNode(obs.NodeLog{ 126 ID: obs.NodeID(webpage.GetID()), 127 CreatedAt: time.Now().UTC(), 128 DeletedAt: nil, 129 }) 130 } 131 } 132 133 func (mux *GraphMux) logNodeDeletion(webpage hyr.HyperRenderer) { 134 if mux.Observer != nil { 135 now := time.Now().UTC() 136 if logNode, ok := mux.Observer.NodeLogMap[obs.NodeID(webpage.GetID())]; ok { 137 logNode.DeletedAt = &now 138 } 139 } 140 } 141 142 func (mux *GraphMux) logVisit(req *http.Request) { 143 if mux.Observer == nil { 144 return 145 } 146 147 ip, _, _ := net.SplitHostPort(req.RemoteAddr) 148 if node, ok := mux.RouteMap[req.URL.Path]; ok { 149 if currentPage, ok := node.(*hyr.Webpage); ok { 150 mux.Observer.LogVisit(obs.VisitLog{ 151 RemoteAddr: obs.IPAddr(ip), 152 NodeID: obs.NodeID(currentPage.GetID()), 153 VisitedAt: time.Now().UTC(), 154 }) 155 } 156 } 157 } 158 159 func VisitLoggerMiddleware(mux *GraphMux) Middleware { 160 return func(next http.HandlerFunc) http.HandlerFunc { 161 return func(w http.ResponseWriter, r *http.Request) { 162 next(w, r) 163 164 mux.logVisit(r) 165 } 166 } 167 } 168 169 func (mux *GraphMux) ActivateDashboard(dashboard *dsh.Dashboard) { 170 dashboard.HandleBy(mux.ServeMux) 171 }