package registry import ( "bytes" "encoding/gob" "net/url" "strings" "git.capotej.com/capotej/communique/config" "git.capotej.com/capotej/communique/models" "git.capotej.com/capotej/communique/urls" "git.capotej.com/capotej/communique/views" ) type Handler struct { handlerCfg config.Handler } // TODO rename to controller and controller.go type Registry struct { cfg config.Config persister *models.Persister handlerMap map[string]Handler } func NewRegistry(cfg config.Config, persister *models.Persister) *Registry { reg := Registry{cfg: cfg, persister: persister} reg.handlerMap = make(map[string]Handler) for _, v := range cfg.Handlers { reg.handlerMap[v.Name] = Handler{handlerCfg: v} } return ® } func (r *Registry) Actor(name string) (map[string]interface{}, error) { handler := r.findByName(name) if handler == nil { return nil, nil } return views.RenderActor(handler.handlerCfg.Name, r.cfg.Domain) } func (r *Registry) OutboxCollection(name string) (map[string]interface{}, error) { handler := r.findByName(name) if handler == nil { return nil, nil } aso := models.NewOutboxItem(handler.handlerCfg) page, err := r.persister.Collect(aso) if err != nil { return nil, err } var outboxItems []models.OutboxItem for _, v := range page[0:20] { //TODO pagination buf := bytes.NewBuffer(v) dec := gob.NewDecoder(buf) var outboxItem models.OutboxItem err = dec.Decode(&outboxItem) if err != nil { return nil, err } outboxItems = append(outboxItems, outboxItem) } return views.RenderOutboxCollection(handler.handlerCfg.Name, r.cfg.Domain, outboxItems) } func (r *Registry) Following(name string) (map[string]interface{}, error) { handler := r.findByName(name) if handler == nil { return nil, nil } profile, err := urls.UrlProfile(name, r.cfg.Domain) if err != nil { return nil, err } following, err := urls.UrlFollowing(name, r.cfg.Domain) if err != nil { return nil, err } result := make(map[string]interface{}) result["@context"] = "https://www.w3.org/ns/activitystreams" result["attributedTo"] = profile.String() result["id"] = following.String() result["totalItems"] = 0 result["orderedItems"] = []bool{} result["type"] = "OrderedCollection" return result, nil } func (r *Registry) Followers(name string) (map[string]interface{}, error) { handler := r.findByName(name) if handler == nil { return nil, nil } profile, err := urls.UrlProfile(name, r.cfg.Domain) if err != nil { return nil, err } followers, err := urls.UrlFollowers(name, r.cfg.Domain) if err != nil { return nil, err } result := make(map[string]interface{}) result["@context"] = "https://www.w3.org/ns/activitystreams" result["attributedTo"] = profile.String() result["id"] = followers.String() result["totalItems"] = 0 result["orderedItems"] = []bool{} result["type"] = "OrderedCollection" return result, nil } func (r *Registry) ActivityOrNote(activityOrNote, name, id string) (map[string]interface{}, error) { handler := r.findByName(name) if handler == nil { return nil, nil } lookup := models.NewOutboxItem(handler.handlerCfg) lookup.Id = []byte(id) result, err := r.persister.Find(lookup) if err != nil { return nil, err } if result == nil { return nil, nil } buf := bytes.NewBuffer(result) dec := gob.NewDecoder(buf) var outboxItem models.OutboxItem err = dec.Decode(&outboxItem) if err != nil { return nil, err } if activityOrNote == "activity" { return views.RenderActivity(handler.handlerCfg.Name, r.cfg.Domain, outboxItem) } return views.RenderNote(handler.handlerCfg.Name, r.cfg.Domain, outboxItem) } // This has to handle various lookup formats: // ?resource=acct:actor@domain // ?resource=actor@domain // ?resource=actor // ?resource=acct:actor func (r *Registry) Webfinger(fqn string) (*views.WebfingerResource, error) { // Strip away acct: prefix, if found fqn = strings.TrimPrefix(fqn, "acct:") // Strip away @domain suffix, if found domainUrl, err := url.Parse(r.cfg.Domain) if err != nil { return nil, err } hostname := "@" + domainUrl.Hostname() fqn = strings.TrimSuffix(fqn, hostname) // We should just have $actor left handler := r.findByName(fqn) if handler == nil { return nil, nil } return views.RenderWebfinger(handler.handlerCfg.Name, r.cfg.Domain, hostname) } func (r *Registry) findByName(name string) *Handler { handler, ok := r.handlerMap[name] if !ok { return nil } return &handler }