hi

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 25, 2025 License: MIT Imports: 11 Imported by: 0

README ΒΆ

Hi - MQTT Chat Client

πŸ“Œ Overview

Hi is a terminal-based MQTT chat room that combines the MQTT protocol with Charmbracelet Bubbles to create a beautiful and interactive CLI chat tool.

πŸš€ Installation

Method 1: Using Go Install
go install github.com/longkeyy/hi@latest
Method 2: Using Homebrew (macOS/Linux)
brew install hi
Method 3: Using Package Managers

Debian/Ubuntu (.deb):

# Download from GitHub Releases
wget https://github.com/longkeyy/hi/releases/download/vX.X.X/hi_X.X.X_linux_amd64.deb
sudo dpkg -i hi_X.X.X_linux_amd64.deb

Fedora/RHEL/CentOS (.rpm):

# Download from GitHub Releases
wget https://github.com/longkeyy/hi/releases/download/vX.X.X/hi_X.X.X_linux_amd64.rpm
sudo rpm -i hi_X.X.X_linux_amd64.rpm

Alpine (.apk):

# Download from GitHub Releases
wget https://github.com/longkeyy/hi/releases/download/vX.X.X/hi_X.X.X_linux_amd64.apk
sudo apk add --allow-untrusted hi_X.X.X_linux_amd64.apk
Method 4: Build from Source
git clone https://github.com/longkeyy/hi.git
cd hi
go build -o hi

πŸ’‘ Usage

# Use default parameters (username Bell-xxxx, room hi)
hi

# Specify username and room
hi --name alice --room lobby

# Specify MQTT broker
hi --host mqtt://broker.hivemq.com:1883 --name bob

# Show version
hi --version

🎯 Features

Feature Description
βœ… MQTT Connection Connect to any MQTT broker via --host parameter, defaults to mqtt.eclipse.org:1883
βœ… Custom Username Set username with --name, used as message topic identifier
βœ… Chat Rooms Each room has a dedicated topic prefix like chatroom/room1/xxx
βœ… Send Messages Publish messages to chatroom/<room>/<name>
βœ… Receive Messages Subscribe to chatroom/<room>/# to receive all messages
βœ… Beautiful UI Message list + input box UI built with Bubbles
βœ… Sender Distinction Visual differentiation between your messages and others'

πŸ“ Project Structure

hi/
β”œβ”€β”€ go.mod                          # Go module file
β”œβ”€β”€ cmd/hi/main.go                  # CLI entry point
β”œβ”€β”€ hi.go                           # Core package API (extensible)
β”œβ”€β”€ mqtt.go                         # MQTT client (locked)
β”œβ”€β”€ model.go                        # TUI model
β”œβ”€β”€ styles.go                       # Style definitions
β”œβ”€β”€ utils.go                        # Utility functions
β”œβ”€β”€ examples/                       # Example projects
β”‚   β”œβ”€β”€ headless/                   # Headless mode example
β”‚   β”œβ”€β”€ with_keyword_replace/       # Keyword filter example
β”‚   └── plugins/                    # Example middleware plugins
└── README.md                       # Project documentation

πŸ”Œ Extensibility

The Hi package provides middleware hooks for customizing message processing:

MessageMiddleware Interface
type MessageMiddleware interface {
    // ProcessIncoming processes received messages before displaying
    ProcessIncoming(sender, content string) (string, bool)

    // ProcessOutgoing processes messages before sending
    ProcessOutgoing(content string) (string, bool)
}
Locked Components (Cannot be modified)
  • ❌ Topic structure: chatroom/<room>/<user> (locked)
  • ❌ Username format: Must end with -XXXX (4 digits, locked)
  • ❌ MQTT connection logic (locked)
Extensible Components (Can be customized)
  • βœ… Message processing before sending
  • βœ… Message processing after receiving
  • βœ… Keyword filtering/replacement
  • βœ… Encryption/Decryption (for internal development)
  • βœ… Custom message handlers

πŸ’» Development Examples

Example 1: Basic CLI Usage
package main

import (
    "log"
    "github.com/longkeyy/hi"
)

func main() {
    config := hi.Config{
        Host:     "mqtt://test.mosquitto.org:1883",
        Username: "alice",
        Room:     "lobby",
    }

    client, err := hi.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

    if err := client.Run(); err != nil {
        log.Fatal(err)
    }
}
Example 2: Keyword Filtering
package main

import (
    "log"
    "github.com/longkeyy/hi"
    "github.com/longkeyy/hi/examples/plugins"
)

func main() {
    // Create keyword replacer
    replacer := plugins.NewKeywordReplacer(map[string]string{
        "bad":   "***",
        "ugly":  "***",
    })

    config := hi.Config{
        Host:       "mqtt://test.mosquitto.org:1883",
        Username:   "alice",
        Room:       "lobby",
        Middleware: []hi.MessageMiddleware{replacer},
    }

    client, err := hi.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

    client.Run()
}
Example 3: Headless Mode (No TUI)
package main

import (
    "fmt"
    "log"
    "github.com/longkeyy/hi"
)

func main() {
    config := hi.Config{
        Host:     "mqtt://test.mosquitto.org:1883",
        Username: "bot",
        Room:     "lobby",
    }

    client, err := hi.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

    // Run without TUI
    err = client.RunHeadless(func(sender, content string) {
        fmt.Printf("[%s]: %s\n", sender, content)
    })

    if err != nil {
        log.Fatal(err)
    }

    // Send messages programmatically
    client.SendMessage("Hello from bot!")
}
Example 4: Custom Encryption Middleware (Internal)
package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "github.com/longkeyy/hi"
)

