Skip to content

Commit

Permalink
Merge pull request #34 from aqasemi/master
Browse files Browse the repository at this point in the history
Multisession support
  • Loading branch information
krypton-byte authored Aug 6, 2024
2 parents 97819dc + dc9bff9 commit 97667a0
Show file tree
Hide file tree
Showing 6 changed files with 489 additions and 11 deletions.
314 changes: 314 additions & 0 deletions examples/multisession.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
import logging
import os
import signal
import sys
from datetime import timedelta
from neonize.client import ClientFactory, NewClient
from neonize.events import (
ConnectedEv,
MessageEv,
PairStatusEv,
event,
ReceiptEv,
CallOfferEv,
)

from neonize.proto.waE2E.WAWebProtobufsE2E_pb2 import (
Message,
FutureProofMessage,
InteractiveMessage,
MessageContextInfo,
DeviceListMetadata,
)
from neonize.types import MessageServerID
from neonize.utils import log
from neonize.utils.enum import ReceiptType

sys.path.insert(0, os.getcwd())


def interrupted(*_):
event.set()


log.setLevel(logging.DEBUG)
signal.signal(signal.SIGINT, interrupted)



client_factory = ClientFactory("db.sqlite3")

# create clients from preconfigured sessions
sessions = client_factory.get_all_devices()
for device in sessions:
client_factory.new_client(
device.JID
)
# if new_client jid parameter is not passed, it will create a new client

# or create a new client
# from uuid import uuid4
# client_factory.new_client(uuid=uuid4().hex[:5])


@client_factory.event(ConnectedEv)
def on_connected(_: NewClient, __: ConnectedEv):
log.info("⚡ Connected")


@client_factory.event(ReceiptEv)
def on_receipt(_: NewClient, receipt: ReceiptEv):
log.debug(receipt)


@client_factory.event(CallOfferEv)
def on_call(_: NewClient, call: CallOfferEv):
log.debug(call)


@client_factory.event(MessageEv)
def on_message(client: NewClient, message: MessageEv):
handler(client, message)



