2022-06-22 17:48:54 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"git.sr.ht/~emersion/soju/database"
|
|
|
|
)
|
|
|
|
|
|
|
|
const usage = `usage: migrate-db <source database> <destination database>
|
|
|
|
|
|
|
|
Migrates an existing Soju database to another system. Database is specified
|
|
|
|
in the format of "driver:source" where driver is sqlite3 or postgres and source
|
|
|
|
is the string that would be in the Soju config file.
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
|
|
|
-help Show this help message
|
|
|
|
`
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
flag.Usage = func() {
|
|
|
|
fmt.Fprint(flag.CommandLine.Output(), usage)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
source := strings.Split(flag.Arg(0), ":")
|
|
|
|
destination := strings.Split(flag.Arg(1), ":")
|
|
|
|
|
|
|
|
if len(source) != 2 || len(destination) != 2 {
|
|
|
|
log.Fatalf("source or destination not properly specified: %s %s", flag.Arg(0), flag.Arg(1))
|
|
|
|
}
|
|
|
|
|
|
|
|
sourcedb, err := database.Open(source[0], source[1])
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to open database: %v", err)
|
|
|
|
}
|
|
|
|
defer sourcedb.Close()
|
|
|
|
|
|
|
|
destinationdb, err := database.Open(destination[0], destination[1])
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to open database: %v", err)
|
|
|
|
}
|
|
|
|
defer destinationdb.Close()
|
|
|
|
|
|
|
|
users, err := sourcedb.ListUsers(ctx)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("unable to get source users")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, user := range users {
|
|
|
|
log.Printf("Storing user: %s\n", user.Username)
|
|
|
|
|
|
|
|
user.ID = 0
|
|
|
|
|
|
|
|
err := destinationdb.StoreUser(ctx, &user)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("unable to store user: #%d %s", user.ID, user.Username)
|
|
|
|
}
|
|
|
|
|
|
|
|
networks, err := sourcedb.ListNetworks(ctx, user.ID)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("unable to get source networks for user: #%d %s", user.ID, user.Username)
|
|
|
|
}
|
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
for _, srcNetwork := range networks {
|
|
|
|
log.Printf("Storing network: %s\n", srcNetwork.Name)
|
|
|
|
destNetwork := srcNetwork
|
2022-06-22 17:48:54 +00:00
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
destNetwork.ID = 0
|
2022-06-22 17:48:54 +00:00
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
err := destinationdb.StoreNetwork(ctx, user.ID, &destNetwork)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Fatalf("unable to store network: #%d %s", srcNetwork.ID, srcNetwork.Name)
|
2022-06-22 17:48:54 +00:00
|
|
|
}
|
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
channels, err := sourcedb.ListChannels(ctx, srcNetwork.ID)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Fatalf("unable to get source channels for network: #%d %s", srcNetwork.ID, srcNetwork.Name)
|
2022-06-22 17:48:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, channel := range channels {
|
|
|
|
log.Printf("Storing channel: %s\n", channel.Name)
|
|
|
|
|
|
|
|
channel.ID = 0
|
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
err := destinationdb.StoreChannel(ctx, destNetwork.ID, &channel)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("unable to store channel: #%d %s", channel.ID, channel.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
deliveryReceipts, err := sourcedb.ListDeliveryReceipts(ctx, srcNetwork.ID)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Fatalf("unable to get source delivery receipts for network: #%d %s", srcNetwork.ID, srcNetwork.Name)
|
2022-06-22 17:48:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
drcpts := make(map[string][]database.DeliveryReceipt)
|
|
|
|
|
|
|
|
for _, d := range deliveryReceipts {
|
|
|
|
if drcpts[d.Client] == nil {
|
|
|
|
drcpts[d.Client] = make([]database.DeliveryReceipt, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
d.ID = 0
|
|
|
|
|
|
|
|
drcpts[d.Client] = append(drcpts[d.Client], d)
|
|
|
|
}
|
|
|
|
|
|
|
|
for client, rcpts := range drcpts {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Printf("Storing delivery receipt for: %s.%s.%s", user.Username, srcNetwork.Name, client)
|
|
|
|
err := destinationdb.StoreClientDeliveryReceipts(ctx, destNetwork.ID, client, rcpts)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Fatalf("unable to store delivery receipts for network and client: %s %s", srcNetwork.Name, client)
|
2022-06-22 17:48:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: migrate read receipts as well
|
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
webPushSubscriptions, err := sourcedb.ListWebPushSubscriptions(ctx, user.ID, srcNetwork.ID)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Fatalf("unable to get source web push subscriptions for user and network: %s %s", user.Username, srcNetwork.Name)
|
2022-06-22 17:48:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, sub := range webPushSubscriptions {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Printf("Storing web push subscription: %s.%s.%d", user.Username, srcNetwork.Name, sub.ID)
|
2022-06-22 17:48:54 +00:00
|
|
|
|
|
|
|
sub.ID = 0
|
|
|
|
|
2023-07-10 00:28:01 +00:00
|
|
|
err := destinationdb.StoreWebPushSubscription(ctx, user.ID, destNetwork.ID, &sub)
|
2022-06-22 17:48:54 +00:00
|
|
|
if err != nil {
|
2023-07-10 00:28:01 +00:00
|
|
|
log.Fatalf("unable to store web push subscription for user and network: %s %s", user.Username, srcNetwork.Name)
|
2022-06-22 17:48:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
webPushConfigs, err := sourcedb.ListWebPushConfigs(ctx)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("unable to get source web push configs")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, config := range webPushConfigs {
|
|
|
|
log.Printf("Storing web push config: %d", config.ID)
|
|
|
|
config.ID = 0
|
|
|
|
err := destinationdb.StoreWebPushConfig(ctx, &config)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("unable to store web push config: #%d", config.ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|