Lindenii Project Forge
Add package descriptions
// Package ansiec provides definitions for ANSI escape sequences. package ansiec
// Package database provides stubs and wrappers for databases.
package database import ( "context" "github.com/jackc/pgx/v5/pgxpool" ) type Database struct { *pgxpool.Pool } func Open(connString string) (Database, error) { db, err := pgxpool.New(context.Background(), connString) return Database{db}, err }
// Package embed provides embedded filesystems created in build-time.
package embed import "embed" //go:embed LICENSE* source.tar.gz var Source embed.FS //go:embed templates/* static/* //go:embed hookc/hookc git2d/git2d var Resources embed.FS
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
// Package git2c provides routines to interact with the git2d backend daemon.
package git2c import ( "fmt" "net" "git.sr.ht/~sircmpwn/go-bare" ) type Client struct { SocketPath string conn net.Conn writer *bare.Writer reader *bare.Reader } func NewClient(socketPath string) (*Client, error) { conn, err := net.Dial("unix", socketPath) if err != nil { return nil, fmt.Errorf("git2d connection failed: %w", err) } writer := bare.NewWriter(conn) reader := bare.NewReader(conn) return &Client{ SocketPath: socketPath, conn: conn, writer: writer, reader: reader, }, nil } func (c *Client) Close() error { if c.conn != nil { return c.conn.Close() } return nil }
// Package irc provides basic IRC bot functionality.
package irc import ( "crypto/tls" "log/slog" "net" "go.lindenii.runxiyu.org/forge/internal/misc" irc "go.lindenii.runxiyu.org/lindenii-irc" ) type Config struct { Net string `scfg:"net"` Addr string `scfg:"addr"` TLS bool `scfg:"tls"` SendQ uint `scfg:"sendq"` Nick string `scfg:"nick"` User string `scfg:"user"` Gecos string `scfg:"gecos"` } type Bot struct { config *Config ircSendBuffered chan string ircSendDirectChan chan misc.ErrorBack[string] } func NewBot(c *Config) (b *Bot) { b = &Bot{ config: c, } return } func (b *Bot) Connect() error { var err error var underlyingConn net.Conn if b.config.TLS { underlyingConn, err = tls.Dial(b.config.Net, b.config.Addr, nil) } else { underlyingConn, err = net.Dial(b.config.Net, b.config.Addr) } if err != nil { return err } defer underlyingConn.Close() conn := irc.NewConn(underlyingConn) logAndWriteLn := func(s string) (n int, err error) { slog.Debug("irc tx", "line", s) return conn.WriteString(s + "\r\n") } _, err = logAndWriteLn("NICK " + b.config.Nick) if err != nil { return err } _, err = logAndWriteLn("USER " + b.config.User + " 0 * :" + b.config.Gecos) if err != nil { return err } readLoopError := make(chan error) writeLoopAbort := make(chan struct{}) go func() { for { select { case <-writeLoopAbort: return default: } msg, line, err := conn.ReadMessage() if err != nil { readLoopError <- err return } slog.Debug("irc rx", "line", line) switch msg.Command { case "001": _, err = logAndWriteLn("JOIN #chat") if err != nil { readLoopError <- err return } case "PING": _, err = logAndWriteLn("PONG :" + msg.Args[0]) if err != nil { readLoopError <- err return } case "JOIN": c, ok := msg.Source.(irc.Client) if !ok { slog.Error("unable to convert source of JOIN to client") } if c.Nick != b.config.Nick { continue } default: } } }() for { select { case err = <-readLoopError: return err case line := <-b.ircSendBuffered: _, err = logAndWriteLn(line) if err != nil { select { case b.ircSendBuffered <- line: default: slog.Error("unable to requeue message", "line", line) } writeLoopAbort <- struct{}{} return err } case lineErrorBack := <-b.ircSendDirectChan: _, err = logAndWriteLn(lineErrorBack.Content) lineErrorBack.ErrorChan <- err if err != nil { writeLoopAbort <- struct{}{} return err } } } } // SendDirect sends an IRC message directly to the connection and bypasses // the buffering system. func (b *Bot) SendDirect(line string) error { ech := make(chan error, 1) b.ircSendDirectChan <- misc.ErrorBack[string]{ Content: line, ErrorChan: ech, } return <-ech } func (b *Bot) Send(line string) { select { case b.ircSendBuffered <- line: default: slog.Error("irc sendq full", "line", line) } } // TODO: Delay and warnings? func (b *Bot) ConnectLoop() { b.ircSendBuffered = make(chan string, b.config.SendQ) b.ircSendDirectChan = make(chan misc.ErrorBack[string]) for { err := b.Connect() slog.Error("irc session error", "error", err) } }
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
// Package misc provides miscellaneous functions and other definitions.
package misc import "strings" // sliceContainsNewlines returns true if and only if the given slice contains // one or more strings that contains newlines. func SliceContainsNewlines(s []string) bool { for _, v := range s { if strings.Contains(v, "\n") { return true } } return false }
// Package oldgit provides deprecated functions that depend on go-git. package oldgit
// Package render provides functions to render code and READMEs. package render
// Package unsorted is where unsorted Go files from the old structure are kept. package unsorted
// Package web provides web-facing components of the forge. package web