Make all types, functions and variables private

This commit is contained in:
Trevor Slocum 2020-10-28 18:06:34 -07:00
parent fa717894a5
commit 62a6f87203
11 changed files with 197 additions and 197 deletions

View File

@ -1,14 +1,14 @@
package main
type Author struct {
type author struct {
Key string
Name string
Email string
Notebooks []*Notebook
Notebooks []*notebook
}
var PublicAuthor = &Author{
var publicAuthor = &author{
Key: "public",
Name: "Anonymous",
Email: "anonymous@stick.app",

View File

@ -10,38 +10,38 @@ import (
)
const (
AuthorAccessRead = 0
AuthorAccessCheck = 1
AuthorAccessWrite = 2
authorAccessRead = 0
authorAccessCheck = 1
authorAccessWrite = 2
)
const DefaultConfigPath = "~/.config/stick/stick.yml"
const defaultConfigPath = "~/.config/stick/stick.yml"
type Config struct {
type config struct {
Salt string
Serve string
Authors []*AuthorConfig
Notebooks []*NotebookConfig
Authors []*authorConfig
Notebooks []*notebookConfig
Debug bool
}
type AuthorConfig struct {
type authorConfig struct {
Email string
Name string
}
type NotebookConfig struct {
type notebookConfig struct {
Label string
Repo string
Serve map[string]int
}
func ReadConfigFile(path string) (*Config, error) {
func readConfigFile(path string) (*config, error) {
var err error
if path == "" {
path = DefaultConfigPath
path = defaultConfigPath
}
path, err = expandPath(path)
if err != nil {
@ -53,18 +53,18 @@ func ReadConfigFile(path string) (*Config, error) {
return nil, err
}
c := &Config{}
c := &config{}
err = c.load(data)
return c, err
}
func ReadConfigData(data []byte) (*Config, error) {
c := &Config{}
func readConfigData(data []byte) (*config, error) {
c := &config{}
err := c.load(data)
return c, err
}
func (c *Config) load(data []byte) error {
func (c *config) load(data []byte) error {
var config map[string]interface{}
err := yaml.Unmarshal(data, &config)
if err != nil {
@ -82,7 +82,7 @@ func (c *Config) load(data []byte) error {
if as, ok := config["authors"]; ok {
auths := as.(map[interface{}]interface{})
for aemail, aname := range auths {
c.Authors = append(c.Authors, &AuthorConfig{Email: aemail.(string), Name: aname.(string)})
c.Authors = append(c.Authors, &authorConfig{Email: aemail.(string), Name: aname.(string)})
}
}
@ -94,7 +94,7 @@ func (c *Config) load(data []byte) error {
}
sort.Strings(labels)
for _, label := range labels {
nbconfig := &NotebookConfig{Label: label, Serve: make(map[string]int)}
nbconfig := &notebookConfig{Label: label, Serve: make(map[string]int)}
nbo := nbs[label].(map[interface{}]interface{})
for option, v := range nbo {
@ -106,18 +106,18 @@ func (c *Config) load(data []byte) error {
for _, nbsvi := range nbsv {
switch nbsvi.(type) {
case string:
nbconfig.Serve[nbsvi.(string)] = AuthorAccessRead
nbconfig.Serve[nbsvi.(string)] = authorAccessRead
case map[interface{}]interface{}:
nbsvx := nbsvi.(map[interface{}]interface{})
for nbsvxi, nbsvxa := range nbsvx {
access := -1
switch nbsvxa.(string) {
case "read":
access = AuthorAccessRead
access = authorAccessRead
case "check":
access = AuthorAccessCheck
access = authorAccessCheck
case "write":
access = AuthorAccessWrite
access = authorAccessWrite
}
if access == -1 {
return errors.New(fmt.Sprintf("invalid serve configuration: invalid access level specified for %s (%s should be read/check/write)", nbsvxi, nbsvxa.(string)))

View File

@ -29,7 +29,7 @@ notebooks:
- read@stick.rocketnine.space
`)
c, err := ReadConfigData(configData)
c, err := readConfigData(configData)
if err != nil {
t.Errorf("failed to load config data: %+v", err)
}
@ -42,7 +42,7 @@ notebooks:
t.Errorf("failed to read config option Salt: expected %s, got %s", "xXxN4CLxXx", c.Salt)
}
expectedAuthors := []*AuthorConfig{
expectedAuthors := []*authorConfig{
{Email: "read@stick.rocketnine.space", Name: "Read Access"},
{Email: "check@stick.rocketnine.space", Name: "Check Access"},
{Email: "write@stick.rocketnine.space", Name: "Write Access"}}
@ -54,13 +54,13 @@ notebooks:
}
}
if found != 1 {
t.Errorf("failed to read config option Author: expected 1 %v, got %d", expectedAuthor, found)
t.Errorf("failed to read config option author: expected 1 %v, got %d", expectedAuthor, found)
}
}
expectedNotebooks := []*NotebookConfig{
{Label: "Test Notebook A", Repo: "/home/stick/repo/a", Serve: map[string]int{"read@stick.rocketnine.space": AuthorAccessRead, "write@stick.rocketnine.space": AuthorAccessWrite}},
{Label: "Test Notebook B", Repo: "/home/stick/repo/b", Serve: map[string]int{"check@stick.rocketnine.space": AuthorAccessCheck, "read@stick.rocketnine.space": AuthorAccessRead}}}
expectedNotebooks := []*notebookConfig{
{Label: "Test Notebook A", Repo: "/home/stick/repo/a", Serve: map[string]int{"read@stick.rocketnine.space": authorAccessRead, "write@stick.rocketnine.space": authorAccessWrite}},
{Label: "Test Notebook B", Repo: "/home/stick/repo/b", Serve: map[string]int{"check@stick.rocketnine.space": authorAccessCheck, "read@stick.rocketnine.space": authorAccessRead}}}
for _, expectedNotebook := range expectedNotebooks {
found := 0
for _, notebook := range c.Notebooks {
@ -69,7 +69,7 @@ notebooks:
}
}
if found != 1 {
t.Errorf("failed to read config option Notebook: expected 1 %v, got %d", expectedNotebook, found)
t.Errorf("failed to read config option notebook: expected 1 %v, got %d", expectedNotebook, found)
}
}
}

4
git.go
View File

@ -4,7 +4,7 @@ import (
git "github.com/go-git/go-git/v5"
)
func InitializeRepository(worktree string, cloneurl string) (*git.Repository, error) {
func initializeRepository(worktree string, cloneurl string) (*git.Repository, error) {
if cloneurl == "" {
return git.PlainInit(worktree, false)
}
@ -14,6 +14,6 @@ func InitializeRepository(worktree string, cloneurl string) (*git.Repository, er
})
}
func LoadRepository(worktree string) (*git.Repository, error) {
func loadRepository(worktree string) (*git.Repository, error) {
return git.PlainOpen(worktree)
}

10
main.go
View File

@ -27,7 +27,7 @@ Global options:
`
var (
stick *Stick
stick *server
)
func main() {
@ -47,7 +47,7 @@ func main() {
command := flag.Arg(0)
switch command {
case "init":
Initialize(configPath, debug)
initialize(configPath, debug)
path := flag.Arg(1)
if path == "" {
@ -57,14 +57,14 @@ func main() {
cloneURL := flag.Arg(2)
_, err := InitializeRepository(path, cloneURL)
_, err := initializeRepository(path, cloneURL)
if err != nil {
panic(errors.Wrap(err, "failed to initialize notebook"))
}
fmt.Println("notebook initialized")
case "resolve":
Initialize(configPath, debug)
initialize(configPath, debug)
path := flag.Arg(1)
if path == "" {
@ -74,7 +74,7 @@ func main() {
// TODO: initialize editor to resolve conflict
case "serve":
Initialize(configPath, debug)
initialize(configPath, debug)
address := flag.Arg(1)
if stick.Config.Serve == "" && address == "" {

26
note.go
View File

@ -9,19 +9,19 @@ import (
"strings"
)
const OptionsReaderSize = 512
const optionsReaderSize = 512
var (
startsWithCheckbox = regexp.MustCompile(`^\[[ *xX]].*`)
noteHeader = []byte("[//]: # (")
)
type ListItem struct {
type listItem struct {
Indent int
Text string
}
type Note struct {
type note struct {
ID string
Label string
ModifiedAt int64
@ -29,7 +29,7 @@ type Note struct {
Body string
}
func OptionsReader(r io.Reader) []string {
func optionsReader(r io.Reader) []string {
lr := io.LimitReader(r, 9)
hdr := make([]byte, 9)
@ -45,7 +45,7 @@ func OptionsReader(r io.Reader) []string {
var (
opts []string
buf = make([]byte, OptionsReaderSize)
buf = make([]byte, optionsReaderSize)
opt []byte
)
@ -83,7 +83,7 @@ ReadOptions:
return opts
}
func Options(body string) []string {
func options(body string) []string {
if len(body) <= 10 || body[0:9] != "[//]: # (" {
return nil
}
@ -102,12 +102,12 @@ func Options(body string) []string {
return options
}
func PrintListItems(list []*ListItem, bullet string, capitalize bool) string {
func printListItems(list []*listItem, bullet string, capitalize bool) string {
var indents []int
for _, item := range list {
indents = append(indents, item.Indent)
}
indents = UniqueInts(indents)
indents = uniqueInts(indents)
sort.Ints(indents)
offsets := make(map[int]int, len(indents))
@ -187,11 +187,11 @@ func PrintListItems(list []*ListItem, bullet string, capitalize bool) string {
return out
}
func SortListItems(body string, capitalize bool) string {
func sortListItems(body string, capitalize bool) string {
var (
line string
newBody string
list []*ListItem
list []*listItem
bullet string
)
@ -201,7 +201,7 @@ func SortListItems(body string, capitalize bool) string {
thisIndent := strings.IndexAny(line, "*-")
if thisIndent == -1 || len(line) == (thisIndent+1) || line[thisIndent+1:thisIndent+2] != " " {
if list != nil {
newBody += PrintListItems(list, bullet, capitalize)
newBody += printListItems(list, bullet, capitalize)
list = nil
}
@ -211,12 +211,12 @@ func SortListItems(body string, capitalize bool) string {
bullet = line[thisIndent : thisIndent+1]
}
list = append(list, &ListItem{Indent: thisIndent, Text: strings.TrimSpace(line[thisIndent+2:])})
list = append(list, &listItem{Indent: thisIndent, Text: strings.TrimSpace(line[thisIndent+2:])})
}
}
if list != nil {
newBody += PrintListItems(list, bullet, capitalize)
newBody += printListItems(list, bullet, capitalize)
}
return newBody

View File

@ -10,15 +10,15 @@ import (
"github.com/pkg/errors"
)
/*n, err := LoadNotebook("/home/trevor/stick/personal/")
/*n, err := loadNotebook("/home/trevor/stick/personal/")
if err != nil {
panic(err)
}
log.Print(time.Unix(n.Created(), 0))
log.Print(time.Unix(n.created(), 0))
log.Print(time.Unix(n.Modified(), 0))
err = n.Upload()
err = n.upload()
if err != nil {
if strings.Contains(err.Error(), git.ErrNonFastForwardUpdate.Error()) {
log.Println("conflict while pushing")
@ -26,7 +26,7 @@ if err != nil {
panic(err)
}
}
err = n.Download()
err = n.download()
if err != nil {
if strings.Contains(err.Error(), git.ErrNonFastForwardUpdate.Error()) {
log.Println("conflict while updating")
@ -36,9 +36,9 @@ if err != nil {
}
}*/
const DefaultSubmoduleDepth = 10
const defaultSubmoduleDepth = 10
type Notebook struct {
type notebook struct {
ID string
Label string
Serve map[string]int `json:"-"`
@ -46,8 +46,8 @@ type Notebook struct {
Repository *git.Repository `json:"-"`
}
func (n *Notebook) getNote(id string, fetchBody bool) *Note {
file := n.File(id)
func (n *notebook) getNote(id string, fetchBody bool) *note {
file := n.file(id)
if file == nil {
return nil
}
@ -60,9 +60,9 @@ func (n *Notebook) getNote(id string, fetchBody bool) *Note {
}
cIter, err := r.Log(&git.LogOptions{From: ref.Hash(), Order: git.LogOrderCommitterTime, FileName: &file.Name})
CheckError(err)
checkError(err)
note := &Note{ID: id}
note := &note{ID: id}
err = cIter.ForEach(func(c *object.Commit) error {
note.ModifiedAt = c.Author.When.Unix()
@ -70,7 +70,7 @@ func (n *Notebook) getNote(id string, fetchBody bool) *Note {
return storer.ErrStop
})
CheckError(err)
checkError(err)
note.Label = file.Name
if strings.HasSuffix(strings.ToLower(note.Label), ".md") {
@ -88,40 +88,40 @@ func (n *Notebook) getNote(id string, fetchBody bool) *Note {
return note
}
func (n *Notebook) allNotes() map[string]*Note {
func (n *notebook) allNotes() map[string]*note {
r := n.Repository
ref, err := r.Head()
CheckError(err)
checkError(err)
commit, err := r.CommitObject(ref.Hash())
CheckError(err)
checkError(err)
tree, err := commit.Tree()
CheckError(err)
checkError(err)
notes := make(map[string]*Note)
notes := make(map[string]*note)
err = tree.Files().ForEach(func(f *object.File) error {
noteID := hash(f.Name)
note := n.getNote(noteID, true)
notes[noteID] = note
return nil
})
CheckError(err)
checkError(err)
return notes
}
type ServedNotebook struct {
*Notebook
Notes map[string]*Note
type servedNotebook struct {
*notebook
Notes map[string]*note
}
func NewNotebook(worktree string, cloneurl string) (*Notebook, error) {
func newNotebook(worktree string, cloneurl string) (*notebook, error) {
var err error
n := &Notebook{}
n.Repository, err = InitializeRepository(worktree, cloneurl)
n := &notebook{}
n.Repository, err = initializeRepository(worktree, cloneurl)
if err != nil {
return nil, errors.Wrap(err, "failed to initialize repository")
}
@ -129,11 +129,11 @@ func NewNotebook(worktree string, cloneurl string) (*Notebook, error) {
return n, nil
}
func LoadNotebook(worktree string) (*Notebook, error) {
func loadNotebook(worktree string) (*notebook, error) {
var err error
n := &Notebook{}
n.Repository, err = LoadRepository(worktree)
n := &notebook{}
n.Repository, err = loadRepository(worktree)
if err != nil {
return nil, errors.Wrap(err, "failed to load repository")
}
@ -141,7 +141,7 @@ func LoadNotebook(worktree string) (*Notebook, error) {
return n, nil
}
func (n *Notebook) Created() int64 {
func (n *notebook) created() int64 {
head, err := n.Repository.Head()
if err != nil {
return 0 // No commits yet
@ -167,20 +167,20 @@ func (n *Notebook) Created() int64 {
return commit.Author.When.Unix()
}
func (n *Notebook) Download() error {
func (n *notebook) download() error {
w, err := n.Repository.Worktree()
if err != nil {
return errors.Wrap(err, "failed to read worktree")
}
return w.Pull(&git.PullOptions{RemoteName: "origin", RecurseSubmodules: DefaultSubmoduleDepth})
return w.Pull(&git.PullOptions{RemoteName: "origin", RecurseSubmodules: defaultSubmoduleDepth})
}
func (n *Notebook) Upload() error {
func (n *notebook) upload() error {
return n.Repository.Push(&git.PushOptions{RemoteName: "origin"})
}
func (n *Notebook) File(id string) *object.File {
func (n *notebook) file(id string) *object.File {
var file *object.File
ref, err := n.Repository.Head()
@ -189,10 +189,10 @@ func (n *Notebook) File(id string) *object.File {
}
commit, err := n.Repository.CommitObject(ref.Hash())
CheckError(err)
checkError(err)
tree, err := commit.Tree()
CheckError(err)
checkError(err)
err = tree.Files().ForEach(func(f *object.File) error {
if hash(f.Name) == id {
@ -202,21 +202,21 @@ func (n *Notebook) File(id string) *object.File {
return nil
})
CheckError(err)
checkError(err)
return file
}
func (n *Notebook) Compact() {
func (n *notebook) compact() {
tree, err := n.Repository.Worktree()
CheckError(err)
checkError(err)
wtroot := tree.Filesystem.Root()
cmd := exec.Command("git", "-C", tree.Filesystem.Root(), "gc", "--aggressive", "--prune=now")
err = cmd.Run()
CheckError(err)
checkError(err)
n.Repository, err = LoadRepository(wtroot)
CheckError(err)
n.Repository, err = loadRepository(wtroot)
checkError(err)
}

View File

@ -21,7 +21,7 @@ func registerSignalHandlers() {
log.Println("Compacting notebooks...")
stick.NotebooksLock.Lock()
for _, notebook := range stick.Notebooks {
notebook.Compact()
notebook.compact()
}
stick.NotebooksLock.Unlock()
log.Println("Compacted notebooks")

View File

@ -7,47 +7,47 @@ import (
"github.com/pkg/errors"
)
type Stick struct {
Config *Config
type server struct {
Config *config
Authors map[string]*Author
Authors map[string]*author
AuthorsLock sync.RWMutex
Notebooks map[string]*Notebook
Notebooks map[string]*notebook
NotebooksLock sync.RWMutex
}
func Initialize(configPath string, debug bool) {
func initialize(configPath string, debug bool) {
var err error
stick = &Stick{}
stick.Config, err = ReadConfigFile(configPath)
CheckError(err)
stick = &server{}
stick.Config, err = readConfigFile(configPath)
checkError(err)
stick.Config.Debug = debug
StickSalt = []byte(stick.Config.Salt)
stickSalt = []byte(stick.Config.Salt)
stick.loadAuthors()
stick.loadNotebooks()
}
func (s *Stick) loadAuthors() {
func (s *server) loadAuthors() {
// TODO: Allow reloading config
stick.Authors = map[string]*Author{}
for _, author := range stick.Config.Authors {
stick.Authors[hash(author.Email)] = &Author{Key: hash(author.Email), Email: author.Email, Name: author.Name}
stick.Authors = map[string]*author{}
for _, a := range stick.Config.Authors {
stick.Authors[hash(a.Email)] = &author{Key: hash(a.Email), Email: a.Email, Name: a.Name}
}
stick.Authors["public"] = PublicAuthor
stick.Authors["public"] = publicAuthor
}
func (s *Stick) loadNotebooks() {
func (s *server) loadNotebooks() {
// TODO: Allow reloading config
stick.Notebooks = make(map[string]*Notebook)
stick.Notebooks = make(map[string]*notebook)
for _, nbconfig := range stick.Config.Notebooks {
notebook, err := LoadNotebook(nbconfig.Repo)
notebook, err := loadNotebook(nbconfig.Repo)
if err != nil {
log.Fatal(errors.Wrapf(err, "failed to load %s", nbconfig.Repo))
}
@ -69,7 +69,7 @@ func (s *Stick) loadNotebooks() {
stick.Notebooks[hash(nbconfig.Label)] = notebook
}
var author *Author
var author *author
for _, notebook := range stick.Notebooks {
for serveauth := range notebook.Serve {
author = stick.getAuthor(serveauth)
@ -84,7 +84,7 @@ func (s *Stick) loadNotebooks() {
}
func (s *Stick) getAuthor(key string) *Author {
func (s *server) getAuthor(key string) *author {
s.AuthorsLock.RLock()
defer s.AuthorsLock.RUnlock()
@ -95,7 +95,7 @@ func (s *Stick) getAuthor(key string) *Author {
return nil
}
func (s *Stick) getNotebook(key string) *Notebook {
func (s *server) getNotebook(key string) *notebook {
s.NotebooksLock.RLock()
defer s.NotebooksLock.RUnlock()

View File

@ -10,7 +10,7 @@ import (
"time"
)
var StickSalt []byte
var stickSalt []byte
func expandPath(path string) (string, error) {
if !strings.HasPrefix(path, "~") {
@ -25,7 +25,7 @@ func expandPath(path string) (string, error) {
return homedir + path[1:], nil
}
func UniqueInts(input []int) []int {
func uniqueInts(input []int) []int {
u := make([]int, 0, len(input))
m := make(map[int]bool)
@ -54,7 +54,7 @@ func hashWithSalt(str string, salt []byte) string {
}
func hash(str string) string {
return hashWithSalt(str, StickSalt)
return hashWithSalt(str, stickSalt)
}
func elapsed(what string) func() {
@ -64,7 +64,7 @@ func elapsed(what string) func() {
}
}
func CheckError(err error) {
func checkError(err error) {
if err != nil {
panic(err)
}

164
web.go
View File

@ -22,23 +22,23 @@ import (
)
const (
SocketBufferSize = 10
SocketPingPeriod = 2 * time.Minute
SocketReadTimeout = 5 * time.Minute
SocketWriteTimeout = 20 * time.Second
socketBufferSize = 10
socketPingPeriod = 2 * time.Minute
socketReadTimeout = 5 * time.Minute
socketWriteTimeout = 20 * time.Second
)
type StickSocket struct {
type stickSocket struct {
ID int
Status int
Conn *websocket.Conn
Author *Author
Author *author
writebuffer chan *map[string]interface{}
writebufferwg sync.WaitGroup
}
func (s *StickSocket) Write(m *map[string]interface{}) {
func (s *stickSocket) Write(m *map[string]interface{}) {
if s.Status == 0 {
return
}
@ -47,10 +47,10 @@ func (s *StickSocket) Write(m *map[string]interface{}) {
s.writebuffer <- m
}
func (s *StickSocket) handleRead() {
func (s *stickSocket) handleRead() {
var (
message []byte
c *StickSocketCommand
c *stickSocketCommand
err error
)
@ -65,9 +65,9 @@ func (s *StickSocket) handleRead() {
log.Printf("WS read %d %s", s.ID, message)
}
c = &StickSocketCommand{}
c = &stickSocketCommand{}
err = json.Unmarshal(message, &c.Data)
CheckError(err)
checkError(err)
if command, ok := c.Data["command"]; ok {
c.Command = command.(string)
@ -115,22 +115,22 @@ func (s *StickSocket) handleRead() {
if a, ok := c.Notebook.Serve[s.Author.Key]; ok {
access = a
}
if access <= AuthorAccessRead || (access == AuthorAccessCheck && c.Command != "check") {
if access <= authorAccessRead || (access == authorAccessCheck && c.Command != "check") {
s.Write(socketResponse("fail", "unauthorized"))
continue
}
if f, ok := SocketCommands[c.Command]; ok {
SocketCommandLock.Lock()
if f, ok := socketCommands[c.Command]; ok {
socketCommandLock.Lock()
s.Write(f(s, c))
SocketCommandLock.Unlock()
socketCommandLock.Unlock()
} else {
s.Write(socketResponse("fail", "invalid-command"))
}
}
}
func (s *StickSocket) handleWrite() {
func (s *stickSocket) handleWrite() {
var (
m *map[string]interface{}
out []byte
@ -144,9 +144,9 @@ func (s *StickSocket) handleWrite() {
}
out, err = json.Marshal(m)
CheckError(err)
checkError(err)
err = s.Conn.SetWriteDeadline(time.Now().Add(SocketWriteTimeout))
err = s.Conn.SetWriteDeadline(time.Now().Add(socketWriteTimeout))
if err != nil {
go s.Close("failed to set write timeout")
continue
@ -165,16 +165,16 @@ func (s *StickSocket) handleWrite() {
}
}
func (s *StickSocket) handlePing() {
err := s.Conn.SetReadDeadline(time.Now().Add(SocketReadTimeout))
func (s *stickSocket) handlePing() {
err := s.Conn.SetReadDeadline(time.Now().Add(socketReadTimeout))
if err != nil {
s.Close("failed to set read timeout")
return
}
s.Conn.SetPongHandler(func(string) error { return s.Conn.SetReadDeadline(time.Now().Add(SocketReadTimeout)) })
s.Conn.SetPongHandler(func(string) error { return s.Conn.SetReadDeadline(time.Now().Add(socketReadTimeout)) })
ticker := time.NewTicker(SocketPingPeriod)
ticker := time.NewTicker(socketPingPeriod)
defer ticker.Stop()
for {
<-ticker.C
@ -182,7 +182,7 @@ func (s *StickSocket) handlePing() {
return
}
err := s.Conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(SocketWriteTimeout))
err := s.Conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(socketWriteTimeout))
if err != nil {
s.Close("failed to ping client")
return
@ -190,9 +190,9 @@ func (s *StickSocket) handlePing() {
}
}
func (s *StickSocket) Close(reason string) {
WebSocketsLock.Lock()
defer WebSocketsLock.Unlock()
func (s *stickSocket) Close(reason string) {
webSocketsLock.Lock()
defer webSocketsLock.Unlock()
if s.Status == 0 {
return
@ -209,26 +209,26 @@ func (s *StickSocket) Close(reason string) {
close(s.writebuffer)
if s.ID > 0 {
delete(WebSockets, s.ID)
delete(webSockets, s.ID)
}
}
type StickSocketCommand struct {
type stickSocketCommand struct {
Command string
Modified int64
Notebook *Notebook
Note *Note
Notebook *notebook
Note *note
Data map[string]interface{} // Command JSON from client
}
type StickSocketHandler func(*StickSocket, *StickSocketCommand) *map[string]interface{}
type stickSocketHandler func(*stickSocket, *stickSocketCommand) *map[string]interface{}
var (
SocketCommands = map[string]StickSocketHandler{"fetch": webFetch,"edit": webEdit, "check": webCheck, "delete": webDelete}
SocketCommandLock sync.Mutex
socketCommands = map[string]stickSocketHandler{"fetch": webFetch, "edit": webEdit, "check": webCheck, "delete": webDelete}
socketCommandLock sync.Mutex
WebSockets = make(map[int]*StickSocket)
WebSocketsLock sync.RWMutex
webSockets = make(map[int]*stickSocket)
webSocketsLock sync.RWMutex
)
var upgrader = websocket.Upgrader{
@ -278,7 +278,7 @@ func webSocketHandler(w http.ResponseWriter, r *http.Request) {
if a, ok := vars["author"]; ok {
auth = a
}
var author *Author
var author *author
stick.AuthorsLock.RLock()
for stickauthkey, stickauth := range stick.Authors {
if stickauthkey == auth {
@ -288,7 +288,7 @@ func webSocketHandler(w http.ResponseWriter, r *http.Request) {
}
stick.AuthorsLock.RUnlock()
s := &StickSocket{Status: 1, Conn: conn, Author: author, writebuffer: make(chan *map[string]interface{}, SocketBufferSize)}
s := &stickSocket{Status: 1, Conn: conn, Author: author, writebuffer: make(chan *map[string]interface{}, socketBufferSize)}
go s.handleWrite()
go s.handlePing()
@ -304,16 +304,16 @@ func webSocketHandler(w http.ResponseWriter, r *http.Request) {
var (
socketID int
)
WebSocketsLock.Lock()
webSocketsLock.Lock()
for {
socketID = rand.Intn(math.MaxInt32-1) + 1
if _, ok := WebSockets[socketID]; !ok {
if _, ok := webSockets[socketID]; !ok {
s.ID = socketID
WebSockets[socketID] = s
webSockets[socketID] = s
break
}
}
WebSocketsLock.Unlock()
webSocketsLock.Unlock()
if m, ok := vars["modified"]; ok {
syncmodified, err = strconv.ParseInt(m, 10, 64)
@ -341,7 +341,7 @@ func serveWeb() {
}
}
func sendNote(ss *StickSocket, notebookID string, noteID string) {
func sendNote(ss *stickSocket, notebookID string, noteID string) {
response := map[string]interface{}{}
response["author"] = ss.Author.Name
response["notebookid"] = notebookID
@ -363,7 +363,7 @@ func sendNote(ss *StickSocket, notebookID string, noteID string) {
ss.Write(&response)
}
func sendNotesSince(ss *StickSocket, modified int64) {
func sendNotesSince(ss *stickSocket, modified int64) {
newModified := modified
author := ss.Author
@ -371,18 +371,18 @@ func sendNotesSince(ss *StickSocket, modified int64) {
response := map[string]interface{}{}
response["author"] = author.Name
response["notebooks"] = map[string]*ServedNotebook{}
response["notebooks"] = map[string]*servedNotebook{}
response["pinned"] = map[string][]string{}
for _, notebook := range author.Notebooks {
snb := &ServedNotebook{Notebook: notebook, Notes: make(map[string]*Note)}
snb := &servedNotebook{notebook: notebook, Notes: make(map[string]*note)}
ref, err := notebook.Repository.Head()
if err == nil { // Non-empty repository
commit, err := notebook.Repository.CommitObject(ref.Hash())
CheckError(err)
checkError(err)
tree, err := commit.Tree()
CheckError(err)
checkError(err)
err = tree.Files().ForEach(func(f *object.File) error {
noteID := hash(f.Name)
@ -398,7 +398,7 @@ func sendNotesSince(ss *StickSocket, modified int64) {
r, err := f.Reader()
if err == nil { // Ignore err
opts = OptionsReader(r)
opts = optionsReader(r)
for _, opt := range opts {
if opt == "pin" {
response["pinned"].(map[string][]string)[snb.ID] = append(response["pinned"].(map[string][]string)[snb.ID], noteID)
@ -410,10 +410,10 @@ func sendNotesSince(ss *StickSocket, modified int64) {
return nil
})
CheckError(err)
checkError(err)
}
response["notebooks"].(map[string]*ServedNotebook)[snb.ID] = snb
response["notebooks"].(map[string]*servedNotebook)[snb.ID] = snb
}
if modified > 0 {
@ -424,12 +424,12 @@ func sendNotesSince(ss *StickSocket, modified int64) {
}
// Fetch a note
func webFetch(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
func webFetch(s *stickSocket, c *stickSocketCommand) *map[string]interface{} {
return &map[string]interface{}{"status": "success", "notebookid": c.Notebook.ID, "noteid": c.Note.ID, "note": c.Note}
}
// Edit a note
func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
func webEdit(s *stickSocket, c *stickSocketCommand) *map[string]interface{} {
if stick.Config.Debug {
defer elapsed("webEdit")()
}
@ -450,7 +450,7 @@ func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
optSort := false
optList := false
opts := Options(body)
opts := options(body)
for _, opt := range opts {
switch opt {
case "sort":
@ -461,11 +461,11 @@ func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
}
if optSort {
body = SortListItems(body, optList)
body = sortListItems(body, optList)
}
wt, err := c.Notebook.Repository.Worktree()
CheckError(err)
checkError(err)
fileName := ""
addNew := false
@ -481,17 +481,17 @@ func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
if addNew && os.IsExist(err) {
return socketResponse("fail", "note-already-exists")
} else if !os.IsExist(err) && !os.IsNotExist(err) {
CheckError(err)
checkError(err)
}
} else {
file := c.Notebook.File(c.Note.ID)
file := c.Notebook.file(c.Note.ID)
if file == nil {
return socketResponse("fail", "failed-to-read-note")
}
fileName = file.Name
data, err := file.Contents()
CheckError(err)
checkError(err)
if data == body {
// TODO: Send unmodified message
@ -506,19 +506,19 @@ func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
// Write
status, err := wt.Status()
CheckError(err)
checkError(err)
if len(status) > 0 {
return socketResponse("fail", "modified-externally")
}
err = ioutil.WriteFile(wt.Filesystem.Join(wt.Filesystem.Root(), fileName), []byte(body), 0644)
CheckError(err)
checkError(err)
// Commit
_, err = wt.Add(fileName)
CheckError(err)
checkError(err)
commitMessage := "add"
if !addNew {
@ -532,7 +532,7 @@ func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
When: time.Now(),
},
})
CheckError(err)
checkError(err)
if c.Note == nil {
c.Note = c.Notebook.getNote(hash(fileName), true)
@ -546,7 +546,7 @@ func webEdit(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
}
// Mark/un-mark a checkbox via its item number (index)
func webCheck(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
func webCheck(s *stickSocket, c *stickSocketCommand) *map[string]interface{} {
if stick.Config.Debug {
defer elapsed("webCheck")()
}
@ -558,13 +558,13 @@ func webCheck(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
checkItem = int64(ci.(float64))
}
file := c.Notebook.File(c.Note.ID)
file := c.Notebook.file(c.Note.ID)
if file == nil {
return socketResponse("fail", "failed-to-read-note")
}
data, err := file.Contents()
CheckError(err)
checkError(err)
// Update
@ -597,10 +597,10 @@ func webCheck(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
}
wt, err := c.Notebook.Repository.Worktree()
CheckError(err)
checkError(err)
status, err := wt.Status()
CheckError(err)
checkError(err)
if len(status) > 0 {
return socketResponse("fail", "modified-externally")
@ -609,12 +609,12 @@ func webCheck(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
// Write
err = ioutil.WriteFile(wt.Filesystem.Join(wt.Filesystem.Root(), file.Name), []byte(data), 0644)
CheckError(err)
checkError(err)
// Commit
_, err = wt.Add(file.Name)
CheckError(err)
checkError(err)
_, err = wt.Commit("update "+file.Name, &git.CommitOptions{
Author: &object.Signature{
@ -623,14 +623,14 @@ func webCheck(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
When: time.Now(),
},
})
CheckError(err)
checkError(err)
updateWebSockets(s.Author, c.Notebook.ID, c.Note.ID)
return socketResponse("success", "")
}
// Delete a note
func webDelete(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
func webDelete(s *stickSocket, c *stickSocketCommand) *map[string]interface{} {
if stick.Config.Debug {
defer elapsed("webDelete")()
}
@ -639,7 +639,7 @@ func webDelete(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
err error
)
file := c.Notebook.File(c.Note.ID)
file := c.Notebook.file(c.Note.ID)
if file == nil || file.Name == "" {
return socketResponse("fail", "failed-to-read-note")
}
@ -647,22 +647,22 @@ func webDelete(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
// Delete
wt, err := c.Notebook.Repository.Worktree()
CheckError(err)
checkError(err)
status, err := wt.Status()
CheckError(err)
checkError(err)
if len(status) > 0 {
return socketResponse("fail", "modified-externally")
}
err = wt.Filesystem.Remove(file.Name)
CheckError(err)
checkError(err)
// Commit
_, err = wt.Add(file.Name)
CheckError(err)
checkError(err)
_, err = wt.Commit("delete "+file.Name, &git.CommitOptions{
Author: &object.Signature{
@ -671,7 +671,7 @@ func webDelete(s *StickSocket, c *StickSocketCommand) *map[string]interface{} {
When: time.Now(),
},
})
CheckError(err)
checkError(err)
updateWebSockets(s.Author, c.Notebook.ID, "")
return socketResponse("success", "")
@ -681,15 +681,15 @@ func socketResponse(status string, message string) *map[string]interface{} {
return &map[string]interface{}{"status": status, "message": message}
}
func updateWebSockets(author *Author, notebookID string, noteID string) {
func updateWebSockets(author *author, notebookID string, noteID string) {
stick.NotebooksLock.RLock()
defer stick.NotebooksLock.RUnlock()
WebSocketsLock.RLock()
defer WebSocketsLock.RUnlock()
webSocketsLock.RLock()
defer webSocketsLock.RUnlock()
if noteID == "" {
for _, ss := range WebSockets {
for _, ss := range webSockets {
if ss.Author.Key == author.Key {
sendNotesSince(ss, 0)
}
@ -698,7 +698,7 @@ func updateWebSockets(author *Author, notebookID string, noteID string) {
return
}
for _, ss := range WebSockets {
for _, ss := range webSockets {
if ss.Author.Key == author.Key {
sendNote(ss, notebookID, noteID)
}