From d317e8f6df0e0e16445db606da1d683a6b35f531 Mon Sep 17 00:00:00 2001 From: Alexander Neonxp Kiryukhin Date: Tue, 30 Dec 2025 19:33:39 +0300 Subject: =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/qchat/main.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 cmd/qchat/main.go (limited to 'cmd') diff --git a/cmd/qchat/main.go b/cmd/qchat/main.go new file mode 100644 index 0000000..0e28ab5 --- /dev/null +++ b/cmd/qchat/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "context" + "encoding/pem" + "errors" + "flag" + "fmt" + "log/slog" + "os" + "os/signal" + + "go.neonxp.ru/qchat/internal/chat" + "go.neonxp.ru/qchat/internal/config" + "go.neonxp.ru/qchat/internal/server" + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ssh" + "golang.org/x/sync/errgroup" +) + +var ( + configFile = flag.String("config", "./config.json", "Config file") + debug = flag.Bool("debug", false, "Debug mode") + version string +) + +func main() { + flag.Parse() + if *configFile == "" { + flag.Usage() + os.Exit(1) + } + + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) + defer cancel() + + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}))) + if *debug { + slog.SetLogLoggerLevel(slog.LevelDebug) + } + + slog.InfoContext(ctx, "qChat by NeonXP. https://neonxp.ru/", slog.String("version", version)) + + cfg, err := config.Load(*configFile) + if err != nil && !errors.Is(err, os.ErrNotExist) { + panic(err) + } + if err != nil { + hostname, err := os.Hostname() + if err != nil { + panic(err) + } + _, privKey, err := ed25519.GenerateKey(nil) + if err != nil { + panic(err) + } + + privateKeyOpenSSH, err := ssh.MarshalPrivateKey(privKey, "") + if err != nil { + panic(fmt.Sprintf("Failed to marshal private key: %v", err)) + } + + cfg = &config.Config{ + Server: config.Server{ + PrivateKey: string(pem.EncodeToMemory(privateKeyOpenSSH)), + Addr: ":1337", + Name: hostname, + }, + Channels: []config.Channel{ + {Name: "main"}, + }, + } + + slog.InfoContext(ctx, "no config file. creating new.", slog.String("config", *configFile)) + if err := config.Save(*configFile, cfg); err != nil { + panic(err) + } + } + + ch := chat.New(cfg) + + serv := server.New(cfg, ch) + + eg, ectx := errgroup.WithContext(ctx) + + eg.Go(func() error { return ch.Run(ectx) }) + + eg.Go(func() error { return serv.Run(ectx) }) + + if err := eg.Wait(); err != nil { + panic(err) + } +} -- cgit v1.2.3