diff --git a/.gitignore b/.gitignore
index 63f6eea..a156fc1 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,4 @@ cmd/sub-demo/sub-demo
cmd/auth-demo/auth-demo
.vscode/
**/.DS_Store
-
+**/*.db
diff --git a/cmd/auth-demo/main.go b/cmd/auth-demo/main.go
index b383767..de835bb 100755
--- a/cmd/auth-demo/main.go
+++ b/cmd/auth-demo/main.go
@@ -5,8 +5,8 @@ import (
"os"
"github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/auth"
- _http "github.com/jchenry/jchenry/http"
+ "github.com/jchenry/jchenry/internal/auth"
+ _http "github.com/jchenry/jchenry/internal/http"
)
func main() {
diff --git a/cmd/gcal2calendar/main.go b/cmd/gcal2calendar/main.go
new file mode 100644
index 0000000..d5ebdb7
--- /dev/null
+++ b/cmd/gcal2calendar/main.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "time"
+
+ "github.com/PuloV/ics-golang"
+)
+
+func main() {
+
+ // calendarFile = flag.String("f", os.Env, "the calendar to convert")
+ help := flag.Bool("help", false, "this help.")
+ flag.Parse()
+ if *help {
+ flag.Usage()
+ return
+ }
+
+ parser := ics.New()
+ parserChan := parser.GetInputChan()
+ outputChan := parser.GetOutputChan()
+ go func() {
+ nowYear := time.Now().Year()
+ for event := range outputChan {
+ if event.GetStart().Year() == nowYear {
+ printEvent(event)
+ }
+ }
+ }()
+
+ parserChan <- "https://calendar.google.com/calendar/ical/colin%40jchenry.me/private-ff5ffa18eb856032d166c7f410fe33c0/basic.ics"
+
+ parser.Wait()
+}
+
+func printEvent(evt *ics.Event) {
+ fmt.Printf("%s - %s : %s (%s)\n", fmtTime(evt.GetStart()), fmtTime(evt.GetEnd()), evt.GetSummary(), evt.GetLocation())
+}
+
+func fmtTime(t time.Time) string {
+ loc, err := time.LoadLocation("America/Los_Angeles")
+ if err != nil {
+ panic("bad timezone")
+ }
+
+ return t.In(loc).Format("Jan 02\t2006 15:04 MST")
+}
diff --git a/cmd/jchsh/main.go b/cmd/jchsh/main.go
new file mode 100644
index 0000000..e08dae3
--- /dev/null
+++ b/cmd/jchsh/main.go
@@ -0,0 +1,64 @@
+package main
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+ "time"
+
+ "github.com/jchenry/jchenry/pkg/arvelie"
+ "github.com/jchenry/jchenry/pkg/neralie"
+)
+
+func main() {
+ if err := run(); err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+}
+
+func run() (err error) {
+ PS1 := "[%]: "
+ reader := bufio.NewReader(os.Stdin)
+
+ for {
+ fmt.Print(PS1)
+ if input, err := reader.ReadString('\n'); err == nil {
+ if err = execute(input); err != nil {
+ fmt.Fprintf(os.Stderr, err.Error())
+ }
+ } else {
+ fmt.Fprintln(os.Stderr, err.Error())
+ }
+
+ }
+
+}
+
+func execute(input string) error {
+ input = strings.TrimSuffix(input, "\n")
+ args := strings.Split(input, " ")
+
+ switch args[0] {
+ case "cd":
+ if len(args) < 2 {
+ return errors.New("path required")
+ }
+ return os.Chdir(args[1])
+ case "now":
+ t := time.Now()
+ fmt.Printf("%s %s\n", arvelie.FromDate(t), neralie.FromTime(t))
+ return nil
+ case "exit":
+ os.Exit(0)
+ }
+
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+ return cmd.Run()
+}
diff --git a/cmd/now/main.go b/cmd/now/main.go
index dd95ecf..9f3b79d 100755
--- a/cmd/now/main.go
+++ b/cmd/now/main.go
@@ -4,7 +4,7 @@ import (
"fmt"
"time"
- "github.com/jchenry/jchenry/neralie"
+ "github.com/jchenry/jchenry/pkg/neralie"
)
func main() {
diff --git a/cmd/sub-demo/main.go b/cmd/sub-demo/main.go
index 3091e68..7d94524 100755
--- a/cmd/sub-demo/main.go
+++ b/cmd/sub-demo/main.go
@@ -5,9 +5,9 @@ import (
"os"
"github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/auth"
- _http "github.com/jchenry/jchenry/http"
- "github.com/jchenry/jchenry/payments"
+ "github.com/jchenry/jchenry/internal/auth"
+ _http "github.com/jchenry/jchenry/internal/http"
+ "github.com/jchenry/jchenry/internal/payments"
)
func main() {
diff --git a/cmd/today/main.go b/cmd/today/main.go
index ccb0f9d..a3e48c1 100755
--- a/cmd/today/main.go
+++ b/cmd/today/main.go
@@ -4,7 +4,7 @@ import (
"fmt"
"time"
- "github.com/jchenry/jchenry/arvelie"
+ "github.com/jchenry/jchenry/pkg/arvelie"
)
func main() {
diff --git a/cmd/web-tinkertoy/jch b/cmd/web-tinkertoy/jch
deleted file mode 100755
index 418ef4f..0000000
Binary files a/cmd/web-tinkertoy/jch and /dev/null differ
diff --git a/cmd/web-tinkertoy/server.go b/cmd/web-tinkertoy/server.go
index 6cbda2e..7b4204e 100644
--- a/cmd/web-tinkertoy/server.go
+++ b/cmd/web-tinkertoy/server.go
@@ -15,5 +15,4 @@ func (s *server) routes() {
s.router.HandleFunc("/time", s.handleTime())
s.router.HandleFunc("/echo", s.handleEcho())
s.router.HandleFunc("/fortune", s.handleFortune())
-
}
diff --git a/cmd/web-tinkertoy/time.go b/cmd/web-tinkertoy/time.go
index a12d2db..9239450 100644
--- a/cmd/web-tinkertoy/time.go
+++ b/cmd/web-tinkertoy/time.go
@@ -1,14 +1,22 @@
package main
import (
+ "fmt"
"io"
"net/http"
"time"
+
+ "github.com/jchenry/jchenry/arvelie"
+ "github.com/jchenry/jchenry/neralie"
)
func (s *server) handleTime() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
+ t := time.Now()
w.WriteHeader(200)
- io.WriteString(w, time.Now().String())
+ io.WriteString(w, t.String())
+ io.WriteString(w, fmt.Sprintf("\n%s %s",
+ arvelie.FromDate(t),
+ neralie.FromTime(t)))
}
}
diff --git a/cmd/wiki/edit.go b/cmd/wiki/edit.go
new file mode 100644
index 0000000..fb16702
--- /dev/null
+++ b/cmd/wiki/edit.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+ "net/http"
+ "os"
+)
+
+func edit(pageName string, w http.ResponseWriter, r *http.Request) (err error) {
+ if body, err := getFile(pageName, os.O_RDWR|os.O_CREATE); err == nil {
+ return render(pageName, "edit", body, w)
+ }
+ return
+}
diff --git a/cmd/wiki/http.go b/cmd/wiki/http.go
new file mode 100644
index 0000000..340408f
--- /dev/null
+++ b/cmd/wiki/http.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "net/http"
+ "os"
+)
+
+func auth(fn http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ user, pass, _ := r.BasicAuth()
+ if !(user == os.Getenv("WIKI_USERNAME") && pass == os.Getenv("WIKI_PASSWORD")) {
+ w.Header().Set("WWW-Authenticate", `Basic realm="wiki"`)
+ http.Error(w, "Unauthorized.", 401)
+ return
+ }
+ fn(w, r)
+ }
+}
diff --git a/cmd/wiki/main.go b/cmd/wiki/main.go
new file mode 100644
index 0000000..e057c8f
--- /dev/null
+++ b/cmd/wiki/main.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "path/filepath"
+)
+
+type actionFunc func(s string, w http.ResponseWriter, r *http.Request) error
+
+var pageDir *string
+
+func main() {
+ p, err := filepath.Abs(filepath.Dir(os.Args[0]))
+ if err != nil {
+ panic(err)
+ }
+ pageDir = flag.String("pageDir", path.Join(p, "pages"), "the directory in which pages exist")
+ httpAddr := flag.String("http", "127.0.0.1:8080", " HTTP service address")
+ help := flag.Bool("help", false, "this help.")
+ flag.Parse()
+ if *help {
+ flag.Usage()
+ return
+ }
+ for path, action := range map[string]actionFunc{"/wiki/": view, "/edit/": edit, "/save/": save, "/search/": search} {
+ register(path, action)
+ }
+ http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
+ http.Handle("/", auth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { view("WelcomeVisitors", w, r) })))
+ log.Printf("using log/pass: %s/%s", os.Getenv("WIKI_USERNAME"), os.Getenv("WIKI_PASSWORD"))
+ log.Printf("wiki has started listening at %s", *httpAddr)
+ log.Fatal(http.ListenAndServe(*httpAddr, nil))
+}
+
+func register(path string, action actionFunc) {
+ http.Handle(path, http.StripPrefix(path, auth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "" {
+ if err := action(r.URL.Path, w, r); err != nil {
+ log.Fatal(err)
+ }
+ }
+ }))))
+}
diff --git a/cmd/wiki/os.go b/cmd/wiki/os.go
new file mode 100644
index 0000000..5272ee8
--- /dev/null
+++ b/cmd/wiki/os.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "io/ioutil"
+ "os"
+ "path"
+)
+
+func getFile(pageName string, flags int) (file []byte, err error) {
+ if f, err := os.OpenFile(path.Join(*pageDir, pageName), flags, 0755); err == nil {
+ return ioutil.ReadAll(f)
+ }
+ return file, err
+}
+
+func saveFile(pageName string, contents []byte) error {
+ return ioutil.WriteFile(path.Join(*pageDir, pageName), contents, 0700)
+}
diff --git a/cmd/wiki/render.go b/cmd/wiki/render.go
new file mode 100644
index 0000000..6394d12
--- /dev/null
+++ b/cmd/wiki/render.go
@@ -0,0 +1,17 @@
+package main
+
+import (
+ "net/http"
+ "text/template"
+)
+
+func render(p string, m string, body []byte, w http.ResponseWriter) (err error) {
+ if tmpl, err := template.ParseFiles("page.tmpl.html"); err == nil {
+ return tmpl.Execute(w, struct {
+ Mode string
+ Body string
+ Page string
+ }{m, string(body), p})
+ }
+ return err
+}
diff --git a/cmd/wiki/save.go b/cmd/wiki/save.go
new file mode 100644
index 0000000..2d33fd7
--- /dev/null
+++ b/cmd/wiki/save.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+)
+
+func save(pageName string, w http.ResponseWriter, r *http.Request) (err error) {
+ r.ParseForm()
+ if err = saveFile(pageName, []byte(r.Form.Get("Text"))); err == nil {
+ http.Redirect(w, r, fmt.Sprintf("/wiki/%s", pageName), http.StatusTemporaryRedirect)
+ }
+ return
+}
diff --git a/cmd/wiki/search.go b/cmd/wiki/search.go
new file mode 100644
index 0000000..9f1eb91
--- /dev/null
+++ b/cmd/wiki/search.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "regexp"
+)
+
+const resultFmt = "%s . . . . . . %s
\n"
+
+func search(keyword string, w http.ResponseWriter, r *http.Request) (err error) {
+ var results string
+ if files, err := ioutil.ReadDir(*pageDir); err == nil {
+ re := regexp.MustCompile(keyword)
+ for _, f := range files {
+ if f.Name() == keyword {
+ results += fmt.Sprintf(resultFmt, f.Name(), f.Name(), f.Name())
+ }
+ if body, err := getFile(f.Name(), os.O_RDWR); err == nil {
+ for _, occur := range re.FindSubmatch(body) {
+ results += fmt.Sprintf(resultFmt, f.Name(), f.Name(), occur)
+ }
+ } else {
+ return err
+ }
+ }
+ render("search", "view", []byte(results), w)
+ }
+ return err
+}
diff --git a/cmd/wiki/view.go b/cmd/wiki/view.go
new file mode 100644
index 0000000..24bc2fa
--- /dev/null
+++ b/cmd/wiki/view.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "net/http"
+ "os"
+ "regexp"
+ "strings"
+
+ "github.com/russross/blackfriday/v2"
+)
+
+var patterns [5]*regexp.Regexp
+var renderers [5]func([]byte) []byte
+
+func init() {
+ // /*autoLinkRegexp*/ patterns[0], renderers[0] = regexp.MustCompile("[A-Z][a-z0-9]+([A-Z][a-z0-9]+)+"), func(s []byte) []byte { return []byte(fmt.Sprintf(`%s`, string(s), string(s))) }
+ /*BracketedAutoLinkRegexp*/
+ patterns[0], renderers[0] = regexp.MustCompile("\\[\\[[A-Za-z0-9 ]+([A-Za-z0-9 ]+)+\\]\\]"), func(s []byte) []byte { return []byte(fmt.Sprintf(`%s`, string(s), string(s))) }
+
+ /*searchRegexp*/
+ patterns[1], renderers[1] = regexp.MustCompile("\\[Search\\]"), func(s []byte) []byte {
+ return []byte(`
`)
+ }
+ /*youTubeLinkRegexp*/ patterns[2], renderers[2] = regexp.MustCompile("https://(www.)?youtube.com/watch\\?v=([-\\w]+)"), func(s []byte) []byte {
+ return []byte(fmt.Sprintf(``, strings.Split(string(s), "=")[1]))
+ }
+ /*isbnLinkRegexp*/ patterns[3], renderers[3] = regexp.MustCompile("ISBN:*([0-9]{10,})"), func(s []byte) []byte {
+ return []byte(fmt.Sprintf(`ISBN %s`, bytes.Replace(bytes.Split(s, []byte(":"))[1], []byte("-"), []byte(""), -1), bytes.Split(s, []byte(":"))[1]))
+ }
+ /*alltextRegexp*/ patterns[4], renderers[4] = regexp.MustCompile(".*"), func(s []byte) []byte {
+ return blackfriday.Run(s, blackfriday.WithExtensions(blackfriday.CommonExtensions))
+ }
+}
+
+func view(pageName string, w http.ResponseWriter, r *http.Request) (err error) {
+ var body []byte
+ if body, err = getFile(pageName, os.O_RDWR); os.IsNotExist(err) {
+ http.Redirect(w, r, fmt.Sprintf("/edit/%s", pageName), http.StatusTemporaryRedirect) // no page? redirect to edit/create it.
+ return nil
+ }
+ for i := range renderers {
+ body = patterns[i].ReplaceAllFunc(body, renderers[i])
+ }
+ return render(pageName, "view", body, w)
+}
diff --git a/go.mod b/go.mod
index 1aa2e46..bf150d6 100755
--- a/go.mod
+++ b/go.mod
@@ -3,11 +3,16 @@ module github.com/jchenry/jchenry
go 1.13
require (
+ github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade
+ github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 // indirect
github.com/codegangsta/negroni v1.0.0
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/gorilla/sessions v1.2.0
github.com/julienschmidt/httprouter v1.2.0
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
+ github.com/rsc/rsc v0.0.0-20180427141835-fc6202590229
+ github.com/russross/blackfriday/v2 v2.0.1
+ github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/stretchr/testify v1.4.0 // indirect
github.com/stripe/stripe-go v63.4.0+incompatible
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect
@@ -15,4 +20,5 @@ require (
gopkg.in/auth0.v1 v1.2.7
gopkg.in/square/go-jose.v2 v2.3.1 // indirect
rsc.io/dbstore v0.1.1
+ rsc.io/rsc v0.0.0-20180427141835-fc6202590229 // indirect
)
diff --git a/go.sum b/go.sum
index b5fb1c6..7e46086 100755
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,10 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9 h1:VE0eMvNSQI72dADsq4gm5KpNPmt97WgqneTfaS5MWrs=
github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9/go.mod h1:ItsOiHl4XeMOV3rzbZqQRjLc3QQxbE6391/9iNG7rE8=
+github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade h1:odEkSCl2gLWPtvraEdCyBZbeYyMMTysWPLMurnB8sUY=
+github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade/go.mod h1:f1P3hjG+t54/IrnXMnnw+gRmFCDR/ryj9xSQ7MPMkQw=
+github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 h1:o64h9XF42kVEUuhuer2ehqrlX8rZmvQSU0+Vpj1rF6Q=
+github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:Rp8e0DCtEKwXFOC6JPJQVTz8tuGoGvw6Xfexggh/ed0=
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
@@ -19,6 +23,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/rsc/rsc v0.0.0-20180427141835-fc6202590229 h1:s5M0EEh5JyTx0PrhLGlog+CegHIkmiCd07ht20coRtA=
+github.com/rsc/rsc v0.0.0-20180427141835-fc6202590229/go.mod h1:TJRSe/n0/H37q9TsEwBtcOz32UX+UWqgapLwsXTV4jE=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -53,5 +64,7 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
rsc.io/dbstore v0.1.1 h1:LI4gBJUwbejn0wHJWe0KTwgCM33zUVP3BsNz5y2fkEE=
rsc.io/dbstore v0.1.1/go.mod h1:zI7k1PCSLg9r/T2rBM4E/SctbGmqdtt3kjQSemVh1Rs=
+rsc.io/rsc v0.0.0-20180427141835-fc6202590229 h1:6s5zUknxnRp4D3GlNb7uDzlcfFVq9G2ficO+k4Bcb6w=
+rsc.io/rsc v0.0.0-20180427141835-fc6202590229/go.mod h1:nHU4RAWoD9u1Hr+vTW0mktVbANmwCPkTwT2xNpVs/70=
rsc.io/sqlite v0.5.0 h1:HG63YxeP0eALjqorwnJ9ENxUUOUR6NYJ4FHEKFJ7aVk=
rsc.io/sqlite v0.5.0/go.mod h1:fqHuveM9iIqMzjD0WiZIvKYMty/WqTo2bxE9+zC54WE=
diff --git a/auth/auth.go b/internal/auth/auth.go
similarity index 100%
rename from auth/auth.go
rename to internal/auth/auth.go
diff --git a/auth/callback.go b/internal/auth/callback.go
similarity index 100%
rename from auth/callback.go
rename to internal/auth/callback.go
diff --git a/auth/config.go b/internal/auth/config.go
similarity index 100%
rename from auth/config.go
rename to internal/auth/config.go
diff --git a/auth/login.go b/internal/auth/login.go
similarity index 100%
rename from auth/login.go
rename to internal/auth/login.go
diff --git a/auth/logout.go b/internal/auth/logout.go
similarity index 100%
rename from auth/logout.go
rename to internal/auth/logout.go
diff --git a/auth/middleware.go b/internal/auth/middleware.go
similarity index 100%
rename from auth/middleware.go
rename to internal/auth/middleware.go
diff --git a/auth/service.go b/internal/auth/service.go
similarity index 95%
rename from auth/service.go
rename to internal/auth/service.go
index 6bd2c70..21afd76 100755
--- a/auth/service.go
+++ b/internal/auth/service.go
@@ -4,7 +4,7 @@ import (
"net/http"
"github.com/codegangsta/negroni"
- _http "github.com/jchenry/jchenry/http"
+ _http "github.com/jchenry/jchenry/internal/http"
"gopkg.in/auth0.v1/management"
)
diff --git a/auth/session.go b/internal/auth/session.go
similarity index 100%
rename from auth/session.go
rename to internal/auth/session.go
diff --git a/auth/user.go b/internal/auth/user.go
similarity index 92%
rename from auth/user.go
rename to internal/auth/user.go
index 8700f29..98b5741 100755
--- a/auth/user.go
+++ b/internal/auth/user.go
@@ -3,7 +3,7 @@ package auth
import (
"net/http"
- jchenry_http "github.com/jchenry/jchenry/http"
+ jchenry_http "github.com/jchenry/jchenry/internal/http"
)
func UserHandler(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/crud/service.go b/internal/crud/service.go
new file mode 100644
index 0000000..5618f2d
--- /dev/null
+++ b/internal/crud/service.go
@@ -0,0 +1,44 @@
+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
+}
diff --git a/data/db_collection_store.go b/internal/data/db_collection_store.go
similarity index 100%
rename from data/db_collection_store.go
rename to internal/data/db_collection_store.go
diff --git a/internal/http/auth.go b/internal/http/auth.go
new file mode 100644
index 0000000..f81c965
--- /dev/null
+++ b/internal/http/auth.go
@@ -0,0 +1,18 @@
+package http
+
+import (
+ "net/http"
+ "os"
+)
+
+func BasicAuth(fn http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ user, pass, _ := r.BasicAuth()
+ if !(user == os.Getenv("WIKI_USERNAME") && pass == os.Getenv("WIKI_PASSWORD")) {
+ w.Header().Set("WWW-Authenticate", `Basic realm="wiki"`)
+ http.Error(w, "Unauthorized.", 401)
+ return
+ }
+ fn(w, r)
+ }
+}
diff --git a/http/julienschmidt_router.go b/internal/http/julienschmidt_router.go
similarity index 100%
rename from http/julienschmidt_router.go
rename to internal/http/julienschmidt_router.go
diff --git a/http/server.go b/internal/http/server.go
similarity index 97%
rename from http/server.go
rename to internal/http/server.go
index f3238af..5c6063f 100755
--- a/http/server.go
+++ b/internal/http/server.go
@@ -7,8 +7,8 @@ import (
)
type Middleware interface {
+ go_http.Handler
UseHandler(handler http.Handler)
- ServeHTTP(w go_http.ResponseWriter, req *go_http.Request)
}
type Router interface {
diff --git a/http/server_test.go b/internal/http/server_test.go
similarity index 100%
rename from http/server_test.go
rename to internal/http/server_test.go
diff --git a/internal/http/service.go b/internal/http/service.go
new file mode 100644
index 0000000..bf0f23c
--- /dev/null
+++ b/internal/http/service.go
@@ -0,0 +1,28 @@
+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"
diff --git a/http/templates.go b/internal/http/templates.go
similarity index 74%
rename from http/templates.go
rename to internal/http/templates.go
index 1cf0e9c..0e6500c 100755
--- a/http/templates.go
+++ b/internal/http/templates.go
@@ -21,3 +21,10 @@ func RenderTemplate(w http.ResponseWriter, tmpl string, data interface{}) {
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
+}
diff --git a/http/util.go b/internal/http/util.go
similarity index 100%
rename from http/util.go
rename to internal/http/util.go
diff --git a/model/database_model.go b/internal/model/database_model.go
similarity index 100%
rename from model/database_model.go
rename to internal/model/database_model.go
diff --git a/payments/config.go b/internal/payments/config.go
similarity index 100%
rename from payments/config.go
rename to internal/payments/config.go
diff --git a/payments/doc.go b/internal/payments/doc.go
similarity index 100%
rename from payments/doc.go
rename to internal/payments/doc.go
diff --git a/payments/middleware.go b/internal/payments/middleware.go
similarity index 93%
rename from payments/middleware.go
rename to internal/payments/middleware.go
index 59d5c86..64a26d5 100755
--- a/payments/middleware.go
+++ b/internal/payments/middleware.go
@@ -3,7 +3,7 @@ package payments
import (
"net/http"
- "github.com/jchenry/jchenry/auth"
+ "github.com/jchenry/jchenry/internal/auth"
)
func HasTenantAndSubscription(productID string) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
diff --git a/payments/service.go b/internal/payments/service.go
similarity index 96%
rename from payments/service.go
rename to internal/payments/service.go
index 3e964bd..abd1895 100755
--- a/payments/service.go
+++ b/internal/payments/service.go
@@ -5,8 +5,8 @@ import (
"net/http"
"github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/auth"
- _http "github.com/jchenry/jchenry/http"
+ "github.com/jchenry/jchenry/internal/auth"
+ _http "github.com/jchenry/jchenry/internal/http"
"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/client"
"github.com/stripe/stripe-go/customer"
diff --git a/pic/parser.go b/internal/pic/parser.go
similarity index 100%
rename from pic/parser.go
rename to internal/pic/parser.go
diff --git a/pic/pic.y b/internal/pic/pic.y
similarity index 100%
rename from pic/pic.y
rename to internal/pic/pic.y
diff --git a/pic/y.output b/internal/pic/y.output
similarity index 100%
rename from pic/y.output
rename to internal/pic/y.output
diff --git a/rest/collection.go b/internal/rest/collection.go
similarity index 99%
rename from rest/collection.go
rename to internal/rest/collection.go
index d8bd7cc..1ef83dd 100755
--- a/rest/collection.go
+++ b/internal/rest/collection.go
@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
- _http "github.com/jchenry/jchenry/http"
+ _http "github.com/jchenry/jchenry/internal/http"
)
const (
diff --git a/rest/collection_test.go b/internal/rest/collection_test.go
similarity index 100%
rename from rest/collection_test.go
rename to internal/rest/collection_test.go
diff --git a/rest/resultset_response.go b/internal/rest/resultset_response.go
similarity index 100%
rename from rest/resultset_response.go
rename to internal/rest/resultset_response.go
diff --git a/arvelie/arvelie.go b/pkg/arvelie/arvelie.go
similarity index 100%
rename from arvelie/arvelie.go
rename to pkg/arvelie/arvelie.go
diff --git a/arvelie/arvelie_test.go b/pkg/arvelie/arvelie_test.go
similarity index 100%
rename from arvelie/arvelie_test.go
rename to pkg/arvelie/arvelie_test.go
diff --git a/arvelie/doc.go b/pkg/arvelie/doc.go
similarity index 100%
rename from arvelie/doc.go
rename to pkg/arvelie/doc.go
diff --git a/db/actor.go b/pkg/db/actor.go
similarity index 100%
rename from db/actor.go
rename to pkg/db/actor.go
diff --git a/db/doc.go b/pkg/db/doc.go
similarity index 100%
rename from db/doc.go
rename to pkg/db/doc.go
diff --git a/neralie/doc.go b/pkg/neralie/doc.go
similarity index 100%
rename from neralie/doc.go
rename to pkg/neralie/doc.go
diff --git a/neralie/neralie.go b/pkg/neralie/neralie.go
similarity index 100%
rename from neralie/neralie.go
rename to pkg/neralie/neralie.go
diff --git a/neralie/neralie_test.go b/pkg/neralie/neralie_test.go
similarity index 100%
rename from neralie/neralie_test.go
rename to pkg/neralie/neralie_test.go
diff --git a/pkg/snowflake/README.md b/pkg/snowflake/README.md
new file mode 100644
index 0000000..7fcf124
--- /dev/null
+++ b/pkg/snowflake/README.md
@@ -0,0 +1,27 @@
+# snowflake
+
+A snowflake ID generator based on instagram and twitter's snowflake concept
+
+## Install
+
+```
+go get github.com/jchenry/snowflake
+```
+
+## Usage
+
+```
+import "github.com/jchenry/snowflake"
+
+func main(){
+ snowflake.Next()
+}
+```
+
+## Contributing
+
+PRs accepted.
+
+## License
+
+MIT © Colin Henry
diff --git a/pkg/snowflake/snowflake.go b/pkg/snowflake/snowflake.go
new file mode 100755
index 0000000..b606028
--- /dev/null
+++ b/pkg/snowflake/snowflake.go
@@ -0,0 +1,91 @@
+package snowflake
+
+import (
+ "fmt"
+ "hash/fnv"
+ "math"
+ "net"
+ "sync"
+ "time"
+)
+
+const (
+ totalBits = 64
+ epochBits = 32
+ nodeIDBits = 10
+ sequenceBits = 12
+
+ // Custom Epoch (January 1, 2015 Midnight UTC = 2015-01-01T00:00:00Z)
+ customEpoch uint64 = 1420070400000
+)
+
+var maxNodeID uint64
+var maxSequence uint64
+
+var nodeID uint64
+var lastTimestamp uint64 = 0
+var sequence uint64
+
+func init() {
+ maxNodeID = uint64(math.Pow(2, nodeIDBits) - 1)
+ maxSequence = uint64(math.Pow(2, sequenceBits) - 1)
+ nodeID = generateNodeID()
+}
+
+func generateNodeID() uint64 {
+ var nodeID uint64
+ if interfaces, err := net.Interfaces(); err == nil {
+ h := fnv.New32a()
+ for _, i := range interfaces {
+ h.Write(i.HardwareAddr)
+ }
+ nodeID = uint64(h.Sum32())
+ } else {
+ panic("interfaces not available")
+ }
+ nodeID = nodeID & maxNodeID
+ return nodeID
+}
+
+var timestampMutex sync.Mutex
+var sequenceMutex sync.Mutex
+
+// Next returns the next logical snowflake
+func Next() uint64 {
+ timestampMutex.Lock()
+ currentTimestamp := ts()
+ timestampMutex.Unlock()
+
+ sequenceMutex.Lock()
+ if currentTimestamp == lastTimestamp {
+ sequence = (sequence + 1) & maxSequence
+ if sequence == 0 {
+ // Sequence Exhausted, wait till next millisecond.
+ currentTimestamp = waitNextMillis(currentTimestamp)
+ }
+ } else {
+ sequence = 0
+ }
+ sequenceMutex.Unlock()
+
+ lastTimestamp = currentTimestamp
+ id := currentTimestamp << (totalBits - epochBits)
+ fmt.Printf("%b\n", id)
+ id |= (nodeID << (totalBits - epochBits - nodeIDBits))
+ fmt.Printf("%b\n", id)
+
+ id |= sequence
+ fmt.Printf("%b\n", id)
+ return id
+}
+
+func ts() uint64 {
+ return uint64(time.Now().UnixNano()/1000000) - customEpoch
+}
+
+func waitNextMillis(currentTimestamp uint64) uint64 {
+ for currentTimestamp == lastTimestamp {
+ currentTimestamp = ts()
+ }
+ return currentTimestamp
+}
diff --git a/pkg/snowflake/snowflake_test.go b/pkg/snowflake/snowflake_test.go
new file mode 100755
index 0000000..a6ddcb4
--- /dev/null
+++ b/pkg/snowflake/snowflake_test.go
@@ -0,0 +1,25 @@
+package snowflake
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestNext(t *testing.T) {
+ fmt.Printf("node id: %b\n", generateNodeID())
+ fmt.Printf("timestamp: %b\n", ts())
+ fmt.Printf("full token: %b\n", Next())
+ // t.Fail()
+}
+
+func BenchmarkNext(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ Next()
+ }
+}
+
+func BenchmarkNextParallel(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ go Next()
+ }
+}
diff --git a/tablatal/doc.go b/pkg/tablatal/doc.go
similarity index 100%
rename from tablatal/doc.go
rename to pkg/tablatal/doc.go
diff --git a/tablatal/tabatal.go b/pkg/tablatal/tabatal.go
similarity index 100%
rename from tablatal/tabatal.go
rename to pkg/tablatal/tabatal.go
diff --git a/scripts/bin/openapigen.bash b/scripts/bin/openapigen.bash
new file mode 100755
index 0000000..a4ea025
--- /dev/null
+++ b/scripts/bin/openapigen.bash
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
+ -i $1 \ #https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml \
+ -g go \
+ -o /local/out/go
\ No newline at end of file
diff --git a/scripts/bin/tel.bash b/scripts/bin/tel.bash
new file mode 100755
index 0000000..40d1246
--- /dev/null
+++ b/scripts/bin/tel.bash
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+# A port of plan9 'tel' program
+
+for var in "$@"
+do
+ if test -f "$HOME/.tel"; then
+ grep -i $1 $HOME/.tel
+ fi
+
+ grep -hi $1 /usr/lib/tel /usr/lib/areacodes
+done
+
+exit
+
+