def handler(client: NewClient, message: MessageEv):
text = message.Message.conversation or message.Message.extendedTextMessage.text
chat = message.Info.MessageSource.Chat
match text:
case "ping":
client.reply_message("pong", message)
case "_test_link_preview":
client.send_message(
chat, "Test https://github.com/krypton-byte/neonize", link_preview=True
)
case "_sticker":
client.send_sticker(
chat,
"https://mystickermania.com/cdn/stickers/anime/spy-family-anya-smirk-512x512.png",
)
case "_sticker_exif":
client.send_sticker(
chat,
"https://mystickermania.com/cdn/stickers/anime/spy-family-anya-smirk-512x512.png",
name="@Neonize",
packname="2024",
)
case "_image":
client.send_image(
chat,
"https://download.samplelib.com/png/sample-boat-400x300.png",
caption="Test",
quoted=message,
)
case "_video":
client.send_video(
chat,
"https://download.samplelib.com/mp4/sample-5s.mp4",
caption="Test",
quoted=message,
)
case "_audio":
client.send_audio(
chat,
"https://download.samplelib.com/mp3/sample-12s.mp3",
quoted=message,
)
case "_ptt":
client.send_audio(
chat,
"https://download.samplelib.com/mp3/sample-12s.mp3",
ptt=True,
quoted=message,
)
case "_doc":
client.send_document(
chat,
"https://download.samplelib.com/xls/sample-heavy-1.xls",
caption="Test",
filename="test.xls",
quoted=message,
)
case "debug":
client.send_message(chat, message.__str__())
case "viewonce":
client.send_image(
chat,
"https://pbs.twimg.com/media/GC3ywBMb0AAAEWO?format=jpg&name=medium",
viewonce=True,
)
case "profile_pict":
client.send_message(chat, client.get_profile_picture(chat).__str__())
case "status_privacy":
client.send_message(chat, client.get_status_privacy().__str__())
case "read":
client.send_message(
chat,
client.mark_read(
message.Info.ID,
chat=message.Info.MessageSource.Chat,
sender=message.Info.MessageSource.Sender,
receipt=ReceiptType.READ,
).__str__(),
)
case "read_channel":
metadata = client.get_newsletter_info_with_invite(
"https://whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
)
err = client.follow_newsletter(metadata.ID)
client.send_message(chat, "error: " + err.__str__())
resp = client.newsletter_mark_viewed(metadata.ID, [MessageServerID(0)])
client.send_message(chat, resp.__str__() + "\n" + metadata.__str__())
case "logout":
client.logout()
case "send_react_channel":
metadata = client.get_newsletter_info_with_invite(
"https://whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
)
data_msg = client.get_newsletter_messages(
metadata.ID, 2, MessageServerID(0)
)
client.send_message(chat, data_msg.__str__())
for _ in data_msg:
client.newsletter_send_reaction(
metadata.ID, MessageServerID(0), "🗿", ""
)
case "subscribe_channel_updates":
metadata = client.get_newsletter_info_with_invite(
"https://whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
)
result = client.newsletter_subscribe_live_updates(metadata.ID)
client.send_message(chat, result.__str__())
case "mute_channel":
metadata = client.get_newsletter_info_with_invite(
"https://whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
)
client.send_message(
chat, client.newsletter_toggle_mute(metadata.ID, False).__str__()
)
case "set_diseapearing":
client.send_message(
chat, client.set_default_disappearing_timer(timedelta(days=7)).__str__()
)
case "test_contacts":
client.send_message(chat, client.contact.get_all_contacts().__str__())
case "build_sticker":
client.send_message(
chat,
client.build_sticker_message(
"https://mystickermania.com/cdn/stickers/anime/spy-family-anya-smirk-512x512.png",
message,
"2024",
"neonize",
),
)
case "build_video":
client.send_message(
chat,
client.build_video_message(
"https://download.samplelib.com/mp4/sample-5s.mp4", "Test", message
),
)
case "build_image":
client.send_message(
chat,
client.build_image_message(
"https://download.samplelib.com/png/sample-boat-400x300.png",
"Test",
message,
),
)
case "build_document":
client.send_message(
chat,
client.build_document_message(
"https://download.samplelib.com/xls/sample-heavy-1.xls",
"Test",
"title",
"sample-heavy-1.xls",
quoted=message,
),
)
# ChatSettingsStore
case "put_muted_until":
client.chat_settings.put_muted_until(chat, timedelta(seconds=5))
case "put_pinned_enable":
client.chat_settings.put_pinned(chat, True)
case "put_pinned_disable":
client.chat_settings.put_pinned(chat, False)
case "put_archived_enable":
client.chat_settings.put_archived(chat, True)
case "put_archived_disable":
client.chat_settings.put_archived(chat, False)
case "get_chat_settings":
client.send_message(
chat, client.chat_settings.get_chat_settings(chat).__str__()
)
case "button":
client.send_message(
message.Info.MessageSource.Chat,
Message(
viewOnceMessage=FutureProofMessage(
message=Message(
messageContextInfo=MessageContextInfo(
deviceListMetadata=DeviceListMetadata(),
deviceListMetadataVersion=2,
),
interactiveMessage=InteractiveMessage(
body=InteractiveMessage.Body(text="Body Message"),
footer=InteractiveMessage.Footer(text="@krypton-byte"),
header=InteractiveMessage.Header(
title="Title Message",
subtitle="Subtitle Message",
hasMediaAttachment=False,
),
nativeFlowMessage=InteractiveMessage.NativeFlowMessage(
buttons=[
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="single_select",
buttonParamsJSON='{"title":"List Buttons","sections":[{"title":"title","highlight_label":"label","rows":[{"header":"header","title":"title","description":"description","id":"select 1"},{"header":"header","title":"title","description":"description","id":"select 2"}]}]}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="quick_reply",
buttonParamsJSON='{"display_text":"Quick URL","url":"https://www.google.com","merchant_url":"https://www.google.com"}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="cta_call",
buttonParamsJSON='{"display_text":"Quick Call","id":"message"}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="cta_copy",
buttonParamsJSON='{"display_text":"Quick Copy","id":"123456789","copy_code":"message"}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="cta_remainder",
buttonParamsJSON='{"display_text":"Reminder","id":"message"}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="cta_cancel_remainder",
buttonParamsJSON='{"display_text":"Cancel Reminder","id":"message"}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="address_message",
buttonParamsJSON='{"display_text":"Address","id":"message"}',
),
InteractiveMessage.NativeFlowMessage.NativeFlowButton(
name="send_location", buttonParamsJSON=""
),
]
),
),
)
)
),
)


