Initial commit: JustAMessenger v0.1.0
Серверная часть (Go): - WebSocket сервер с бинарным протоколом - XChaCha20-Poly1305 шифрование - zstd сжатие с дедупликацией (64KB чанки) - SQLite хранилище (WAL режим) - Управление гильдиями, каналами, ролями - Федерация между серверами (ed25519) - REST API + WebSocket endpoints Клиентская часть (Flutter): - Material Design 3 тёмная тема (Discord-like) - WebSocket соединение с сервером - Экраны: сплэш, логин, домашний, гильдии, чат - Модели: пользователи, гильдии, каналы, сообщения, роли - Сервисы: соединение, API, криптография, тема - Виджеты: иконки гильдий, сообщения, ввод чата - Web сборка (PWA) Документация: - AGENTS.md — контекст для ИИ ассистентов - docs/protocol.md — спецификация протокола
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
*sql.DB
|
||||
}
|
||||
|
||||
func Open(dataDir string) (*DB, error) {
|
||||
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbPath := filepath.Join(dataDir, "jam.db")
|
||||
|
||||
db, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&_busy_timeout=5000&_synchronous=NORMAL")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(1)
|
||||
db.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
d := &DB{db}
|
||||
if err := d.migrate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (db *DB) migrate() error {
|
||||
schema := `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
avatar TEXT DEFAULT '',
|
||||
bio TEXT DEFAULT '',
|
||||
public_key BLOB,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS guilds (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
owner_id TEXT NOT NULL,
|
||||
icon TEXT DEFAULT '',
|
||||
description TEXT DEFAULT '',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (owner_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS guild_members (
|
||||
guild_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
nickname TEXT DEFAULT '',
|
||||
avatar TEXT DEFAULT '',
|
||||
joined_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (guild_id, user_id),
|
||||
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS categories (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
position INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS channels (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
category_id TEXT DEFAULT '',
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL DEFAULT 'text',
|
||||
topic TEXT DEFAULT '',
|
||||
position INTEGER DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
color INTEGER DEFAULT 0,
|
||||
position INTEGER DEFAULT 0,
|
||||
permissions TEXT DEFAULT '[]',
|
||||
is_default INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS role_members (
|
||||
role_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
PRIMARY KEY (role_id, user_id),
|
||||
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
author_id TEXT NOT NULL,
|
||||
content BLOB,
|
||||
encrypted INTEGER DEFAULT 0,
|
||||
nonce BLOB,
|
||||
message_type TEXT DEFAULT 'text',
|
||||
reply_to TEXT,
|
||||
pinned INTEGER DEFAULT 0,
|
||||
self_destruct DATETIME,
|
||||
edited_at DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (author_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages(channel_id, created_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
id TEXT PRIMARY KEY,
|
||||
message_id TEXT NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
file_type TEXT DEFAULT '',
|
||||
size INTEGER DEFAULT 0,
|
||||
compressed INTEGER DEFAULT 0,
|
||||
original_size INTEGER DEFAULT 0,
|
||||
url TEXT NOT NULL,
|
||||
hash TEXT DEFAULT '',
|
||||
FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS reactions (
|
||||
message_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
emoji TEXT NOT NULL,
|
||||
PRIMARY KEY (message_id, user_id, emoji),
|
||||
FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stickers (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
data BLOB,
|
||||
format TEXT DEFAULT 'png',
|
||||
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS voice_states (
|
||||
user_id TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
guild_id TEXT NOT NULL,
|
||||
muted INTEGER DEFAULT 0,
|
||||
deafened INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (user_id, channel_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS streams (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
title TEXT DEFAULT '',
|
||||
started_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS federation_peers (
|
||||
domain TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
public_key BLOB,
|
||||
last_seen DATETIME,
|
||||
is_active INTEGER DEFAULT 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS server_config (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
`
|
||||
_, err := db.Exec(schema)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user