removed internal package
This commit is contained in:
parent
3991c52689
commit
e3a6d711d1
@ -1,40 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "context"
|
|
||||||
// "log"
|
|
||||||
|
|
||||||
// "golang.org/x/oauth2"
|
|
||||||
|
|
||||||
// oidc "github.com/coreos/go-oidc"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type Authenticator struct {
|
|
||||||
// Provider *oidc.Provider
|
|
||||||
// Config oauth2.Config
|
|
||||||
// Ctx context.Context
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func NewAuthenticator(domain, clientID, clientSecret, callback string) (*Authenticator, error) {
|
|
||||||
// ctx := context.Background()
|
|
||||||
|
|
||||||
// provider, err := oidc.NewProvider(ctx, domain)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Printf("failed to get provider: %v", err)
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// conf := oauth2.Config{
|
|
||||||
// ClientID: clientID,
|
|
||||||
// ClientSecret: clientSecret,
|
|
||||||
// RedirectURL: callback,
|
|
||||||
// Endpoint: provider.Endpoint(),
|
|
||||||
// Scopes: []string{oidc.ScopeOpenID, "profile"},
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return &Authenticator{
|
|
||||||
// Provider: provider,
|
|
||||||
// Config: conf,
|
|
||||||
// Ctx: ctx,
|
|
||||||
// }, nil
|
|
||||||
// }
|
|
@ -1,89 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "context"
|
|
||||||
// "log"
|
|
||||||
// "net/http"
|
|
||||||
|
|
||||||
// oidc "github.com/coreos/go-oidc"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func NewCallbackHandler(c Config) http.HandlerFunc {
|
|
||||||
|
|
||||||
// return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// session, err := Store.Get(r, SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if r.URL.Query().Get("state") != session.Values["state"] {
|
|
||||||
// http.Error(w, "Invalid state parameter", http.StatusBadRequest)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// authenticator, err := NewAuthenticator(c.Domain, c.ClientID, c.ClientSecret, c.CallbackURL)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// token, err := authenticator.Config.Exchange(context.TODO(), r.URL.Query().Get("code"))
|
|
||||||
// if err != nil {
|
|
||||||
// log.Printf("no token found: %v", err)
|
|
||||||
// w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// rawIDToken, ok := token.Extra("id_token").(string)
|
|
||||||
// if !ok {
|
|
||||||
// http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// oidcConfig := &oidc.Config{
|
|
||||||
// ClientID: c.ClientID,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// idToken, err := authenticator.Provider.Verifier(oidcConfig).Verify(context.TODO(), rawIDToken)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Getting now the userInfo
|
|
||||||
// user := User{}
|
|
||||||
// if err := idToken.Claims(&user); err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// session.Values["id_token"] = rawIDToken
|
|
||||||
// session.Values["access_token"] = token.AccessToken
|
|
||||||
// session.Values["profile"] = user
|
|
||||||
// err = session.Save(r, w)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // if application ID is non existent, and therefore does not have a tenant
|
|
||||||
// // Create or associate?
|
|
||||||
// // Create:
|
|
||||||
// // - Create Tenant
|
|
||||||
// // - Specify plan
|
|
||||||
// // - Specify payment info
|
|
||||||
// // - Associate Tenant
|
|
||||||
// // - by email address domain?
|
|
||||||
// //set tenant ID on application ID in App Metadata on user
|
|
||||||
|
|
||||||
// // if c.CallbackFunc != nil {
|
|
||||||
// // c.CallbackFunc(c, user)
|
|
||||||
// // } else {
|
|
||||||
// // Redirect to logged in page
|
|
||||||
// http.Redirect(w, r, c.RedirectURL, http.StatusSeeOther)
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,36 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "os"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type Config struct {
|
|
||||||
// Domain string
|
|
||||||
// ClientID string
|
|
||||||
// ClientSecret string
|
|
||||||
// ManagementClientID string
|
|
||||||
// ManagementClientSecret string
|
|
||||||
|
|
||||||
// CallbackURL string
|
|
||||||
// RedirectURL string
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func FromEnv() Config {
|
|
||||||
// return Config{
|
|
||||||
// Domain: os.Getenv("AUTH_DOMAIN"),
|
|
||||||
// ClientID: os.Getenv("AUTH_CLIENT_ID"),
|
|
||||||
// ClientSecret: os.Getenv("AUTH_CLIENT_SECRET"),
|
|
||||||
// ManagementClientID: os.Getenv("AUTH_MGMT_CLIENT_ID"),
|
|
||||||
// ManagementClientSecret: os.Getenv("AUTH_MGMT_CLIENT_SECRET"),
|
|
||||||
|
|
||||||
// CallbackURL: os.Getenv("AUTH_CALLBACK_URL"),
|
|
||||||
// RedirectURL: "/user",
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func PrintConfig() {
|
|
||||||
// fmt.Printf("%#v\n", FromEnv())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type CallbackFunc func(c Config, u User) error
|
|
@ -1,43 +0,0 @@
|
|||||||
// routes/login/login.go
|
|
||||||
|
|
||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "crypto/rand"
|
|
||||||
// "encoding/base64"
|
|
||||||
// "net/http"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func NewLoginHandler(c Config) http.HandlerFunc {
|
|
||||||
// return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// // Generate random state
|
|
||||||
// b := make([]byte, 32)
|
|
||||||
// _, err := rand.Read(b)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// state := base64.StdEncoding.EncodeToString(b)
|
|
||||||
|
|
||||||
// session, err := Store.Get(r, SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// session.Values["state"] = state
|
|
||||||
// err = session.Save(r, w)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// authenticator, err := NewAuthenticator(c.Domain, c.ClientID, c.ClientSecret, c.CallbackURL)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// http.Redirect(w, r, authenticator.Config.AuthCodeURL(state), http.StatusTemporaryRedirect)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
@ -1,43 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "net/http"
|
|
||||||
// "net/url"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
// if cook, err := r.Cookie(SessionName); err == nil {
|
|
||||||
// cook.MaxAge = -1
|
|
||||||
// http.SetCookie(w, cook)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// domain := "dev-pb4s8m55.auth0.com"
|
|
||||||
|
|
||||||
// // var Url *url.URL
|
|
||||||
// URL, err := url.Parse("https://" + domain)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// session, err := Store.Get(r, SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// session.Options.MaxAge = -1
|
|
||||||
|
|
||||||
// err = session.Save(r, w)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// URL.Path += "/v2/logout"
|
|
||||||
// parameters := url.Values{}
|
|
||||||
// parameters.Add("returnTo", "http://localhost:3000")
|
|
||||||
// parameters.Add("client_id", "ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9")
|
|
||||||
// URL.RawQuery = parameters.Encode()
|
|
||||||
|
|
||||||
// http.Redirect(w, r, URL.String(), http.StatusTemporaryRedirect)
|
|
||||||
// }
|
|
@ -1,19 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import "net/http"
|
|
||||||
|
|
||||||
// func IsAuthenticated(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
|
|
||||||
// session, err := Store.Get(r, SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if _, ok := session.Values["profile"]; !ok {
|
|
||||||
// //TODO allow customization of redirect
|
|
||||||
// http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
||||||
// } else {
|
|
||||||
// next(w, r)
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,38 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "github.com/jchenry/x/internal/http"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func Service(c Config) ServiceInstance {
|
|
||||||
// return ServiceInstance{c: c}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ServiceInstance struct {
|
|
||||||
// c Config
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (si ServiceInstance) Register(m *http.Mux) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (si ServiceInstance) Register(uriBase string, s *_http.Server) {
|
|
||||||
|
|
||||||
// s.Get(uriBase+"/login", "login endpoint", http.HandlerFunc(NewLoginHandler(si.c)))
|
|
||||||
// s.Get(uriBase+"/logout", "logout endpoint", http.HandlerFunc(LogoutHandler))
|
|
||||||
// s.Get(uriBase+"/callback", "oidc callback", http.HandlerFunc(NewCallbackHandler(si.c)))
|
|
||||||
// s.Get(uriBase+"/user", "user info endpoint", negroni.New(
|
|
||||||
// negroni.HandlerFunc(IsAuthenticated),
|
|
||||||
// negroni.Wrap(http.HandlerFunc(UserHandler)),
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (si ServiceInstance) UpdateUser(u User) error {
|
|
||||||
// m, err := management.New(si.c.Domain, si.c.ManagementClientID, si.c.ManagementClientSecret)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// um := management.NewUserManager(m)
|
|
||||||
|
|
||||||
// return um.Update(u.ID, &management.User{AppMetadata: u.Apps})
|
|
||||||
// }
|
|
@ -1,19 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "encoding/gob"
|
|
||||||
|
|
||||||
// "github.com/gorilla/sessions"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// const SessionName = "auth-session"
|
|
||||||
|
|
||||||
// var (
|
|
||||||
// Store *sessions.FilesystemStore
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func Init() error {
|
|
||||||
// Store = sessions.NewFilesystemStore("", []byte("something-very-secret"))
|
|
||||||
// gob.Register(User{})
|
|
||||||
// return nil
|
|
||||||
// }
|
|
@ -1,28 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "net/http"
|
|
||||||
|
|
||||||
// jchenry_http "github.com/jchenry/x/internal/http"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func UserHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
// session, err := Store.Get(r, SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// jchenry_http.RenderTemplate(w, "user", session.Values["profile"])
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type User struct {
|
|
||||||
// ID string `json:"sub"`
|
|
||||||
// Email string `json:"email"`
|
|
||||||
// FirstName string `json:"given_name"`
|
|
||||||
// LastName string `json:"family_name"`
|
|
||||||
// Picture string `json:"picture"`
|
|
||||||
// Nickname string `json:"nickname"`
|
|
||||||
// Apps map[string]interface{} `json:"app_metadata,omitempty"`
|
|
||||||
// }
|
|
@ -1,42 +0,0 @@
|
|||||||
package crud
|
|
||||||
|
|
||||||
// import "github.com/jchenry/jchenry/pkg/db"
|
|
||||||
|
|
||||||
// type Service interface {
|
|
||||||
// // Find returns a pointer to an array of the results found based on params
|
|
||||||
// // or an error
|
|
||||||
// Find(entityArrPtr interface{}, params map[string]interface{}) (err error)
|
|
||||||
// // Create returns the identifier for the newly accepted entity, or error
|
|
||||||
// Create(entityPtr interface{}) (err error)
|
|
||||||
// // Update returns the id of the newly updated entity, or error
|
|
||||||
// Update(entityPtr interface{}) (err error)
|
|
||||||
// // Delete returns whether the entity, specified by id, was successfully deleted
|
|
||||||
// // or error
|
|
||||||
// Delete(entityPtr interface{}) error
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type Storage struct {
|
|
||||||
// Actor db.Actor
|
|
||||||
// FindOp func(entityArrPtr interface{}, params map[string]interface{}) db.Func
|
|
||||||
// CreateOp func(entityPtr interface{}) db.Func
|
|
||||||
// UpdateOp func(entityPtr interface{}) db.Func
|
|
||||||
// DeleteOp func(entityPtr interface{}) db.Func
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (s *Storage) Find(entityArrPtr interface{}, params map[string]interface{}) (err error) {
|
|
||||||
// s.Actor.ActionChan <- s.FindOp(entityArrPtr, params)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (s *Storage) Create(entityPtr interface{}) (err error) {
|
|
||||||
// s.Actor.ActionChan <- s.CreateOp(entityPtr)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// func (s *Storage) Update(entityPtr interface{}) (err error) {
|
|
||||||
// s.Actor.ActionChan <- s.UpdateOp(entityPtr)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// func (s *Storage) Delete(entityPtr interface{}) error {
|
|
||||||
// s.Actor.ActionChan <- s.DeleteOp(entityPtr)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
@ -1,56 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"rsc.io/dbstore"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DatabaseCollectionInstance struct {
|
|
||||||
db *sql.DB
|
|
||||||
store *dbstore.Storage
|
|
||||||
}
|
|
||||||
|
|
||||||
func DatabaseCollection(
|
|
||||||
db *sql.DB,
|
|
||||||
createTables bool,
|
|
||||||
types ...interface{}) (*DatabaseCollectionInstance, error) {
|
|
||||||
|
|
||||||
dbi := &DatabaseCollectionInstance{
|
|
||||||
db: db,
|
|
||||||
store: new(dbstore.Storage),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, t := range types {
|
|
||||||
dbi.store.Register(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dbi.store.CreateTables(db); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbi, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find returns a pointer to an array of the results found based on params
|
|
||||||
// or an error
|
|
||||||
func (d *DatabaseCollectionInstance) Find(entityArrPtr interface{}, params map[string]interface{}) error {
|
|
||||||
return d.store.Select(d.db, entityArrPtr, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create returns the identifier for the newly accepted entity, or error
|
|
||||||
func (d *DatabaseCollectionInstance) Create(entityPtr interface{}) error {
|
|
||||||
return d.store.Insert(d.db, entityPtr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update returns the id of the newly updated entity, or error
|
|
||||||
func (d *DatabaseCollectionInstance) Update(entityPtr interface{}) error {
|
|
||||||
return d.store.Insert(d.db, entityPtr)
|
|
||||||
// return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete returns whether the entity, specified by id, was successfully deleted
|
|
||||||
// or error
|
|
||||||
func (d *DatabaseCollectionInstance) Delete(entityPtr interface{}) error {
|
|
||||||
return d.store.Delete(d.db, entityPtr)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package gopher
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RFC 1436 types
|
|
||||||
Text byte = '0'
|
|
||||||
Submenu byte = '1'
|
|
||||||
Nameserver byte = '2'
|
|
||||||
Error byte = '3'
|
|
||||||
Binhex byte = '4'
|
|
||||||
DOS byte = '5'
|
|
||||||
UUencode byte = '6'
|
|
||||||
Search byte = '7'
|
|
||||||
Telnet byte = '8'
|
|
||||||
Binary byte = '9'
|
|
||||||
Mirror byte = '+'
|
|
||||||
Gif byte = 'g'
|
|
||||||
Image byte = 'I'
|
|
||||||
Telnet3270 byte = 'T'
|
|
||||||
|
|
||||||
// UnRFC'd Extensions
|
|
||||||
Doc byte = 'd'
|
|
||||||
Html byte = 'h'
|
|
||||||
Info byte = 'i'
|
|
||||||
Sound byte = 's'
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
Socket net.Conn
|
|
||||||
in *bufio.Reader
|
|
||||||
out *bufio.Writer
|
|
||||||
init sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Select(selector string) (m Menu, err error) {
|
|
||||||
c.init.Do(func() {
|
|
||||||
c.in = bufio.NewReader(c.Socket)
|
|
||||||
c.out = bufio.NewWriter(c.Socket)
|
|
||||||
})
|
|
||||||
c.out.WriteString(selector)
|
|
||||||
|
|
||||||
for {
|
|
||||||
if l, _, err := c.in.ReadLine(); err == nil {
|
|
||||||
s := Selector{}
|
|
||||||
s.Type = l[0]
|
|
||||||
bs := bytes.Split(l[1:], []byte{'\t'})
|
|
||||||
s.Display = string(bs[0])
|
|
||||||
s.Path = string(bs[1])
|
|
||||||
s.Hostname = string(bytes.Join(bs[2:3], []byte{':'}))
|
|
||||||
m = append(m, s)
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// s := Selector{
|
|
||||||
// Type: Text,
|
|
||||||
// Display: "",
|
|
||||||
// Hostname: "",
|
|
||||||
// Path: "",
|
|
||||||
// }
|
|
||||||
return Menu{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Menu []Selector
|
|
||||||
|
|
||||||
type Selector struct {
|
|
||||||
Type byte
|
|
||||||
Display string
|
|
||||||
Path string
|
|
||||||
Hostname string
|
|
||||||
Port string
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import "net/http"
|
|
||||||
|
|
||||||
// Error is an error wrapper for the standard HTTP error codes
|
|
||||||
type Error int
|
|
||||||
|
|
||||||
func (e Error) Error() string {
|
|
||||||
return http.StatusText(int(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Error) Code() int {
|
|
||||||
return int(e)
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JulienschmidtHTTPRouter struct {
|
|
||||||
httprouter.Router
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJulienschmidtHTTPRouter() *JulienschmidtHTTPRouter {
|
|
||||||
return &JulienschmidtHTTPRouter{
|
|
||||||
httprouter.Router{
|
|
||||||
RedirectTrailingSlash: true,
|
|
||||||
RedirectFixedPath: true,
|
|
||||||
HandleMethodNotAllowed: true,
|
|
||||||
HandleOPTIONS: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JulienschmidtHTTPRouter) AddHandler(method, path string, handler http.Handler) {
|
|
||||||
j.Handle(method, path, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
|
||||||
if req.Form == nil {
|
|
||||||
req.Form = url.Values{}
|
|
||||||
}
|
|
||||||
for _, param := range params {
|
|
||||||
// stuffing values back into request.Form to honor the handler contract
|
|
||||||
req.Form.Add(param.Key, param.Value)
|
|
||||||
}
|
|
||||||
handler.ServeHTTP(w, req)
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import "net/http"
|
|
||||||
|
|
||||||
type Mux interface {
|
|
||||||
Handle(pattern string, handler http.Handler)
|
|
||||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
|
|
||||||
// "log"
|
|
||||||
"net/http"
|
|
||||||
go_http "net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Middleware interface {
|
|
||||||
go_http.Handler
|
|
||||||
UseHandler(handler http.Handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Router interface {
|
|
||||||
go_http.Handler
|
|
||||||
ServeFiles(path string, root go_http.FileSystem)
|
|
||||||
AddHandler(method, path string, handler go_http.Handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// type Service interface {
|
|
||||||
// Register(uriBase string, restServer *Server)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ServiceFunc func(uriBase string, restServer *Server)
|
|
||||||
|
|
||||||
// func (f ServiceFunc) Register(uriBase string, restServer *Server) {
|
|
||||||
// f(uriBase, restServer)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var docString = "%s \t%s\t- %s"
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
router Router
|
|
||||||
middleware Middleware
|
|
||||||
}
|
|
||||||
|
|
||||||
// func NewServer(m Middleware, r Router) *Server {
|
|
||||||
// s := &Server{
|
|
||||||
// router: r,
|
|
||||||
// middleware: m,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// s.middleware.UseHandler(s.router)
|
|
||||||
|
|
||||||
// return s
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (r *Server) Get(path string, documentation string, handle go_http.Handler) *Server {
|
|
||||||
r.handle("GET", path, documentation, handle)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (r *Server) Patch(path string, documentation string, handle go_http.Handler) *Server {
|
|
||||||
// r.handle("PATCH", path, documentation, handle)
|
|
||||||
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
func (r *Server) Post(path string, documentation string, handle go_http.Handler) *Server {
|
|
||||||
r.handle("POST", path, documentation, handle)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (r *Server) Put(path string, documentation string, handle go_http.Handler) *Server {
|
|
||||||
// r.handle("PUT", path, documentation, handle)
|
|
||||||
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
// func (r *Server) Delete(path string, documentation string, handle go_http.Handler) *Server {
|
|
||||||
// r.handle("DELETE", path, documentation, handle)
|
|
||||||
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
func (r *Server) handle(method, path string, documentation string, handler go_http.Handler) {
|
|
||||||
// log.Printf(docString, method, path, documentation)
|
|
||||||
r.router.AddHandler(method, path, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (r *Server) Banner(banner string) *Server {
|
|
||||||
// log.Printf(banner)
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (r *Server) Service(basePath string, service Service) *Server {
|
|
||||||
// service.Register(basePath, r)
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
// func (r *Server) Static(path string, root go_http.FileSystem) *Server {
|
|
||||||
// r.router.ServeFiles(path, root)
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
// func (r *Server) Middleware(handler go_http.Handler) *Server {
|
|
||||||
// r.middleware.UseHandler(handler)
|
|
||||||
// return r
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (r *Server) Run(addr string) {
|
|
||||||
// log.Printf("listening on %s", addr)
|
|
||||||
// log.Fatal(http.ListenAndServe(addr, r.middleware))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (r *Server) ServeHTTP(w go_http.ResponseWriter, req *go_http.Request) {
|
|
||||||
// r.middleware.ServeHTTP(w, req)
|
|
||||||
// }
|
|
@ -1,34 +0,0 @@
|
|||||||
package http_test
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "os"
|
|
||||||
|
|
||||||
// "github.com/codegangsta/negroni"
|
|
||||||
// "github.com/jchenry/jchenry/http"
|
|
||||||
// "github.com/jchenry/jchenry/rest"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func ExampleServer() {
|
|
||||||
// type contact struct {
|
|
||||||
// ID int64 `json:"id"`
|
|
||||||
// First string `json:"firstName"`
|
|
||||||
// Last string `json:"lastName"`
|
|
||||||
// Email string `json:"emailAddress"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// s := http.NewServer(
|
|
||||||
// negroni.Classic(),
|
|
||||||
// http.NewJulienschmidtHTTPRouter()).
|
|
||||||
// Service("",
|
|
||||||
// rest.Collection(new(contact),
|
|
||||||
// nil,
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
|
|
||||||
// port := os.Getenv("PORT")
|
|
||||||
// if port == "" {
|
|
||||||
// port = "8080"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// s.Run(":" + port)
|
|
||||||
// }
|
|
@ -1,38 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
// import "net/http"
|
|
||||||
|
|
||||||
// type Service interface {
|
|
||||||
// Register(s Server)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type Mux interface {
|
|
||||||
// Head(pattern string, handler http.Handler)
|
|
||||||
// Post(pattern string, handler http.Handler)
|
|
||||||
// Put(pattern string, handler http.Handler)
|
|
||||||
// Patch(pattern string, handler http.Handler)
|
|
||||||
// Delete(pattern string, handler http.Handler)
|
|
||||||
// Connect(pattern string, handler http.Handler)
|
|
||||||
// Options(pattern string, handler http.Handler)
|
|
||||||
// Trace(pattern string, handler http.Handler)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// MethodGet = "GET"
|
|
||||||
// MethodHead = "HEAD"
|
|
||||||
// MethodPost = "POST"
|
|
||||||
// MethodPut = "PUT"
|
|
||||||
// MethodPatch = "PATCH" // RFC 5789
|
|
||||||
// MethodDelete = "DELETE"
|
|
||||||
// MethodConnect = "CONNECT"
|
|
||||||
// MethodOptions = "OPTIONS"
|
|
||||||
// MethodTrace = "TRACE"
|
|
||||||
|
|
||||||
type Service interface {
|
|
||||||
Register(m *Mux) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServiceFunc func(m *Mux) error
|
|
||||||
|
|
||||||
func (s ServiceFunc) Register(m *Mux) error {
|
|
||||||
return s(m)
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RenderTemplate(w http.ResponseWriter, tmpl string, data interface{}) {
|
|
||||||
cwd, _ := os.Getwd()
|
|
||||||
// t, err := template.ParseFiles(filepath.Join(cwd, "./routes/"+tmpl+"/"+tmpl+".html"))
|
|
||||||
t, err := template.ParseFiles(filepath.Join(cwd, "./"+tmpl+".html"))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = t.Execute(w, data)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func render(w http.ResponseWriter, tmpl string, data interface{}) (err error) {
|
|
||||||
if t, err := template.ParseFiles(tmpl); err == nil {
|
|
||||||
return t.Execute(w, data)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
HeaderContentType = "Content-Type"
|
|
||||||
MimeJSON = "application/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
//ErrNotFound is returned when an entity could not be found in Find
|
|
||||||
var ErrNotFound = errors.New("entity not found")
|
|
||||||
|
|
||||||
func WriteEntity(w http.ResponseWriter, entityPtr interface{}) error {
|
|
||||||
w.Header().Set(HeaderContentType, MimeJSON)
|
|
||||||
|
|
||||||
var out []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if entityPtr == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err = json.MarshalIndent(entityPtr, " ", " ")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = w.Write(out); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadEntity(request *http.Request, entityPtr interface{}) error {
|
|
||||||
decoder := json.NewDecoder(request.Body)
|
|
||||||
err := decoder.Decode(entityPtr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorResponse - A structured Error HTTP response
|
|
||||||
type ErrorResponse struct {
|
|
||||||
Status int
|
|
||||||
DeveloperMessage string
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteErrorResponse - Creates a new ErrorResponse and writes it to
|
|
||||||
// the response
|
|
||||||
func WriteErrorResponse(w http.ResponseWriter, status int, message string) error {
|
|
||||||
log.Println(status, message)
|
|
||||||
w.WriteHeader(status)
|
|
||||||
return WriteEntity(w, ErrorResponse{status, message})
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
// import "database/sql"
|
|
||||||
|
|
||||||
// type Storage interface {
|
|
||||||
// Insert(ctxt StorageContext, val interface{}) error
|
|
||||||
// Read(ctxt StorageContext, val interface{}, columns ...string) error
|
|
||||||
// Select(ctxt StorageContext, val interface{}, query string, args ...interface{}) error
|
|
||||||
// Write(ctxt StorageContext, val interface{}, columns ...string) error
|
|
||||||
// Delete(ctxt StorageContext, val interface{}) error
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type StorageContext interface {
|
|
||||||
// Exec(query string, args ...interface{}) (sql.Result, error)
|
|
||||||
// Query(query string, args ...interface{}) (*sql.Rows, error)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ModelService struct {
|
|
||||||
// db Storage
|
|
||||||
// ctx *StorageContext
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Find returns a pointer to an array of the results found based on params
|
|
||||||
// // or an error
|
|
||||||
// func (s *ModelService) Find(entityArrPtr interface{}, params map[string]interface{}) (err error) {
|
|
||||||
// s.db.Select(s.ctx, )
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Create returns the identifier for the newly accepted entity, or error
|
|
||||||
// func (s *ModelService) Create(entityPtr interface{}) (id interface{}, err error) {}
|
|
||||||
|
|
||||||
// // Update returns the id of the newly updated entity, or error
|
|
||||||
// func (s *ModelService) Update(entityPtr interface{}) (id interface{}, err error) {}
|
|
||||||
|
|
||||||
// // Delete returns whether the entity, specified by id, was successfully deleted
|
|
||||||
// // or error
|
|
||||||
// func (s *ModelService) Delete(entityPtr interface{}) error {}
|
|
@ -1,25 +0,0 @@
|
|||||||
package payments
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "os"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type Config struct {
|
|
||||||
// StripeKey string
|
|
||||||
// StripeProductID string
|
|
||||||
// RedirectURL string
|
|
||||||
// TenantSetup func(subscriptionID, customerID string) (tenantID string)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func FromEnv() Config {
|
|
||||||
// return Config{
|
|
||||||
// StripeKey: os.Getenv("STRIPE_KEY"),
|
|
||||||
// StripeProductID: os.Getenv("STRIPE_PRODUCT_ID"),
|
|
||||||
// RedirectURL: "/",
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func PrintConfig() {
|
|
||||||
// fmt.Printf("%#v\n", FromEnv())
|
|
||||||
// }
|
|
@ -1 +0,0 @@
|
|||||||
package payments
|
|
@ -1,26 +0,0 @@
|
|||||||
package payments
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "net/http"
|
|
||||||
|
|
||||||
// "github.com/jchenry/x/internal/auth"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func HasTenantAndSubscription(productID string) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
// return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
// session, err := auth.Store.Get(r, auth.SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if u, ok := session.Values["profile"]; ok {
|
|
||||||
// user := u.(auth.User)
|
|
||||||
// if _, exist := user.Apps[productID]; exist {
|
|
||||||
// next(w, r)
|
|
||||||
// } else {
|
|
||||||
// http.Redirect(w, r, "/subscription", http.StatusSeeOther)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,121 +0,0 @@
|
|||||||
package payments
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "net/http"
|
|
||||||
|
|
||||||
// "github.com/codegangsta/negroni"
|
|
||||||
// "github.com/jchenry/x/internal/auth"
|
|
||||||
// _http "github.com/jchenry/x/internal/http"
|
|
||||||
// "github.com/stripe/stripe-go"
|
|
||||||
// "github.com/stripe/stripe-go/client"
|
|
||||||
// "github.com/stripe/stripe-go/customer"
|
|
||||||
// "github.com/stripe/stripe-go/plan"
|
|
||||||
// "github.com/stripe/stripe-go/product"
|
|
||||||
// "github.com/stripe/stripe-go/sub"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func Service(c Config, auth *auth.ServiceInstance) ServiceInstance {
|
|
||||||
// stripe.Key = c.StripeKey
|
|
||||||
// sc := &client.API{}
|
|
||||||
// sc.Init(c.StripeKey, nil)
|
|
||||||
// return ServiceInstance{
|
|
||||||
// c: c,
|
|
||||||
// stripe: sc,
|
|
||||||
// auth: auth,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ServiceInstance struct {
|
|
||||||
// c Config
|
|
||||||
// stripe *client.API
|
|
||||||
// auth *auth.ServiceInstance
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (si ServiceInstance) Register(uriBase string, s *_http.Server) {
|
|
||||||
// s.Get(uriBase+"/subscription", "subscription info endpoint", negroni.New(
|
|
||||||
// negroni.HandlerFunc(auth.IsAuthenticated),
|
|
||||||
// negroni.Wrap(http.HandlerFunc(si.subscriptionHandler)),
|
|
||||||
// )).Post(uriBase+"/subscription", "subscription payment endpoint", negroni.New(
|
|
||||||
// negroni.HandlerFunc(auth.IsAuthenticated),
|
|
||||||
// negroni.Wrap(http.HandlerFunc(si.paymentHandler)),
|
|
||||||
// ))
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (si ServiceInstance) subscriptionHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
// prod, _ := product.Get(si.c.StripeProductID, nil)
|
|
||||||
|
|
||||||
// params := &stripe.PlanListParams{
|
|
||||||
// Product: &si.c.StripeProductID,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// it := plan.List(params)
|
|
||||||
// var plans []stripe.Plan
|
|
||||||
// for it.Next() {
|
|
||||||
// plans = append(plans, *it.Plan())
|
|
||||||
// }
|
|
||||||
// _http.RenderTemplate(w, "subscription", offering{Product: *prod, Plans: plans})
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type offering struct {
|
|
||||||
// Product stripe.Product
|
|
||||||
// Plans []stripe.Plan
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (si ServiceInstance) paymentHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
// session, err := auth.Store.Get(r, auth.SessionName)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if u, ok := session.Values["profile"]; ok {
|
|
||||||
// user := u.(auth.User)
|
|
||||||
// r.ParseForm()
|
|
||||||
|
|
||||||
// params := &stripe.CustomerParams{
|
|
||||||
// Email: stripe.String(user.Email),
|
|
||||||
// Name: stripe.String(fmt.Sprintf("%s, %s", user.LastName, user.FirstName)),
|
|
||||||
// }
|
|
||||||
// params.SetSource(r.PostFormValue("stripeToken"))
|
|
||||||
// cus, err := customer.New(params)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// p := &stripe.SubscriptionParams{
|
|
||||||
// Customer: stripe.String(cus.ID),
|
|
||||||
// Items: []*stripe.SubscriptionItemsParams{
|
|
||||||
// {
|
|
||||||
// Plan: stripe.String(r.PostFormValue("plan")),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// s, err := sub.New(p)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if si.c.TenantSetup == nil {
|
|
||||||
// panic("need code to setup the tenant")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if user.Apps == nil {
|
|
||||||
// user.Apps = map[string]interface{}{}
|
|
||||||
// }
|
|
||||||
// user.Apps[si.c.StripeProductID] = si.c.TenantSetup(s.ID, user.ID)
|
|
||||||
// err = si.auth.UpdateUser(user)
|
|
||||||
// if err != nil {
|
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// http.Redirect(w, r, si.c.RedirectURL, http.StatusSeeOther)
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
File diff suppressed because it is too large
Load Diff
@ -1,351 +0,0 @@
|
|||||||
%union{
|
|
||||||
str string
|
|
||||||
result Result
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%{
|
|
||||||
/*
|
|
||||||
* Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
|
|
||||||
*
|
|
||||||
* Derived from Plan 9 v4 /sys/src/cmd/pic/
|
|
||||||
*
|
|
||||||
* Copyright (C) 2003, Lucent Technologies Inc. and others.
|
|
||||||
* All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Distributed under the terms of the Lucent Public License Version 1.02.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Sccsid @(#)picy.y 1.4 (gritter) 11/28/05 */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "pic.h"
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef RAND_MAX
|
|
||||||
#define RAND_MAX 32767
|
|
||||||
#endif
|
|
||||||
|
|
||||||
YYSTYPE y;
|
|
||||||
|
|
||||||
extern void yyerror(char *);
|
|
||||||
extern int yylex(void);
|
|
||||||
%}
|
|
||||||
|
|
||||||
%token <i> BOX 1 /* DON'T CHANGE THESE! */
|
|
||||||
%token <i> LINE 2
|
|
||||||
%token <i> ARROW 3
|
|
||||||
%token <i> CIRCLE 4
|
|
||||||
%token <i> ELLIPSE 5
|
|
||||||
%token <i> ARC 6
|
|
||||||
%token <i> SPLINE 7
|
|
||||||
%token <i> BLOCK 8
|
|
||||||
%token <p> TEXT 9
|
|
||||||
%token <p> TROFF 10
|
|
||||||
%token <i> MOVE 11
|
|
||||||
%token <i> BLOCKEND 12
|
|
||||||
%token <i> PLACE 13
|
|
||||||
%token <i> PRINT RESET THRU UNTIL
|
|
||||||
%token <o> FOR IF COPY
|
|
||||||
%token <p> THENSTR ELSESTR DOSTR PLACENAME VARNAME SPRINTF
|
|
||||||
%token <st> DEFNAME
|
|
||||||
%token <i> ATTR TEXTATTR
|
|
||||||
%token <i> LEFT RIGHT UP DOWN FROM TO AT BY WITH HEAD CW CCW THEN
|
|
||||||
%token <i> HEIGHT WIDTH RADIUS DIAMETER LENGTH SIZE
|
|
||||||
%token <i> CORNER HERE LAST NTH SAME BETWEEN AND
|
|
||||||
%token <i> EAST WEST NORTH SOUTH NE NW SE SW START END
|
|
||||||
%token <i> DOTX DOTY DOTHT DOTWID DOTRAD
|
|
||||||
%token <f> NUMBER
|
|
||||||
%token <f> LOG EXP SIN COS ATAN2 SQRT RAND MIN MAX INT
|
|
||||||
%token <i> DIR
|
|
||||||
%token <i> DOT DASH CHOP FILL NOEDGE
|
|
||||||
%token <o> ST /* statement terminator */
|
|
||||||
|
|
||||||
%right <f> '='
|
|
||||||
%left <f> OROR
|
|
||||||
%left <f> ANDAND
|
|
||||||
%nonassoc <f> GT LT LE GE EQ NEQ
|
|
||||||
%left <f> '+' '-'
|
|
||||||
%left <f> '*' '/' '%'
|
|
||||||
%right <f> UMINUS NOT
|
|
||||||
%right <f> '^'
|
|
||||||
|
|
||||||
%type <f> expr if_expr asgn
|
|
||||||
%type <p> name text
|
|
||||||
%type <i> optop exprlist
|
|
||||||
%type <o> if for copy
|
|
||||||
|
|
||||||
/* this is a lie: picture and position are really the whole union */
|
|
||||||
%type <o> leftbrace picture piclist position lbracket
|
|
||||||
%type <o> prim place blockname
|
|
||||||
%type <i> textlist textattr /* not a sensible value */
|
|
||||||
%type <i> last type
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
top:
|
|
||||||
piclist
|
|
||||||
| /* empty */
|
|
||||||
| error { WARNING("syntax error"); }
|
|
||||||
;
|
|
||||||
|
|
||||||
piclist:
|
|
||||||
picture
|
|
||||||
| piclist picture
|
|
||||||
;
|
|
||||||
|
|
||||||
picture:
|
|
||||||
prim ST { codegen = 1; makeiattr(0, 0); }
|
|
||||||
| leftbrace piclist '}' { rightthing($1, '}'); $$ = $2; }
|
|
||||||
| PLACENAME ':' picture { y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
|
|
||||||
| PLACENAME ':' ST picture { y.o=$4; makevar($1,PLACENAME,y); $$ = $4; }
|
|
||||||
| PLACENAME ':' position ST { y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
|
|
||||||
| asgn ST { y.f = $1; $$ = y.o; $$ = makenode(PLACE, 0); }
|
|
||||||
| DIR { setdir($1); $$ = makenode(PLACE, 0); }
|
|
||||||
| PRINT expr ST { printexpr($2); $$ = makenode(PLACE, 0); }
|
|
||||||
| PRINT position ST { printpos($2); $$ = makenode(PLACE, 0); }
|
|
||||||
| PRINT text ST { printf("%s\n", $2); free($2); $$ = makenode(PLACE, 0); }
|
|
||||||
| RESET varlist ST { resetvar(); makeiattr(0, 0); $$ = makenode(PLACE, 0); }
|
|
||||||
| copy
|
|
||||||
| for
|
|
||||||
| if
|
|
||||||
| ST
|
|
||||||
;
|
|
||||||
|
|
||||||
varlist:
|
|
||||||
/* empty */
|
|
||||||
| VARNAME { makevattr($1); }
|
|
||||||
| varlist VARNAME { makevattr($2); }
|
|
||||||
| varlist ',' VARNAME { makevattr($3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
asgn:
|
|
||||||
VARNAME '=' expr { $$=y.f=$3; makevar($1,VARNAME,y); checkscale($1); }
|
|
||||||
;
|
|
||||||
|
|
||||||
copy:
|
|
||||||
COPY copylist { copy(); }
|
|
||||||
;
|
|
||||||
copylist:
|
|
||||||
copyattr
|
|
||||||
| copylist copyattr
|
|
||||||
;
|
|
||||||
copyattr:
|
|
||||||
text { copyfile($1); }
|
|
||||||
| THRU DEFNAME { copydef($2); }
|
|
||||||
| UNTIL text { copyuntil($2); }
|
|
||||||
;
|
|
||||||
|
|
||||||
for:
|
|
||||||
FOR name FROM expr TO expr BY optop expr DOSTR
|
|
||||||
{ forloop($2, $4, $6, $8, $9, $10); }
|
|
||||||
| FOR name FROM expr TO expr DOSTR
|
|
||||||
{ forloop($2, $4, $6, '+', 1.0, $7); }
|
|
||||||
| FOR name '=' expr TO expr BY optop expr DOSTR
|
|
||||||
{ forloop($2, $4, $6, $8, $9, $10); }
|
|
||||||
| FOR name '=' expr TO expr DOSTR
|
|
||||||
{ forloop($2, $4, $6, '+', 1.0, $7); }
|
|
||||||
;
|
|
||||||
|
|
||||||
if:
|
|
||||||
IF if_expr THENSTR ELSESTR { ifstat($2, $3, $4); }
|
|
||||||
| IF if_expr THENSTR { ifstat($2, $3, (char *) 0); }
|
|
||||||
;
|
|
||||||
if_expr:
|
|
||||||
expr
|
|
||||||
| text EQ text { $$ = strcmp($1,$3) == 0; free($1); free($3); }
|
|
||||||
| text NEQ text { $$ = strcmp($1,$3) != 0; free($1); free($3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
name:
|
|
||||||
VARNAME { y.f = 0; makevar($1, VARNAME, y); }
|
|
||||||
;
|
|
||||||
optop:
|
|
||||||
'+' { $$ = '+'; }
|
|
||||||
| '-' { $$ = '-'; }
|
|
||||||
| '*' { $$ = '*'; }
|
|
||||||
| '/' { $$ = '/'; }
|
|
||||||
| /* empty */ { $$ = ' '; }
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
leftbrace:
|
|
||||||
'{' { $$ = leftthing('{'); }
|
|
||||||
;
|
|
||||||
|
|
||||||
prim:
|
|
||||||
BOX attrlist { $$ = boxgen(); }
|
|
||||||
| CIRCLE attrlist { $$ = circgen($1); }
|
|
||||||
| ELLIPSE attrlist { $$ = circgen($1); }
|
|
||||||
| ARC attrlist { $$ = arcgen($1); }
|
|
||||||
| LINE attrlist { $$ = linegen($1); }
|
|
||||||
| ARROW attrlist { $$ = linegen($1); }
|
|
||||||
| SPLINE attrlist { $$ = linegen($1); }
|
|
||||||
| MOVE attrlist { $$ = movegen(); }
|
|
||||||
| textlist attrlist { $$ = textgen(); }
|
|
||||||
| TROFF { $$ = troffgen($1); }
|
|
||||||
| lbracket piclist ']' { $<o>$=rightthing($1,']'); } attrlist
|
|
||||||
{ $$ = blockgen($1, $<o>4); }
|
|
||||||
;
|
|
||||||
|
|
||||||
lbracket:
|
|
||||||
'[' { $$ = leftthing('['); }
|
|
||||||
;
|
|
||||||
|
|
||||||
attrlist:
|
|
||||||
attrlist attr
|
|
||||||
| /* empty */
|
|
||||||
;
|
|
||||||
|
|
||||||
attr:
|
|
||||||
ATTR expr { makefattr($1, !DEFAULT, $2); }
|
|
||||||
| ATTR { makefattr($1, DEFAULT, 0.0); }
|
|
||||||
| expr { makefattr(curdir(), !DEFAULT, $1); }
|
|
||||||
| DIR expr { makefattr($1, !DEFAULT, $2); }
|
|
||||||
| DIR { makefattr($1, DEFAULT, 0.0); }
|
|
||||||
| FROM position { makeoattr($1, $2); }
|
|
||||||
| TO position { makeoattr($1, $2); }
|
|
||||||
| AT position { makeoattr($1, $2); }
|
|
||||||
| BY position { makeoattr($1, $2); }
|
|
||||||
| WITH CORNER { makeiattr(WITH, $2); }
|
|
||||||
| WITH '.' PLACENAME { makeoattr(PLACE, getblock(getlast(1,BLOCK), $3)); }
|
|
||||||
| WITH '.' PLACENAME CORNER
|
|
||||||
{ makeoattr(PLACE, getpos(getblock(getlast(1,BLOCK), $3), $4)); }
|
|
||||||
| WITH position { makeoattr(PLACE, $2); }
|
|
||||||
| SAME { makeiattr(SAME, $1); }
|
|
||||||
| TEXTATTR { maketattr($1, (char *) 0); }
|
|
||||||
| HEAD { makeiattr(HEAD, $1); }
|
|
||||||
| DOT expr { makefattr(DOT, !DEFAULT, $2); }
|
|
||||||
| DOT { makefattr(DOT, DEFAULT, 0.0); }
|
|
||||||
| DASH expr { makefattr(DASH, !DEFAULT, $2); }
|
|
||||||
| DASH { makefattr(DASH, DEFAULT, 0.0); }
|
|
||||||
| CHOP expr { makefattr(CHOP, !DEFAULT, $2); }
|
|
||||||
| CHOP { makefattr(CHOP, DEFAULT, 0.0); }
|
|
||||||
| CHOP PLACENAME { makeattr(CHOP, PLACENAME, getvar($2)); }
|
|
||||||
| FILL expr { makefattr(FILL, !DEFAULT, $2); }
|
|
||||||
| FILL { makefattr(FILL, DEFAULT, 0.0); }
|
|
||||||
| NOEDGE { makeiattr(NOEDGE, 0); }
|
|
||||||
| textlist
|
|
||||||
;
|
|
||||||
|
|
||||||
textlist:
|
|
||||||
textattr
|
|
||||||
| textlist textattr
|
|
||||||
;
|
|
||||||
textattr:
|
|
||||||
text { maketattr(CENTER, $1); }
|
|
||||||
| text TEXTATTR { maketattr($2, $1); }
|
|
||||||
| textattr TEXTATTR { addtattr($2); }
|
|
||||||
;
|
|
||||||
text:
|
|
||||||
TEXT
|
|
||||||
| SPRINTF '(' text ')' { $$ = sprintgen($3); }
|
|
||||||
| SPRINTF '(' text ',' exprlist ')' { $$ = sprintgen($3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
exprlist:
|
|
||||||
expr { exprsave($1); $$ = 0; }
|
|
||||||
| exprlist ',' expr { exprsave($3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
position: /* absolute, not relative */
|
|
||||||
place
|
|
||||||
| '(' position ')' { $$ = $2; }
|
|
||||||
| expr ',' expr { $$ = makepos($1, $3); }
|
|
||||||
| position '+' expr ',' expr { $$ = fixpos($1, $3, $5); }
|
|
||||||
| position '-' expr ',' expr { $$ = fixpos($1, -$3, -$5); }
|
|
||||||
| position '+' '(' expr ',' expr ')' { $$ = fixpos($1, $4, $6); }
|
|
||||||
| position '-' '(' expr ',' expr ')' { $$ = fixpos($1, -$4, -$6); }
|
|
||||||
| position '+' place { $$ = addpos($1, $3); }
|
|
||||||
| position '-' place { $$ = subpos($1, $3); }
|
|
||||||
| '(' place ',' place ')' { $$ = makepos(getcomp($2,DOTX), getcomp($4,DOTY)); }
|
|
||||||
| expr LT position ',' position GT { $$ = makebetween($1, $3, $5); }
|
|
||||||
| expr BETWEEN position AND position { $$ = makebetween($1, $3, $5); }
|
|
||||||
;
|
|
||||||
|
|
||||||
place:
|
|
||||||
PLACENAME { y = getvar($1); $$ = y.o; }
|
|
||||||
| PLACENAME CORNER { y = getvar($1); $$ = getpos(y.o, $2); }
|
|
||||||
| CORNER PLACENAME { y = getvar($2); $$ = getpos(y.o, $1); }
|
|
||||||
| HERE { $$ = gethere(); }
|
|
||||||
| last type { $$ = getlast($1, $2); }
|
|
||||||
| last type CORNER { $$ = getpos(getlast($1, $2), $3); }
|
|
||||||
| CORNER last type { $$ = getpos(getlast($2, $3), $1); }
|
|
||||||
| NTH type { $$ = getfirst($1, $2); }
|
|
||||||
| NTH type CORNER { $$ = getpos(getfirst($1, $2), $3); }
|
|
||||||
| CORNER NTH type { $$ = getpos(getfirst($2, $3), $1); }
|
|
||||||
| blockname
|
|
||||||
| blockname CORNER { $$ = getpos($1, $2); }
|
|
||||||
| CORNER blockname { $$ = getpos($2, $1); }
|
|
||||||
;
|
|
||||||
|
|
||||||
blockname:
|
|
||||||
last BLOCK '.' PLACENAME { $$ = getblock(getlast($1,$2), $4); }
|
|
||||||
| NTH BLOCK '.' PLACENAME { $$ = getblock(getfirst($1,$2), $4); }
|
|
||||||
| PLACENAME '.' PLACENAME { y = getvar($1); $$ = getblock(y.o, $3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
last:
|
|
||||||
last LAST { $$ = $1 + 1; }
|
|
||||||
| NTH LAST { $$ = $1; }
|
|
||||||
| LAST { $$ = 1; }
|
|
||||||
;
|
|
||||||
|
|
||||||
type:
|
|
||||||
BOX
|
|
||||||
| CIRCLE
|
|
||||||
| ELLIPSE
|
|
||||||
| ARC
|
|
||||||
| LINE
|
|
||||||
| ARROW
|
|
||||||
| SPLINE
|
|
||||||
| BLOCK
|
|
||||||
;
|
|
||||||
|
|
||||||
expr:
|
|
||||||
NUMBER
|
|
||||||
| VARNAME { $$ = getfval($1); }
|
|
||||||
| asgn
|
|
||||||
| expr '+' expr { $$ = $1 + $3; }
|
|
||||||
| expr '-' expr { $$ = $1 - $3; }
|
|
||||||
| expr '*' expr { $$ = $1 * $3; }
|
|
||||||
| expr '/' expr { if ($3 == 0.0) {
|
|
||||||
WARNING("division by 0"); $3 = 1; }
|
|
||||||
$$ = $1 / $3; }
|
|
||||||
| expr '%' expr { if ((long)$3 == 0) {
|
|
||||||
WARNING("mod division by 0"); $3 = 1; }
|
|
||||||
$$ = (long)$1 % (long)$3; }
|
|
||||||
| '-' expr %prec UMINUS { $$ = -$2; }
|
|
||||||
| '+' expr %prec UMINUS { $$ = $2; }
|
|
||||||
| '(' expr ')' { $$ = $2; }
|
|
||||||
| place DOTX { $$ = getcomp($1, $2); }
|
|
||||||
| place DOTY { $$ = getcomp($1, $2); }
|
|
||||||
| place DOTHT { $$ = getcomp($1, $2); }
|
|
||||||
| place DOTWID { $$ = getcomp($1, $2); }
|
|
||||||
| place DOTRAD { $$ = getcomp($1, $2); }
|
|
||||||
| PLACENAME '.' VARNAME { y = getvar($1); $$ = getblkvar(y.o, $3); }
|
|
||||||
| last BLOCK '.' VARNAME { $$ = getblkvar(getlast($1,$2), $4); }
|
|
||||||
| NTH BLOCK '.' VARNAME { $$ = getblkvar(getfirst($1,$2), $4); }
|
|
||||||
| expr GT expr { $$ = $1 > $3; }
|
|
||||||
| expr LT expr { $$ = $1 < $3; }
|
|
||||||
| expr LE expr { $$ = $1 <= $3; }
|
|
||||||
| expr GE expr { $$ = $1 >= $3; }
|
|
||||||
| expr EQ expr { $$ = $1 == $3; }
|
|
||||||
| expr NEQ expr { $$ = $1 != $3; }
|
|
||||||
| expr ANDAND expr { $$ = $1 && $3; }
|
|
||||||
| expr OROR expr { $$ = $1 || $3; }
|
|
||||||
| NOT expr { $$ = !($2); }
|
|
||||||
| LOG '(' expr ')' { $$ = Log10($3); }
|
|
||||||
| EXP '(' expr ')' { $$ = Exp($3 * log(10.0)); }
|
|
||||||
| expr '^' expr { $$ = pow($1, $3); }
|
|
||||||
| SIN '(' expr ')' { $$ = sin($3); }
|
|
||||||
| COS '(' expr ')' { $$ = cos($3); }
|
|
||||||
| ATAN2 '(' expr ',' expr ')' { $$ = atan2($3, $5); }
|
|
||||||
| SQRT '(' expr ')' { $$ = Sqrt($3); }
|
|
||||||
| RAND '(' ')' { $$ = (float)rand() / RAND_MAX; }
|
|
||||||
| MAX '(' expr ',' expr ')' { $$ = $3 >= $5 ? $3 : $5; }
|
|
||||||
| MIN '(' expr ',' expr ')' { $$ = $3 <= $5 ? $3 : $5; }
|
|
||||||
| INT '(' expr ')' { $$ = (long) $3; }
|
|
||||||
;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,118 +0,0 @@
|
|||||||
package rss
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Feed is an RSS Feed
|
|
||||||
type Feed struct {
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
Link string `json:"link,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
Language string `json:"language,omitempty"`
|
|
||||||
Copyright string `json:"copyright,omitempty"`
|
|
||||||
ManagingEditor string `json:"managingEditor,omitempty"`
|
|
||||||
WebMaster string `json:"webMaster,omitempty"`
|
|
||||||
PubDate string `json:"pubDate,omitempty"`
|
|
||||||
PubDateParsed *time.Time `json:"pubDateParsed,omitempty"`
|
|
||||||
LastBuildDate string `json:"lastBuildDate,omitempty"`
|
|
||||||
LastBuildDateParsed *time.Time `json:"lastBuildDateParsed,omitempty"`
|
|
||||||
Categories []*Category `json:"categories,omitempty"`
|
|
||||||
Generator string `json:"generator,omitempty"`
|
|
||||||
Docs string `json:"docs,omitempty"`
|
|
||||||
TTL string `json:"ttl,omitempty"`
|
|
||||||
Image *Image `json:"image,omitempty"`
|
|
||||||
Rating string `json:"rating,omitempty"`
|
|
||||||
SkipHours []string `json:"skipHours,omitempty"`
|
|
||||||
SkipDays []string `json:"skipDays,omitempty"`
|
|
||||||
Cloud *Cloud `json:"cloud,omitempty"`
|
|
||||||
TextInput *TextInput `json:"textInput,omitempty"`
|
|
||||||
// DublinCoreExt *ext.DublinCoreExtension `json:"dcExt,omitempty"`
|
|
||||||
// ITunesExt *ext.ITunesFeedExtension `json:"itunesExt,omitempty"`
|
|
||||||
// Extensions ext.Extensions `json:"extensions,omitempty"`
|
|
||||||
Items []*Item `json:"items"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Feed) String() string {
|
|
||||||
json, _ := json.MarshalIndent(f, "", " ")
|
|
||||||
return string(json)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Item is an RSS Item
|
|
||||||
type Item struct {
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
Link string `json:"link,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
Content string `json:"content,omitempty"`
|
|
||||||
Author string `json:"author,omitempty"`
|
|
||||||
Categories []*Category `json:"categories,omitempty"`
|
|
||||||
Comments string `json:"comments,omitempty"`
|
|
||||||
Enclosure *Enclosure `json:"enclosure,omitempty"`
|
|
||||||
GUID *GUID `json:"guid,omitempty"`
|
|
||||||
PubDate string `json:"pubDate,omitempty"`
|
|
||||||
PubDateParsed *time.Time `json:"pubDateParsed,omitempty"`
|
|
||||||
Source *Source `json:"source,omitempty"`
|
|
||||||
// DublinCoreExt *ext.DublinCoreExtension `json:"dcExt,omitempty"`
|
|
||||||
// ITunesExt *ext.ITunesItemExtension `json:"itunesExt,omitempty"`
|
|
||||||
// Extensions ext.Extensions `json:"extensions,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image is an image that represents the feed
|
|
||||||
type Image struct {
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Link string `json:"link,omitempty"`
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
Width string `json:"width,omitempty"`
|
|
||||||
Height string `json:"height,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enclosure is a media object that is attached to
|
|
||||||
// the item
|
|
||||||
type Enclosure struct {
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Length string `json:"length,omitempty"`
|
|
||||||
Type string `json:"type,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GUID is a unique identifier for an item
|
|
||||||
type GUID struct {
|
|
||||||
Value string `json:"value,omitempty"`
|
|
||||||
IsPermalink string `json:"isPermalink,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source contains feed information for another
|
|
||||||
// feed if a given item came from that feed
|
|
||||||
type Source struct {
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Category is category metadata for Feeds and Entries
|
|
||||||
type Category struct {
|
|
||||||
Domain string `json:"domain,omitempty"`
|
|
||||||
Value string `json:"value,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TextInput specifies a text input box that
|
|
||||||
// can be displayed with the channel
|
|
||||||
type TextInput struct {
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Link string `json:"link,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cloud allows processes to register with a
|
|
||||||
// cloud to be notified of updates to the channel,
|
|
||||||
// implementing a lightweight publish-subscribe protocol
|
|
||||||
// for RSS feeds
|
|
||||||
type Cloud struct {
|
|
||||||
Domain string `json:"domain,omitempty"`
|
|
||||||
Port string `json:"port,omitempty"`
|
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
RegisterProcedure string `json:"registerProcedure,omitempty"`
|
|
||||||
Protocol string `json:"protocol,omitempty"`
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package rss
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"golang.org/x/net/html"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Parse(r io.Reader) *Feed {
|
|
||||||
|
|
||||||
// z := html.NewTokenizer(r)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseFeed(z html.Tokenizer) *Feed {
|
|
||||||
z.Next()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseVersion(z html.Tokenizer) {}
|
|
Loading…
x
Reference in New Issue
Block a user