@client_factory.event(PairStatusEv)
def PairStatusMessage(_: NewClient, message: PairStatusEv):
log.info(f"logged as {message.ID.User}")


if __name__ == "__main__":
# all created clients will be automatically logged in and receive all events
client_factory.run()
47 changes: 44 additions & 3 deletions goneonize/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func SendMessage(id *C.char, JIDByte *C.uchar, JIDSize C.int, messageByte *C.uch
}

//export Neonize
func Neonize(db *C.char, id *C.char, logLevel *C.char, qrCb C.ptr_to_python_function_string, logStatus C.ptr_to_python_function_string, event C.ptr_to_python_function_bytes, subscribes *C.uchar, lenSubscriber C.int, blocking C.ptr_to_python_function, devicePropsBuf *C.uchar, devicePropsSize C.int, pairphone *C.uchar, pairphoneSize C.int) { // ,
func Neonize(db *C.char, id *C.char, JIDByte *C.uchar, JIDSize C.int, logLevel *C.char, qrCb C.ptr_to_python_function_string, logStatus C.ptr_to_python_function_string, event C.ptr_to_python_function_bytes, subscribes *C.uchar, lenSubscriber C.int, blocking C.ptr_to_python_function, devicePropsBuf *C.uchar, devicePropsSize C.int, pairphone *C.uchar, pairphoneSize C.int) { // ,
subscribers := map[int]bool{}
var deviceProps waProto.DeviceProps
var loginStateChan = make(chan bool)
Expand All @@ -148,8 +148,20 @@ func Neonize(db *C.char, id *C.char, logLevel *C.char, qrCb C.ptr_to_python_func
panic(err)
}
// If you want multiple sessions, remember their JIDs and use .GetDevice(jid) or .GetAllDevices() instead.
deviceStore, err := container.GetFirstDevice()
if err != nil {
var deviceStore *store.Device
var err_device error
var JID defproto.JID

if int(JIDSize) > 0 {
jidbyte_err := proto.Unmarshal(getByteByAddr(JIDByte, JIDSize), &JID)
if jidbyte_err != nil {
panic(jidbyte_err)
}
deviceStore, err_device = container.GetDevice(utils.DecodeJidProto(&JID))
} else {
deviceStore, err_device = container.NewDevice(), nil
}
if err_device != nil {
panic(err)
}
proto.Merge(store.DeviceProps, &deviceProps)
Expand Down Expand Up @@ -1928,6 +1940,35 @@ func PutArchived(id *C.char, user *C.uchar, userSize C.int, archived C.bool) *C.
return C.CString("")
}

//export GetAllDevices
func GetAllDevices(db *C.char) *C.char {
dbLog := waLog.Stdout("Database", "ERROR", true)
container, err := sqlstore.New("sqlite3", fmt.Sprintf("file:%s?_foreign_keys=on", C.GoString(db)), dbLog)
if err != nil {
panic(err)
}

deviceStore, err := container.GetAllDevices()
if err != nil {
panic(err)
}

var result strings.Builder
for i, device := range deviceStore {
if i > 0 {
// an arbitrary delimiter (a unicode to make sure pushname doesn't collide with it)
result.WriteString("|\u0001|")
}
result.WriteString(fmt.Sprintf("%s,%s,%s,%t",
device.ID.String(),
device.PushName,
device.BusinessName,
device.Initialized))
}

return C.CString(result.String())
}

func main() {

}
4 changes: 4 additions & 0 deletions neonize/_binder.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def get_bytes(self):
ctypes.c_char_p,
ctypes.c_char_p,
ctypes.c_char_p,
ctypes.c_int,
ctypes.c_char_p,
func_string,
func_string,
func_callback_bytes,
Expand Down Expand Up @@ -450,5 +452,7 @@ def get_bytes(self):
gocode.PutArchived.restype = ctypes.c_char_p
gocode.GetChatSettings.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
gocode.GetChatSettings.restype = Bytes
gocode.GetAllDevices.argtypes = [ctypes.c_char_p]
gocode.GetAllDevices.restype = ctypes.c_char_p
else:
gocode: Any = object()
Loading

0 comments on commit 97667a0

Please sign in to comment.