]> Sergey Matveev's repositories - mmc.git/blobdiff - cmd/mmc/main.go
Ability to connect to http:// entrypoints
[mmc.git] / cmd / mmc / main.go
index 159674709388922f2030b490877657ed2e744991..79a850ab48a4992096c347bbd54ab4903a0c5d69 100644 (file)
@@ -1,5 +1,5 @@
 // mmc -- Mattermost client
-// Copyright (C) 2023 Sergey Matveev <stargrave@stargrave.org>
+// Copyright (C) 2023-2024 Sergey Matveev <stargrave@stargrave.org>
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU Affero General Public License as
@@ -26,6 +26,7 @@ import (
        "io"
        "io/fs"
        "log"
+       "net/url"
        "os"
        "os/exec"
        "os/signal"
@@ -38,11 +39,10 @@ import (
 
        "github.com/davecgh/go-spew/spew"
        "github.com/mattermost/mattermost-server/v6/model"
+       "go.cypherpunks.ru/netrc"
        "go.stargrave.org/mmc"
 )
 
-const CmdFile = "/FILE "
-
 var (
        Newwin   = flag.String("newwin", "cmd/newwin", "Path to newwin command")
        DebugFd  *os.File
@@ -51,13 +51,22 @@ var (
 
 func rewriteIfChanged(fn string, data string) {
        if their, err := os.ReadFile(fn); err != nil ||
-               bytes.Compare([]byte(data), their) != 0 {
+               !bytes.Equal([]byte(data), their) {
                if err = os.WriteFile(fn, []byte(data), 0o666); err != nil {
                        log.Fatalln(err)
                }
        }
 }
 
+func mkFifo(pth string) {
+       if _, err := os.Stat(pth); err == nil {
+               return
+       }
+       if err := syscall.Mkfifo(pth, 0666); err != nil {
+               log.Fatalln(err)
+       }
+}
+
 func main() {
        entrypoint := flag.String("entrypoint", mmc.GetEntrypoint(), "Entrypoint")
        notifyCmd := flag.String("notify", "cmd/notify", "Path to notification handler")
@@ -68,11 +77,8 @@ func main() {
        UmaskCur = syscall.Umask(0)
        syscall.Umask(UmaskCur)
 
-       os.Remove("debug")
-       err := syscall.Mkfifo("debug", 0666)
-       if err != nil {
-               log.Fatalln(err)
-       }
+       mkFifo("debug")
+       var err error
        DebugFd, err = os.OpenFile(
                "debug", os.O_WRONLY|os.O_APPEND, os.FileMode(0666),
        )
@@ -81,11 +87,15 @@ func main() {
        }
        defer DebugFd.Close()
 
-       login, password := mmc.FindInNetrc(*entrypoint)
+       entrypointURL, err := url.Parse(*entrypoint)
+       if err != nil {
+               log.Fatalln(err)
+       }
+       login, password := netrc.Find(entrypointURL.Hostname())
        if login == "" || password == "" {
-               log.Fatalln("no credentials found for:", *entrypoint)
+               log.Fatalln("no credentials found for:", entrypointURL.Hostname())
        }
-       c := model.NewAPIv4Client("https://" + *entrypoint)
+       c := model.NewAPIv4Client(*entrypoint)
        c.Login(login, password)
        me, resp, err := c.GetMe("")
        if err != nil {
@@ -150,10 +160,7 @@ func main() {
                }
 
                usersPth := path.Join(pth, "users")
-               os.Remove(usersPth)
-               if err := syscall.Mkfifo(usersPth, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(usersPth)
                go func(ch *model.Channel) {
                        for {
                                time.Sleep(mmc.SleepTime)
@@ -189,10 +196,7 @@ func main() {
                }(ch)
 
                pth = path.Join(pth, "in")
-               os.Remove(pth)
-               if err := syscall.Mkfifo(pth, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(pth)
                go func(ch *model.Channel) {
                        for {
                                fd, err := os.OpenFile(pth, os.O_RDONLY, os.FileMode(0666))
@@ -253,10 +257,7 @@ func main() {
                }
 
                statusPth := path.Join(pth, "status")
-               os.Remove(statusPth)
-               if err := syscall.Mkfifo(statusPth, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(statusPth)
                go func(u *model.User) {
                        for {
                                time.Sleep(mmc.SleepTime)
@@ -285,10 +286,7 @@ func main() {
                }(u)
 
                pth = path.Join(pth, "in")
-               os.Remove(pth)
-               if err := syscall.Mkfifo(pth, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(pth)
                go func(u *model.User) {
                        var dc *model.Channel
                        for {
@@ -327,10 +325,7 @@ func main() {
        var UserStatusM sync.RWMutex
        go func() {
                pth := path.Join("users", "status")
-               os.Remove(pth)
-               if err := syscall.Mkfifo(pth, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(pth)
                for {
                        time.Sleep(mmc.SleepTime)
                        fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
@@ -338,15 +333,20 @@ func main() {
                                log.Println("OpenFile:", pth, err)
                                continue
                        }
-                       statuses := make(map[string][]string)
+                       agg := make(map[string][]string)
                        UserStatusM.RLock()
                        for name, status := range UserStatus {
-                               statuses[status] = append(statuses[status], name)
+                               agg[status] = append(agg[status], name)
                        }
                        UserStatusM.RUnlock()
-                       for status := range statuses {
-                               sort.Strings(statuses[status])
-                               fmt.Fprintln(fd, status+":", strings.Join(statuses[status], " "))
+                       statuses := make([]string, 0, len(agg))
+                       for status := range agg {
+                               sort.Strings(agg[status])
+                               statuses = append(statuses, status)
+                       }
+                       sort.Strings(statuses)
+                       for _, status := range statuses {
+                               fmt.Fprintln(fd, status+":", strings.Join(agg[status], " "))
                        }
                        fd.Close()
                }
@@ -368,15 +368,9 @@ func main() {
        go func() {
                os.MkdirAll("file", 0777)
                pthGet := path.Join("file", "get")
-               os.Remove(pthGet)
-               if err := syscall.Mkfifo(pthGet, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(pthGet)
                pthOut := path.Join("file", "out")
-               os.Remove(pthOut)
-               if err := syscall.Mkfifo(pthOut, 0666); err != nil {
-                       log.Fatalln(err)
-               }
+               mkFifo(pthOut)
                for {
                        time.Sleep(mmc.SleepTime)
                        fd, err := os.OpenFile(pthGet, os.O_RDONLY, os.FileMode(0666))
@@ -450,7 +444,15 @@ func main() {
        }()
 
        needsShutdown := make(chan os.Signal)
-       wc, err := model.NewWebSocketClient4("wss://"+*entrypoint, c.AuthToken)
+       switch entrypointURL.Scheme {
+       case "http":
+               entrypointURL.Scheme = "ws"
+       case "https":
+               entrypointURL.Scheme = "wss"
+       default:
+               log.Println("unhandled scheme:", entrypointURL.Scheme)
+       }
+       wc, err := model.NewWebSocketClient4(entrypointURL.String(), c.AuthToken)
        if err != nil {
                log.Fatalln(err)
        }
@@ -520,7 +522,7 @@ func main() {
                                                userId = strings.TrimSuffix(userId, "__"+me.Id)
                                                user := Users[userId]
                                                if user == nil {
-                                                       log.Println("unknown user:", post)
+                                                       log.Println("unknown user:", userId)
                                                        continue
                                                }
                                                recipient = path.Join("users", user.Username)