type EncryptionMiddleware struct {
    cipher cipher.Block
}

func (e *EncryptionMiddleware) ProcessIncoming(sender, content string) (string, bool) {
    // Decrypt received messages
    decrypted, _ := decrypt(e.cipher, content)
    return decrypted, true
}

func (e *EncryptionMiddleware) ProcessOutgoing(content string) (string, bool) {
    // Encrypt before sending
    encrypted, _ := encrypt(e.cipher, content)
    return encrypted, true
}

func main() {
    key := []byte("my-secret-key-32") // 32 bytes for AES-256
    cipher, _ := aes.NewCipher(key)

    config := hi.Config{
        Host:       "mqtt://test.mosquitto.org:1883",
        Username:   "secure-user",
        Room:       "secure-room",
        Middleware: []hi.MessageMiddleware{
            &EncryptionMiddleware{cipher: cipher},
        },
    }

    client, _ := hi.NewClient(config)
    client.Run()
}

βš™οΈ Configuration

Parameter Type Default Description
--host string mqtt://test.mosquitto.org:1883 MQTT broker address
--name string bell-<4 random digits> Username (must end with 4 digits), used as message topic
--room string hi Chat room name, used as topic prefix
--version bool false Show version information

πŸ”€ MQTT Topic Structure

MQTT uses the following topic model for chat communication:

chatroom/<room>/<user>
  • All users subscribe to: chatroom/<room>/#
  • Each user publishes to: chatroom/<room>/<your_name>

Example:

  • chatroom/room1/alice
  • chatroom/room1/bob

The sender can be extracted from msg.Topic().

🎨 UI Design (Bubbles + Lipgloss)

Layout
╔═══════════════════════════════╗
β•‘         MQTT Chat Room       β•‘ <- Status bar (optional)
╠═══════════════════════════════╣
β•‘ πŸ’¬ alice: Hello!              β•‘ <- Message history
β•‘ πŸ’¬ bob: Hi there~             β•‘
β•‘ πŸ’¬ me: OK let's go            β•‘ <- Your messages (green/right-aligned)
β•‘ ...                          β•‘
╠═══════════════════════════════╣
β•‘ > Type message here...       β•‘ <- textinput.Model
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
UI Features
Element Description
Input Box Implemented with bubbles/textinput
Message List Scrollable display of recent messages, max N cached
Your Messages Green color or right-aligned
Others' Messages Blue/gray color, left-aligned
Status Bar (optional) Shows username, room, connection status

πŸ“¦ Dependencies

github.com/charmbracelet/bubbletea
github.com/charmbracelet/bubbles
github.com/charmbracelet/lipgloss
github.com/eclipse/paho.mqtt.golang

πŸ”„ Message Flow

sequenceDiagram
    participant User as Your Terminal
    participant MQTT as MQTT Broker
    participant Other as Other Users

    User->>MQTT: CONNECT to mqtt.eclipse.org
    User->>MQTT: SUBSCRIBE chatroom/room1/#
    loop Chat loop
        User->>MQTT: PUBLISH chatroom/room1/<name> with msg
        MQTT-->>Other: DELIVER msg via chatroom/room1/<name>
        MQTT-->>User: ECHO msg (if subscribed)
    end

🚒 Publishing to Homebrew

After creating a GitHub release with version tag (e.g., v1.0.0):

  1. Download the release checksums from GitHub
  2. Update homebrew-formula/hi.rb with:
    • Version number
    • SHA256 checksums for each platform
  3. Submit a PR to homebrew-core
  4. Follow the Homebrew Formula Cookbook

πŸ“ License

MIT

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

This section is empty.

Functions ΒΆ

func GetPublishTopic ΒΆ

func GetPublishTopic(room, username string) string

GetPublishTopic returns the MQTT publish topic (LOCKED - for reference only)

func GetTopicPattern ΒΆ

func GetTopicPattern(room string) string

GetTopicPattern returns the MQTT topic pattern (LOCKED - for reference only)

Types ΒΆ

type Client ΒΆ

type Client struct {
	// contains filtered or unexported fields
}

Client represents the chat client instance

func NewClient ΒΆ

func NewClient(config Config) (*Client, error)

NewClient creates a new chat client with given configuration

func (*Client) Disconnect ΒΆ

func (c *Client) Disconnect()

Disconnect closes the MQTT connection

func (*Client) Run ΒΆ

func (c *Client) Run() error

Run starts the chat client with TUI

func (*Client) RunHeadless ΒΆ

func (c *Client) RunHeadless(onMessage func(sender, content string)) error

RunHeadless runs the client without TUI (for embedding)

func (*Client) SendMessage ΒΆ

func (c *Client) SendMessage(content string) error

SendMessage sends a message through the client

type Config ΒΆ

type Config struct {
	Host       string              // MQTT broker address (locked)
	Username   string              // Username (will be validated/formatted, locked format)
	Room       string              // Chat room name (locked)
	Middleware []MessageMiddleware // Message processing middleware (extensible)
}

Config represents the chat client configuration

type Message ΒΆ

type Message struct {
	Sender  string
	Content string
	IsSelf  bool
}

type MessageMiddleware ΒΆ

type MessageMiddleware interface {
	// ProcessIncoming processes received messages before displaying
	// Returns modified content and whether to continue processing
	ProcessIncoming(sender, content string) (string, bool)

	// ProcessOutgoing processes messages before sending
	// Returns modified content and whether to continue sending
	ProcessOutgoing(content string) (string, bool)
}

MessageMiddleware defines the interface for message processing plugins

Directories ΒΆ

Path Synopsis
cmd
hi command
examples
headless command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL