This commit is contained in:
2025-12-02 11:06:23 +09:00
parent bf40c42c2c
commit 22caf64855
34 changed files with 4594 additions and 505 deletions
@@ -4,44 +4,61 @@ import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
part 'ephemeral_database.g.dart'; // (나중에 생성될 파일)
part 'ephemeral_database.g.dart';
// 테이블 정의: 미디어 메타데이터
// 기존 MediaItems 테이블
class MediaItems extends Table {
TextColumn get id => text()(); // UUID
TextColumn get id => text()();
TextColumn get senderId => text()();
TextColumn get senderName => text()();
TextColumn get type => text()(); // 'IMAGE', 'VIDEO', 'AUDIO'
TextColumn get filePath => text()(); // 로컬 저장 경로
TextColumn get type => text()();
TextColumn get filePath => text()();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
@override
Set<Column> get primaryKey => {id};
}
@DriftDatabase(tables: [MediaItems])
// [추가] 패킷 로그 테이블 (재전송용)
class PacketLogs extends Table {
IntColumn get seq => integer()(); // 순번 (Primary Key)
TextColumn get payload => text()(); // JSON 데이터
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
@override
Set<Column> get primaryKey => {seq};
}
@DriftDatabase(tables: [MediaItems, PacketLogs]) // [수정] PacketLogs 추가
class EphemeralDatabase extends _$EphemeralDatabase {
// 싱글톤이 아닌 인스턴스로 관리 (방 만들 때 생성, 나갈 때 close)
EphemeralDatabase(QueryExecutor e) : super(e);
@override
int get schemaVersion => 1;
int get schemaVersion => 2; // [수정] 버전 업 (기존 앱 삭제 후 설치 권장)
// 팩토리: 파일 기반 DB 생성
static Future<EphemeralDatabase> create(String roomName) async {
final dbFolder = await getApplicationDocumentsDirectory();
// 방 이름이나 ID로 파일명 구분
final file = File(p.join(dbFolder.path, 'room_$roomName.sqlite'));
return EphemeralDatabase(NativeDatabase(file));
}
// CRUD 쿼리
Future<List<MediaItem>> getAllMedia() => select(mediaItems).get();
Future<int> insertMedia(MediaItemsCompanion entry) => into(mediaItems).insert(entry);
// [핵심] 방 폭파 시 데이터 삭제
// [추가] 패킷 저장
Future<int> logPacket(int seq, String json) {
return into(packetLogs).insert(PacketLogsCompanion(
seq: Value(seq),
payload: Value(json),
));
}
// [추가] 특정 범위의 패킷 가져오기 (재전송 요청 시 사용)
Future<List<PacketLog>> getPacketsInRange(int fromSeq, int toSeq) {
return (select(packetLogs)..where((tbl) => tbl.seq.isBetweenValues(fromSeq, toSeq))).get();
}
Future<void> wipeData() async {
await close(); // DB 연결 종료
// 실제 파일 삭제 로직은 Manager에서 수행 (DB 파일 자체를 날림)
await close();
}
}
@@ -351,15 +351,229 @@ class MediaItemsCompanion extends UpdateCompanion<MediaItem> {
}
}
class $PacketLogsTable extends PacketLogs
with TableInfo<$PacketLogsTable, PacketLog> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$PacketLogsTable(this.attachedDatabase, [this._alias]);
static const VerificationMeta _seqMeta = const VerificationMeta('seq');
@override
late final GeneratedColumn<int> seq = GeneratedColumn<int>(
'seq', aliasedName, false,
type: DriftSqlType.int, requiredDuringInsert: false);
static const VerificationMeta _payloadMeta =
const VerificationMeta('payload');
@override
late final GeneratedColumn<String> payload = GeneratedColumn<String>(
'payload', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true);
static const VerificationMeta _createdAtMeta =
const VerificationMeta('createdAt');
@override
late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
'created_at', aliasedName, false,
type: DriftSqlType.dateTime,
requiredDuringInsert: false,
defaultValue: currentDateAndTime);
@override
List<GeneratedColumn> get $columns => [seq, payload, createdAt];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'packet_logs';
@override
VerificationContext validateIntegrity(Insertable<PacketLog> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('seq')) {
context.handle(
_seqMeta, seq.isAcceptableOrUnknown(data['seq']!, _seqMeta));
}
if (data.containsKey('payload')) {
context.handle(_payloadMeta,
payload.isAcceptableOrUnknown(data['payload']!, _payloadMeta));
} else if (isInserting) {
context.missing(_payloadMeta);
}
if (data.containsKey('created_at')) {
context.handle(_createdAtMeta,
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {seq};
@override
PacketLog map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return PacketLog(
seq: attachedDatabase.typeMapping
.read(DriftSqlType.int, data['${effectivePrefix}seq'])!,
payload: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}payload'])!,
createdAt: attachedDatabase.typeMapping
.read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
);
}
@override
$PacketLogsTable createAlias(String alias) {
return $PacketLogsTable(attachedDatabase, alias);
}
}
class PacketLog extends DataClass implements Insertable<PacketLog> {
final int seq;
final String payload;
final DateTime createdAt;
const PacketLog(
{required this.seq, required this.payload, required this.createdAt});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['seq'] = Variable<int>(seq);
map['payload'] = Variable<String>(payload);
map['created_at'] = Variable<DateTime>(createdAt);
return map;
}
PacketLogsCompanion toCompanion(bool nullToAbsent) {
return PacketLogsCompanion(
seq: Value(seq),
payload: Value(payload),
createdAt: Value(createdAt),
);
}
factory PacketLog.fromJson(Map<String, dynamic> json,
{ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return PacketLog(
seq: serializer.fromJson<int>(json['seq']),
payload: serializer.fromJson<String>(json['payload']),
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'seq': serializer.toJson<int>(seq),
'payload': serializer.toJson<String>(payload),
'createdAt': serializer.toJson<DateTime>(createdAt),
};
}
PacketLog copyWith({int? seq, String? payload, DateTime? createdAt}) =>
PacketLog(
seq: seq ?? this.seq,
payload: payload ?? this.payload,
createdAt: createdAt ?? this.createdAt,
);
PacketLog copyWithCompanion(PacketLogsCompanion data) {
return PacketLog(
seq: data.seq.present ? data.seq.value : this.seq,
payload: data.payload.present ? data.payload.value : this.payload,
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
);
}
@override
String toString() {
return (StringBuffer('PacketLog(')
..write('seq: $seq, ')
..write('payload: $payload, ')
..write('createdAt: $createdAt')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(seq, payload, createdAt);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is PacketLog &&
other.seq == this.seq &&
other.payload == this.payload &&
other.createdAt == this.createdAt);
}
class PacketLogsCompanion extends UpdateCompanion<PacketLog> {
final Value<int> seq;
final Value<String> payload;
final Value<DateTime> createdAt;
const PacketLogsCompanion({
this.seq = const Value.absent(),
this.payload = const Value.absent(),
this.createdAt = const Value.absent(),
});
PacketLogsCompanion.insert({
this.seq = const Value.absent(),
required String payload,
this.createdAt = const Value.absent(),
}) : payload = Value(payload);
static Insertable<PacketLog> custom({
Expression<int>? seq,
Expression<String>? payload,
Expression<DateTime>? createdAt,
}) {
return RawValuesInsertable({
if (seq != null) 'seq': seq,
if (payload != null) 'payload': payload,
if (createdAt != null) 'created_at': createdAt,
});
}
PacketLogsCompanion copyWith(
{Value<int>? seq, Value<String>? payload, Value<DateTime>? createdAt}) {
return PacketLogsCompanion(
seq: seq ?? this.seq,
payload: payload ?? this.payload,
createdAt: createdAt ?? this.createdAt,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (seq.present) {
map['seq'] = Variable<int>(seq.value);
}
if (payload.present) {
map['payload'] = Variable<String>(payload.value);
}
if (createdAt.present) {
map['created_at'] = Variable<DateTime>(createdAt.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('PacketLogsCompanion(')
..write('seq: $seq, ')
..write('payload: $payload, ')
..write('createdAt: $createdAt')
..write(')'))
.toString();
}
}
abstract class _$EphemeralDatabase extends GeneratedDatabase {
_$EphemeralDatabase(QueryExecutor e) : super(e);
$EphemeralDatabaseManager get managers => $EphemeralDatabaseManager(this);
late final $MediaItemsTable mediaItems = $MediaItemsTable(this);
late final $PacketLogsTable packetLogs = $PacketLogsTable(this);
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [mediaItems];
List<DatabaseSchemaEntity> get allSchemaEntities => [mediaItems, packetLogs];
}
typedef $$MediaItemsTableCreateCompanionBuilder = MediaItemsCompanion Function({
@@ -548,10 +762,147 @@ typedef $$MediaItemsTableProcessedTableManager = ProcessedTableManager<
),
MediaItem,
PrefetchHooks Function()>;
typedef $$PacketLogsTableCreateCompanionBuilder = PacketLogsCompanion Function({
Value<int> seq,
required String payload,
Value<DateTime> createdAt,
});
typedef $$PacketLogsTableUpdateCompanionBuilder = PacketLogsCompanion Function({
Value<int> seq,
Value<String> payload,
Value<DateTime> createdAt,
});
class $$PacketLogsTableFilterComposer
extends Composer<_$EphemeralDatabase, $PacketLogsTable> {
$$PacketLogsTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnFilters<int> get seq => $composableBuilder(
column: $table.seq, builder: (column) => ColumnFilters(column));
ColumnFilters<String> get payload => $composableBuilder(
column: $table.payload, builder: (column) => ColumnFilters(column));
ColumnFilters<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt, builder: (column) => ColumnFilters(column));
}
class $$PacketLogsTableOrderingComposer
extends Composer<_$EphemeralDatabase, $PacketLogsTable> {
$$PacketLogsTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnOrderings<int> get seq => $composableBuilder(
column: $table.seq, builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get payload => $composableBuilder(
column: $table.payload, builder: (column) => ColumnOrderings(column));
ColumnOrderings<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt, builder: (column) => ColumnOrderings(column));
}
class $$PacketLogsTableAnnotationComposer
extends Composer<_$EphemeralDatabase, $PacketLogsTable> {
$$PacketLogsTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
GeneratedColumn<int> get seq =>
$composableBuilder(column: $table.seq, builder: (column) => column);
GeneratedColumn<String> get payload =>
$composableBuilder(column: $table.payload, builder: (column) => column);
GeneratedColumn<DateTime> get createdAt =>
$composableBuilder(column: $table.createdAt, builder: (column) => column);
}
class $$PacketLogsTableTableManager extends RootTableManager<
_$EphemeralDatabase,
$PacketLogsTable,
PacketLog,
$$PacketLogsTableFilterComposer,
$$PacketLogsTableOrderingComposer,
$$PacketLogsTableAnnotationComposer,
$$PacketLogsTableCreateCompanionBuilder,
$$PacketLogsTableUpdateCompanionBuilder,
(
PacketLog,
BaseReferences<_$EphemeralDatabase, $PacketLogsTable, PacketLog>
),
PacketLog,
PrefetchHooks Function()> {
$$PacketLogsTableTableManager(_$EphemeralDatabase db, $PacketLogsTable table)
: super(TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
$$PacketLogsTableFilterComposer($db: db, $table: table),
createOrderingComposer: () =>
$$PacketLogsTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () =>
$$PacketLogsTableAnnotationComposer($db: db, $table: table),
updateCompanionCallback: ({
Value<int> seq = const Value.absent(),
Value<String> payload = const Value.absent(),
Value<DateTime> createdAt = const Value.absent(),
}) =>
PacketLogsCompanion(
seq: seq,
payload: payload,
createdAt: createdAt,
),
createCompanionCallback: ({
Value<int> seq = const Value.absent(),
required String payload,
Value<DateTime> createdAt = const Value.absent(),
}) =>
PacketLogsCompanion.insert(
seq: seq,
payload: payload,
createdAt: createdAt,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
.toList(),
prefetchHooksCallback: null,
));
}
typedef $$PacketLogsTableProcessedTableManager = ProcessedTableManager<
_$EphemeralDatabase,
$PacketLogsTable,
PacketLog,
$$PacketLogsTableFilterComposer,
$$PacketLogsTableOrderingComposer,
$$PacketLogsTableAnnotationComposer,
$$PacketLogsTableCreateCompanionBuilder,
$$PacketLogsTableUpdateCompanionBuilder,
(
PacketLog,
BaseReferences<_$EphemeralDatabase, $PacketLogsTable, PacketLog>
),
PacketLog,
PrefetchHooks Function()>;
class $EphemeralDatabaseManager {
final _$EphemeralDatabase _db;
$EphemeralDatabaseManager(this._db);
$$MediaItemsTableTableManager get mediaItems =>
$$MediaItemsTableTableManager(_db, _db.mediaItems);
$$PacketLogsTableTableManager get packetLogs =>
$$PacketLogsTableTableManager(_db, _db.packetLogs);
}