mirror of
https://github.com/tulir/mautrix-whatsapp
synced 2024-12-04 20:52:54 +01:00
legacymigrate: fix things
This commit is contained in:
parent
86ffca8a6b
commit
91fbf6f609
15 changed files with 311 additions and 38 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,10 +4,10 @@
|
||||||
!.pre-commit-config.yaml
|
!.pre-commit-config.yaml
|
||||||
!example-config.yaml
|
!example-config.yaml
|
||||||
|
|
||||||
*.session
|
|
||||||
*.json
|
*.json
|
||||||
*.db
|
*.db
|
||||||
*.log
|
*.log
|
||||||
|
*.bak
|
||||||
|
|
||||||
/mautrix-whatsapp
|
/mautrix-whatsapp
|
||||||
/start
|
/start
|
||||||
|
|
|
@ -2,8 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"strings"
|
||||||
|
|
||||||
up "go.mau.fi/util/configupgrade"
|
up "go.mau.fi/util/configupgrade"
|
||||||
|
"go.mau.fi/util/dbutil/litestream"
|
||||||
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
|
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,9 +28,41 @@ ALTER TABLE "user" RENAME TO user_old;
|
||||||
//go:embed legacymigrate.sql
|
//go:embed legacymigrate.sql
|
||||||
var legacyMigrateCopyData string
|
var legacyMigrateCopyData string
|
||||||
|
|
||||||
//lint:ignore U1000 - TODO use this function
|
func init() {
|
||||||
|
litestream.Functions["split_part"] = func(input, delimiter string, partNum int) string {
|
||||||
|
// split_part is 1-indexed
|
||||||
|
partNum++
|
||||||
|
parts := strings.Split(input, delimiter)
|
||||||
|
if len(parts) <= partNum {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return parts[partNum]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func migrateLegacyConfig(helper up.Helper) {
|
func migrateLegacyConfig(helper up.Helper) {
|
||||||
helper.Set(up.Str, "maunium.net/go/mautrix-whatsapp", "encryption", "pickle_key")
|
helper.Set(up.Str, "maunium.net/go/mautrix-whatsapp", "encryption", "pickle_key")
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "os_name"}, []string{"network", "os_name"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "browser_name"}, []string{"network", "browser_name"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "proxy"}, []string{"network", "proxy"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "get_proxy_url"}, []string{"network", "get_proxy_url"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"whatsapp", "proxy_only_login"}, []string{"network", "proxy_only_login"})
|
||||||
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "displayname_template"}, []string{"network", "displayname_template"})
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "displayname_template"}, []string{"network", "displayname_template"})
|
||||||
// TODO other fields
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "call_start_notices"}, []string{"network", "call_start_notices"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "send_presence_on_typing"}, []string{"network", "send_presence_on_typing"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "enable_status_broadcast"}, []string{"network", "enable_status_broadcast"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "disable_status_broadcast_send"}, []string{"network", "disable_status_broadcast_send"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "mute_status_broadcast"}, []string{"network", "mute_status_broadcast"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "status_broadcast_tag"}, []string{"network", "status_broadcast_tag"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "whatsapp_thumbnail"}, []string{"network", "whatsapp_thumbnail"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "url_previews"}, []string{"network", "url_previews"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "force_active_delivery_receipts"}, []string{"network", "force_active_delivery_receipts"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "history_sync", "request_full_sync"}, []string{"network", "history_sync", "request_full_sync"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "full_sync_config", "days_limit"}, []string{"network", "history_sync", "full_sync_config", "days_limit"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "full_sync_config", "size_limit_mb"}, []string{"network", "history_sync", "full_sync_config", "size_limit_mb"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "full_sync_config", "storage_quota_mb"}, []string{"network", "history_sync", "full_sync_config", "storage_quota_mb"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "history_sync", "media_requests", "auto_request_media"}, []string{"network", "history_sync", "media_requests", "auto_request_media"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "history_sync", "media_requests", "request_method"}, []string{"network", "history_sync", "media_requests", "request_method"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "media_requests", "request_local_time"}, []string{"network", "history_sync", "media_requests", "request_local_time"})
|
||||||
|
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "media_requests", "max_async_handle"}, []string{"network", "history_sync", "media_requests", "max_async_handle"})
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ SELECT
|
||||||
'phone_last_seen', phone_last_seen,
|
'phone_last_seen', phone_last_seen,
|
||||||
'phone_last_pinged', phone_last_pinged,
|
'phone_last_pinged', phone_last_pinged,
|
||||||
'timezone', timezone
|
'timezone', timezone
|
||||||
) -- metadata
|
), -- metadata
|
||||||
|
'{}' -- remote_profile
|
||||||
FROM user_old
|
FROM user_old
|
||||||
WHERE username<>'' AND device<>0;
|
WHERE username<>'' AND device<>0;
|
||||||
|
|
||||||
|
@ -51,6 +52,9 @@ SELECT
|
||||||
) -- metadata
|
) -- metadata
|
||||||
FROM puppet_old;
|
FROM puppet_old;
|
||||||
|
|
||||||
|
INSERT INTO ghost (bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, contact_info_set, is_bot, identifiers, metadata)
|
||||||
|
VALUES ('', '', '', '', '', '', false, false, false, false, '[]', '{}');
|
||||||
|
|
||||||
INSERT INTO portal (
|
INSERT INTO portal (
|
||||||
bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, other_user_id,
|
bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, other_user_id,
|
||||||
name, topic, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, topic_set,
|
name, topic, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, topic_set,
|
||||||
|
@ -98,21 +102,35 @@ SELECT
|
||||||
last_read_ts * 1000000000 -- last_read TODO check multiplier
|
last_read_ts * 1000000000 -- last_read TODO check multiplier
|
||||||
FROM user_portal_old;
|
FROM user_portal_old;
|
||||||
|
|
||||||
|
ALTER TABLE message_old ADD COLUMN combined_id TEXT;
|
||||||
|
UPDATE message_old SET combined_id = chat_jid || ':' || (
|
||||||
|
CASE WHEN sender LIKE '%:%@s.whatsapp.net'
|
||||||
|
THEN (split_part(replace(sender, '@s.whatsapp.net', ''), ':', 1) || '@s.whatsapp.net')
|
||||||
|
ELSE sender
|
||||||
|
END
|
||||||
|
) || ':' || jid;
|
||||||
|
|
||||||
INSERT INTO message (
|
INSERT INTO message (
|
||||||
bridge_id, id, part_id, mxid, room_id, room_receiver, sender_id, sender_mxid, timestamp, edit_count, metadata
|
bridge_id, id, part_id, mxid, room_id, room_receiver, sender_id, sender_mxid, timestamp, edit_count, metadata
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
'', -- bridge_id
|
'', -- bridge_id
|
||||||
jid, -- id FIXME requires prefix
|
combined_id, -- id
|
||||||
'', -- part_id
|
'', -- part_id
|
||||||
mxid,
|
mxid,
|
||||||
chat_jid, -- room_id
|
chat_jid, -- room_id
|
||||||
CASE WHEN chat_receiver LIKE '%@s.whatsapp.net' THEN chat_receiver ELSE '' END, -- room_receiver
|
CASE WHEN chat_receiver LIKE '%@s.whatsapp.net' THEN chat_receiver ELSE '' END, -- room_receiver
|
||||||
sender, -- sender_id
|
CASE WHEN sender=chat_jid THEN '' ELSE split_part(replace(sender, '@s.whatsapp.net', ''), ':', 1) END, -- sender_id
|
||||||
sender_mxid, -- sender_mxid
|
sender_mxid, -- sender_mxid
|
||||||
timestamp * 1000000000, -- timestamp TODO check multiplier
|
timestamp * 1000000000, -- timestamp TODO check multiplier
|
||||||
0, -- edit_count
|
0, -- edit_count
|
||||||
'{}' -- metadata
|
-- only: postgres
|
||||||
|
jsonb_build_object
|
||||||
|
-- only: sqlite (line commented)
|
||||||
|
-- json_object
|
||||||
|
(
|
||||||
|
'sender_device_id', CAST(nullif(split_part(replace(sender, '@s.whatsapp.net', ''), ':', 2), '') AS INTEGER)
|
||||||
|
) -- metadata
|
||||||
FROM message_old;
|
FROM message_old;
|
||||||
|
|
||||||
INSERT INTO reaction (
|
INSERT INTO reaction (
|
||||||
|
@ -120,17 +138,27 @@ INSERT INTO reaction (
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
'', -- bridge_id
|
'', -- bridge_id
|
||||||
target_jid, -- message_id FIXME requires prefix
|
message_old.combined_id, -- message_id
|
||||||
'', -- message_part_id
|
'', -- message_part_id
|
||||||
sender, -- sender_id
|
replace(reaction_old.sender, '@s.whatsapp.net', ''), -- sender_id
|
||||||
'', -- emoji_id
|
'', -- emoji_id
|
||||||
chat_jid, -- room_id
|
reaction_old.chat_jid, -- room_id
|
||||||
CASE WHEN chat_receiver LIKE '%@s.whatsapp.net' THEN chat_receiver ELSE '' END, -- room_receiver
|
CASE WHEN reaction_old.chat_receiver LIKE '%@s.whatsapp.net' THEN reaction_old.chat_receiver ELSE '' END, -- room_receiver
|
||||||
mxid,
|
reaction_old.mxid,
|
||||||
0, -- timestamp
|
0, -- timestamp
|
||||||
'', -- emoji
|
'', -- emoji
|
||||||
'{}' -- metadata
|
-- only: postgres
|
||||||
FROM reaction_old;
|
jsonb_build_object
|
||||||
|
-- only: sqlite (line commented)
|
||||||
|
-- json_object
|
||||||
|
(
|
||||||
|
'sender_device_id', CAST(nullif(split_part(replace(reaction_old.sender, '@s.whatsapp.net', ''), ':', 2), '') AS INTEGER)
|
||||||
|
) -- metadata
|
||||||
|
FROM reaction_old
|
||||||
|
LEFT JOIN message_old
|
||||||
|
ON reaction_old.chat_jid = message_old.chat_jid
|
||||||
|
AND reaction_old.chat_receiver = message_old.chat_receiver
|
||||||
|
AND reaction_old.target_jid = message_old.jid;
|
||||||
|
|
||||||
INSERT INTO disappearing_message (bridge_id, mx_room, mxid, type, timer, disappear_at)
|
INSERT INTO disappearing_message (bridge_id, mx_room, mxid, type, timer, disappear_at)
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -152,7 +180,7 @@ SELECT
|
||||||
CASE WHEN portal_receiver LIKE '%@s.whatsapp.net' THEN portal_receiver ELSE '' END, -- portal_receiver
|
CASE WHEN portal_receiver LIKE '%@s.whatsapp.net' THEN portal_receiver ELSE '' END, -- portal_receiver
|
||||||
(SELECT id FROM user_login WHERE user_login.user_mxid=backfill_queue_old.user_mxid), -- user_login_id
|
(SELECT id FROM user_login WHERE user_login.user_mxid=backfill_queue_old.user_mxid), -- user_login_id
|
||||||
COUNT(*), -- batch_count
|
COUNT(*), -- batch_count
|
||||||
COUNT(*) == COUNT(completed_at), -- is_done
|
COUNT(*) = COUNT(completed_at), -- is_done
|
||||||
'', -- cursor
|
'', -- cursor
|
||||||
'', -- oldest_message_id
|
'', -- oldest_message_id
|
||||||
-- only: postgres
|
-- only: postgres
|
||||||
|
@ -165,14 +193,81 @@ FROM backfill_queue_old
|
||||||
WHERE type IN (0, 200)
|
WHERE type IN (0, 200)
|
||||||
GROUP BY user_mxid, portal_jid, portal_receiver;
|
GROUP BY user_mxid, portal_jid, portal_receiver;
|
||||||
|
|
||||||
|
INSERT INTO whatsapp_poll_option_id (bridge_id, msg_mxid, opt_id, opt_hash)
|
||||||
|
SELECT '', msg_mxid, opt_id, opt_hash
|
||||||
|
FROM poll_option_id_old;
|
||||||
|
|
||||||
|
INSERT INTO whatsapp_history_sync_conversation (
|
||||||
|
bridge_id, user_login_id, chat_jid, last_message_timestamp, archived, pinned, mute_end_time,
|
||||||
|
end_of_history_transfer_type, ephemeral_expiration, ephemeral_setting_timestamp, marked_as_unread, unread_count
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'',
|
||||||
|
user_login.id,
|
||||||
|
portal_jid,
|
||||||
|
-- only: postgres
|
||||||
|
CAST(EXTRACT(EPOCH FROM last_message_timestamp) AS BIGINT),
|
||||||
|
-- only: sqlite (line commented)
|
||||||
|
-- unixepoch(last_message_timestamp),
|
||||||
|
archived,
|
||||||
|
CASE WHEN pinned > 0 THEN true ELSE false END,
|
||||||
|
-- only: postgres
|
||||||
|
CAST(EXTRACT(EPOCH FROM mute_end_time) AS BIGINT),
|
||||||
|
-- only: sqlite (line commented)
|
||||||
|
-- unixepoch(mute_end_time),
|
||||||
|
end_of_history_transfer_type,
|
||||||
|
ephemeral_expiration,
|
||||||
|
0,
|
||||||
|
marked_as_unread,
|
||||||
|
unread_count
|
||||||
|
FROM history_sync_conversation_old
|
||||||
|
LEFT JOIN user_login ON user_login.user_mxid = history_sync_conversation_old.user_mxid
|
||||||
|
WHERE user_login.id IS NOT NULL;
|
||||||
|
|
||||||
|
INSERT INTO whatsapp_history_sync_message (
|
||||||
|
bridge_id, user_login_id, chat_jid, message_id, timestamp, data, inserted_time
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'',
|
||||||
|
user_login.id,
|
||||||
|
conversation_id,
|
||||||
|
message_id,
|
||||||
|
-- only: postgres
|
||||||
|
CAST(EXTRACT(EPOCH FROM timestamp) AS BIGINT),
|
||||||
|
-- only: sqlite (line commented)
|
||||||
|
-- unixepoch(timestamp),
|
||||||
|
data,
|
||||||
|
-- only: postgres
|
||||||
|
CAST(EXTRACT(EPOCH FROM inserted_time) AS BIGINT)
|
||||||
|
-- only: sqlite (line commented)
|
||||||
|
-- unixepoch(inserted_time)
|
||||||
|
FROM history_sync_message_old
|
||||||
|
LEFT JOIN user_login ON user_login.user_mxid = history_sync_message_old.user_mxid
|
||||||
|
WHERE user_login.id IS NOT NULL;
|
||||||
|
|
||||||
|
INSERT INTO whatsapp_media_backfill_request (
|
||||||
|
bridge_id, user_login_id, portal_id, portal_receiver, event_id, media_key, status, error
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'',
|
||||||
|
user_login.id,
|
||||||
|
portal_jid,
|
||||||
|
CASE WHEN portal_receiver LIKE '%@s.whatsapp.net' THEN portal_receiver ELSE '' END,
|
||||||
|
event_id,
|
||||||
|
media_key,
|
||||||
|
status,
|
||||||
|
error
|
||||||
|
FROM media_backfill_requests_old
|
||||||
|
LEFT JOIN user_login ON user_login.user_mxid = media_backfill_requests_old.user_mxid
|
||||||
|
WHERE user_login.id IS NOT NULL;
|
||||||
|
|
||||||
DROP TABLE backfill_queue_old;
|
DROP TABLE backfill_queue_old;
|
||||||
DROP TABLE backfill_state_old;
|
DROP TABLE backfill_state_old;
|
||||||
DROP TABLE disappearing_message_old;
|
DROP TABLE disappearing_message_old;
|
||||||
-- TODO migrate these tables
|
DROP TABLE history_sync_message_old;
|
||||||
-- DROP TABLE history_sync_message_old;
|
DROP TABLE history_sync_conversation_old;
|
||||||
-- DROP TABLE history_sync_conversation_old;
|
DROP TABLE media_backfill_requests_old;
|
||||||
-- DROP TABLE media_backfill_requests_old;
|
DROP TABLE poll_option_id_old;
|
||||||
-- DROP TABLE poll_option_id_old;
|
|
||||||
DROP TABLE user_portal_old;
|
DROP TABLE user_portal_old;
|
||||||
DROP TABLE reaction_old;
|
DROP TABLE reaction_old;
|
||||||
DROP TABLE message_old;
|
DROP TABLE message_old;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
|
||||||
"maunium.net/go/mautrix/bridgev2/matrix/mxmain"
|
"maunium.net/go/mautrix/bridgev2/matrix/mxmain"
|
||||||
|
|
||||||
"maunium.net/go/mautrix-whatsapp/pkg/connector"
|
"maunium.net/go/mautrix-whatsapp/pkg/connector"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/pkg/connector/wadb/upgrades"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Information to find out exactly which commit the bridge was built from.
|
// Information to find out exactly which commit the bridge was built from.
|
||||||
|
@ -24,12 +26,16 @@ var m = mxmain.BridgeMain{
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
bridgeconfig.HackyMigrateLegacyNetworkConfig = migrateLegacyConfig
|
||||||
m.PostInit = func() {
|
m.PostInit = func() {
|
||||||
m.CheckLegacyDB(
|
m.CheckLegacyDB(
|
||||||
57,
|
57,
|
||||||
"v0.8.6",
|
"v0.8.6",
|
||||||
"v0.11.0",
|
"v0.11.0",
|
||||||
m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 16),
|
m.LegacyMigrateWithAnotherUpgrader(
|
||||||
|
legacyMigrateRenameTables, legacyMigrateCopyData, 17,
|
||||||
|
upgrades.Table, "whatsapp_version", 1,
|
||||||
|
),
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -20,7 +20,7 @@ require (
|
||||||
golang.org/x/sync v0.8.0
|
golang.org/x/sync v0.8.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
maunium.net/go/mautrix v0.20.1-0.20240906145130-6b055b1475bd
|
maunium.net/go/mautrix v0.20.1-0.20240910112932-ffdb1d575e5f
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -114,5 +114,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/mautrix v0.20.1-0.20240906145130-6b055b1475bd h1:gfiJD2cPS9iUek1UI+DOUn08zogF4kmu7XYfBqSrAU4=
|
maunium.net/go/mautrix v0.20.1-0.20240910112932-ffdb1d575e5f h1:T4K6V2Ige2mshH7FW69xLep23GBrW7xS1sxomaKe1Hg=
|
||||||
maunium.net/go/mautrix v0.20.1-0.20240906145130-6b055b1475bd/go.mod h1:l6nYvD5/FMSrAZ/IP1AqJV0b47SRl/0uQNRiy4CcSVk=
|
maunium.net/go/mautrix v0.20.1-0.20240910112932-ffdb1d575e5f/go.mod h1:l6nYvD5/FMSrAZ/IP1AqJV0b47SRl/0uQNRiy4CcSVk=
|
||||||
|
|
|
@ -79,8 +79,8 @@ func upgradeConfig(helper up.Helper) {
|
||||||
helper.Copy(up.Str, "os_name")
|
helper.Copy(up.Str, "os_name")
|
||||||
helper.Copy(up.Str, "browser_name")
|
helper.Copy(up.Str, "browser_name")
|
||||||
|
|
||||||
helper.Copy(up.Str, "proxy")
|
helper.Copy(up.Str|up.Null, "proxy")
|
||||||
helper.Copy(up.Str, "get_proxy_url")
|
helper.Copy(up.Str|up.Null, "get_proxy_url")
|
||||||
helper.Copy(up.Bool, "proxy_only_login")
|
helper.Copy(up.Bool, "proxy_only_login")
|
||||||
|
|
||||||
helper.Copy(up.Str, "displayname_template")
|
helper.Copy(up.Str, "displayname_template")
|
||||||
|
@ -95,9 +95,9 @@ func upgradeConfig(helper up.Helper) {
|
||||||
helper.Copy(up.Bool, "url_previews")
|
helper.Copy(up.Bool, "url_previews")
|
||||||
|
|
||||||
helper.Copy(up.Bool, "history_sync", "request_full_sync")
|
helper.Copy(up.Bool, "history_sync", "request_full_sync")
|
||||||
helper.Copy(up.Int, "history_sync", "full_sync_config", "days_limit")
|
helper.Copy(up.Int|up.Null, "history_sync", "full_sync_config", "days_limit")
|
||||||
helper.Copy(up.Int, "history_sync", "full_sync_config", "size_mb_limit")
|
helper.Copy(up.Int|up.Null, "history_sync", "full_sync_config", "size_mb_limit")
|
||||||
helper.Copy(up.Int, "history_sync", "full_sync_config", "storage_quota_mb")
|
helper.Copy(up.Int|up.Null, "history_sync", "full_sync_config", "storage_quota_mb")
|
||||||
helper.Copy(up.Bool, "history_sync", "media_requests", "auto_request_media")
|
helper.Copy(up.Bool, "history_sync", "media_requests", "auto_request_media")
|
||||||
helper.Copy(up.Str, "history_sync", "media_requests", "request_method")
|
helper.Copy(up.Str, "history_sync", "media_requests", "request_method")
|
||||||
helper.Copy(up.Int, "history_sync", "media_requests", "request_local_time")
|
helper.Copy(up.Int, "history_sync", "media_requests", "request_local_time")
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"maunium.net/go/mautrix/bridgev2"
|
"maunium.net/go/mautrix/bridgev2"
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix-whatsapp/pkg/connector/wadb"
|
||||||
"maunium.net/go/mautrix-whatsapp/pkg/msgconv"
|
"maunium.net/go/mautrix-whatsapp/pkg/msgconv"
|
||||||
"maunium.net/go/mautrix-whatsapp/pkg/waid"
|
"maunium.net/go/mautrix-whatsapp/pkg/waid"
|
||||||
)
|
)
|
||||||
|
@ -21,6 +22,7 @@ type WhatsAppConnector struct {
|
||||||
Config Config
|
Config Config
|
||||||
DeviceStore *sqlstore.Container
|
DeviceStore *sqlstore.Container
|
||||||
MsgConv *msgconv.MessageConverter
|
MsgConv *msgconv.MessageConverter
|
||||||
|
DB *wadb.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ bridgev2.NetworkConnector = (*WhatsAppConnector)(nil)
|
var _ bridgev2.NetworkConnector = (*WhatsAppConnector)(nil)
|
||||||
|
@ -44,6 +46,7 @@ func (wa *WhatsAppConnector) GetName() bridgev2.BridgeName {
|
||||||
func (wa *WhatsAppConnector) Init(bridge *bridgev2.Bridge) {
|
func (wa *WhatsAppConnector) Init(bridge *bridgev2.Bridge) {
|
||||||
wa.Bridge = bridge
|
wa.Bridge = bridge
|
||||||
wa.MsgConv = msgconv.New(bridge)
|
wa.MsgConv = msgconv.New(bridge)
|
||||||
|
wa.DB = wadb.New(bridge.DB.Database, bridge.Log.With().Str("db_section", "whatsapp").Logger())
|
||||||
|
|
||||||
wa.DeviceStore = sqlstore.NewWithDB(
|
wa.DeviceStore = sqlstore.NewWithDB(
|
||||||
bridge.DB.RawDB,
|
bridge.DB.RawDB,
|
||||||
|
@ -66,11 +69,15 @@ func (wa *WhatsAppConnector) Init(bridge *bridgev2.Bridge) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wa *WhatsAppConnector) Start(_ context.Context) error {
|
func (wa *WhatsAppConnector) Start(ctx context.Context) error {
|
||||||
err := wa.DeviceStore.Upgrade()
|
err := wa.DeviceStore.Upgrade()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bridgev2.DBUpgradeError{Err: err, Section: "whatsmeow"}
|
return bridgev2.DBUpgradeError{Err: err, Section: "whatsmeow"}
|
||||||
}
|
}
|
||||||
|
err = wa.DB.Upgrade(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return bridgev2.DBUpgradeError{Err: err, Section: "whatsapp"}
|
||||||
|
}
|
||||||
|
|
||||||
ver, err := whatsmeow.GetLatestVersion(nil)
|
ver, err := whatsmeow.GetLatestVersion(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,8 +10,12 @@ func (wa *WhatsAppConnector) GetDBMetaTypes() database.MetaTypes {
|
||||||
Ghost: func() any {
|
Ghost: func() any {
|
||||||
return &GhostMetadata{}
|
return &GhostMetadata{}
|
||||||
},
|
},
|
||||||
Message: nil,
|
Message: func() any {
|
||||||
Reaction: nil,
|
return &MessageMetadata{}
|
||||||
|
},
|
||||||
|
Reaction: func() any {
|
||||||
|
return &ReactionMetadata{}
|
||||||
|
},
|
||||||
Portal: func() any {
|
Portal: func() any {
|
||||||
return &PortalMetadata{}
|
return &PortalMetadata{}
|
||||||
},
|
},
|
||||||
|
@ -26,6 +30,14 @@ type UserLoginMetadata struct {
|
||||||
//TODO: Add phone last ping/seen
|
//TODO: Add phone last ping/seen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MessageMetadata struct {
|
||||||
|
SenderDeviceID uint16 `json:"sender_device_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReactionMetadata struct {
|
||||||
|
SenderDeviceID uint16 `json:"sender_device_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type PortalMetadata struct {
|
type PortalMetadata struct {
|
||||||
DisappearingTimerSetAt int64 `json:"disappearing_timer_set_at,omitempty"`
|
DisappearingTimerSetAt int64 `json:"disappearing_timer_set_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ var (
|
||||||
_ bridgev2.RemoteEventThatMayCreatePortal = (*WAMessageEvent)(nil)
|
_ bridgev2.RemoteEventThatMayCreatePortal = (*WAMessageEvent)(nil)
|
||||||
_ bridgev2.RemoteReaction = (*WAMessageEvent)(nil)
|
_ bridgev2.RemoteReaction = (*WAMessageEvent)(nil)
|
||||||
_ bridgev2.RemoteReactionRemove = (*WAMessageEvent)(nil)
|
_ bridgev2.RemoteReactionRemove = (*WAMessageEvent)(nil)
|
||||||
|
_ bridgev2.RemoteReactionWithMeta = (*WAMessageEvent)(nil)
|
||||||
_ bridgev2.RemoteEdit = (*WAMessageEvent)(nil)
|
_ bridgev2.RemoteEdit = (*WAMessageEvent)(nil)
|
||||||
_ bridgev2.RemoteMessageRemove = (*WAMessageEvent)(nil)
|
_ bridgev2.RemoteMessageRemove = (*WAMessageEvent)(nil)
|
||||||
)
|
)
|
||||||
|
@ -77,6 +78,12 @@ func (evt *WAMessageEvent) GetReactionEmoji() (string, networkid.EmojiID) {
|
||||||
return evt.Message.Message.GetReactionMessage().GetText(), ""
|
return evt.Message.Message.GetReactionMessage().GetText(), ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (evt *WAMessageEvent) GetReactionDBMetadata() any {
|
||||||
|
return &ReactionMetadata{
|
||||||
|
SenderDeviceID: evt.Info.Sender.Device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (evt *WAMessageEvent) GetRemovedEmojiID() networkid.EmojiID {
|
func (evt *WAMessageEvent) GetRemovedEmojiID() networkid.EmojiID {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -129,5 +136,11 @@ func (evt *WAMessageEvent) GetTransactionID() networkid.TransactionID {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (evt *WAMessageEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) {
|
func (evt *WAMessageEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) {
|
||||||
return evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, evt.Message.Message), nil
|
converted := evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, evt.Message.Message)
|
||||||
|
for _, part := range converted.Parts {
|
||||||
|
part.DBMetadata = &MessageMetadata{
|
||||||
|
SenderDeviceID: evt.Info.Sender.Device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return converted, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ proxy_only_login: false
|
||||||
# {{.PushName}} - nickname set by the WhatsApp user
|
# {{.PushName}} - nickname set by the WhatsApp user
|
||||||
# {{.BusinessName}} - validated WhatsApp business name
|
# {{.BusinessName}} - validated WhatsApp business name
|
||||||
# {{.Phone}} - phone number (international format)
|
# {{.Phone}} - phone number (international format)
|
||||||
# {{.FullName}} - Name you set in the contacts list
|
# {{.FullName}} - Name you set in the contacts list
|
||||||
displayname_template: "{{or .FullName .BusinessName .PushName .Phone}} (WA)"
|
displayname_template: "{{or .FullName .BusinessName .PushName .Phone}} (WA)"
|
||||||
|
|
||||||
# Should incoming calls send a message to the Matrix room?
|
# Should incoming calls send a message to the Matrix room?
|
||||||
|
|
|
@ -47,8 +47,11 @@ func (wa *WhatsAppClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2
|
||||||
return &bridgev2.MatrixMessageResponse{
|
return &bridgev2.MatrixMessageResponse{
|
||||||
DB: &database.Message{
|
DB: &database.Message{
|
||||||
ID: wrappedMsgID,
|
ID: wrappedMsgID,
|
||||||
SenderID: networkid.UserID(wa.UserLogin.ID),
|
SenderID: waid.MakeUserID(wa.JID),
|
||||||
Timestamp: resp.Timestamp,
|
Timestamp: resp.Timestamp,
|
||||||
|
Metadata: &MessageMetadata{
|
||||||
|
SenderDeviceID: wa.JID.Device,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
RemovePending: networkid.TransactionID(wrappedMsgID),
|
RemovePending: networkid.TransactionID(wrappedMsgID),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -56,7 +59,7 @@ func (wa *WhatsAppClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2
|
||||||
|
|
||||||
func (wa *WhatsAppClient) PreHandleMatrixReaction(_ context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) {
|
func (wa *WhatsAppClient) PreHandleMatrixReaction(_ context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) {
|
||||||
return bridgev2.MatrixReactionPreResponse{
|
return bridgev2.MatrixReactionPreResponse{
|
||||||
SenderID: networkid.UserID(wa.UserLogin.ID),
|
SenderID: waid.MakeUserID(wa.JID),
|
||||||
Emoji: variationselector.Remove(msg.Content.RelatesTo.Key),
|
Emoji: variationselector.Remove(msg.Content.RelatesTo.Key),
|
||||||
MaxReactions: 1,
|
MaxReactions: 1,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -82,7 +85,11 @@ func (wa *WhatsAppClient) HandleMatrixReaction(ctx context.Context, msg *bridgev
|
||||||
|
|
||||||
resp, err := wa.Client.SendMessage(ctx, portalJID, reactionMsg)
|
resp, err := wa.Client.SendMessage(ctx, portalJID, reactionMsg)
|
||||||
zerolog.Ctx(ctx).Trace().Any("response", resp).Msg("WhatsApp reaction response")
|
zerolog.Ctx(ctx).Trace().Any("response", resp).Msg("WhatsApp reaction response")
|
||||||
return nil, err
|
return &database.Reaction{
|
||||||
|
Metadata: &ReactionMetadata{
|
||||||
|
SenderDeviceID: wa.JID.Device,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wa *WhatsAppClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error {
|
func (wa *WhatsAppClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error {
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
package wadb
|
package wadb
|
||||||
|
|
||||||
// TODO: ADD POLL AND HISTORYSYNC AND MEDIABACKFILLREQUEST DBs
|
import (
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"go.mau.fi/util/dbutil"
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix-whatsapp/pkg/connector/wadb/upgrades"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Database struct {
|
||||||
|
*dbutil.Database
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db *dbutil.Database, log zerolog.Logger) *Database {
|
||||||
|
db = db.Child("whatsapp_version", upgrades.Table, dbutil.ZeroLogger(log))
|
||||||
|
return &Database{
|
||||||
|
Database: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
67
pkg/connector/wadb/upgrades/00-latest-schema.sql
Normal file
67
pkg/connector/wadb/upgrades/00-latest-schema.sql
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
-- v0 -> v1 (compatible with v1+): Latest revision
|
||||||
|
|
||||||
|
CREATE TABLE whatsapp_poll_option_id (
|
||||||
|
bridge_id TEXT,
|
||||||
|
msg_mxid TEXT,
|
||||||
|
opt_id TEXT,
|
||||||
|
opt_hash bytea CHECK ( length(opt_hash) = 32 ),
|
||||||
|
|
||||||
|
PRIMARY KEY (bridge_id, msg_mxid, opt_id),
|
||||||
|
CONSTRAINT whatsapp_poll_option_unique_hash UNIQUE (bridge_id, msg_mxid, opt_hash),
|
||||||
|
CONSTRAINT message_mxid_fkey FOREIGN KEY (bridge_id, msg_mxid)
|
||||||
|
REFERENCES message(bridge_id, mxid) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE whatsapp_history_sync_conversation (
|
||||||
|
bridge_id TEXT,
|
||||||
|
user_login_id TEXT,
|
||||||
|
chat_jid TEXT,
|
||||||
|
|
||||||
|
last_message_timestamp BIGINT,
|
||||||
|
archived BOOLEAN,
|
||||||
|
pinned BOOLEAN,
|
||||||
|
mute_end_time BIGINT,
|
||||||
|
end_of_history_transfer_type INTEGER,
|
||||||
|
ephemeral_expiration INTEGER,
|
||||||
|
ephemeral_setting_timestamp BIGINT,
|
||||||
|
marked_as_unread BOOLEAN,
|
||||||
|
unread_count INTEGER,
|
||||||
|
|
||||||
|
PRIMARY KEY (bridge_id, user_login_id, chat_jid),
|
||||||
|
CONSTRAINT whatsapp_history_sync_conversation_user_login_fkey FOREIGN KEY (bridge_id, user_login_id)
|
||||||
|
REFERENCES user_login(bridge_id, id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE whatsapp_history_sync_message (
|
||||||
|
bridge_id TEXT,
|
||||||
|
user_login_id TEXT,
|
||||||
|
chat_jid TEXT,
|
||||||
|
message_id TEXT,
|
||||||
|
timestamp BIGINT,
|
||||||
|
data bytea,
|
||||||
|
inserted_time BIGINT,
|
||||||
|
|
||||||
|
PRIMARY KEY (bridge_id, user_login_id, chat_jid, message_id),
|
||||||
|
CONSTRAINT whatsapp_history_sync_message_user_login_fkey FOREIGN KEY (bridge_id, user_login_id)
|
||||||
|
REFERENCES user_login(bridge_id, id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
CONSTRAINT whatsapp_history_sync_message_conversation_fkey FOREIGN KEY (bridge_id, user_login_id, chat_jid)
|
||||||
|
REFERENCES whatsapp_history_sync_conversation(bridge_id, user_login_id, chat_jid) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE whatsapp_media_backfill_request (
|
||||||
|
bridge_id TEXT,
|
||||||
|
user_login_id TEXT,
|
||||||
|
portal_id TEXT,
|
||||||
|
portal_receiver TEXT,
|
||||||
|
|
||||||
|
event_id TEXT,
|
||||||
|
media_key bytea,
|
||||||
|
status INTEGER,
|
||||||
|
error TEXT,
|
||||||
|
|
||||||
|
PRIMARY KEY (bridge_id, user_login_id, portal_id, portal_receiver, event_id),
|
||||||
|
CONSTRAINT whatsapp_media_backfill_request_user_login_fkey FOREIGN KEY (bridge_id, user_login_id)
|
||||||
|
REFERENCES user_login(bridge_id, id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
CONSTRAINT whatsapp_media_backfill_request_portal_fkey FOREIGN KEY (bridge_id, portal_id, portal_receiver)
|
||||||
|
REFERENCES portal(bridge_id, id, receiver) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);
|
16
pkg/connector/wadb/upgrades/upgrades.go
Normal file
16
pkg/connector/wadb/upgrades/upgrades.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package upgrades
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
|
||||||
|
"go.mau.fi/util/dbutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Table dbutil.UpgradeTable
|
||||||
|
|
||||||
|
//go:embed *.sql
|
||||||
|
var rawUpgrades embed.FS
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Table.RegisterFS(rawUpgrades)
|
||||||
|
}
|
Loading…
Reference in a new issue