diff --git a/examples/molhokwai/app/static/js/app.js b/examples/molhokwai/app/static/js/app.js new file mode 100644 index 0000000..ef59fa6 --- /dev/null +++ b/examples/molhokwai/app/static/js/app.js @@ -0,0 +1,187 @@ +// File: static/js/app.js +(function() { + 'use strict'; + + var pusher = new Pusher('1ed4f14aec1b394a4ed4', { + authEndpoint: '/emelit/plugin_pusher/pusher_auth.json', + cluster: 'eu', + encrypted: true + }); + + // ---------------------------------------------------- + // Chat Details + // ---------------------------------------------------- + + let chat = { + name: undefined, + email: undefined, + myChannel: undefined, + } + + + // ---------------------------------------------------- + // Targeted Elements + // ---------------------------------------------------- + + const chatPage = $(document) + const chatWindow = $('.chatbubble') + const chatHeader = chatWindow.find('.unexpanded') + const chatBody = chatWindow.find('.chat-window') + + + // ---------------------------------------------------- + // Register helpers + // ---------------------------------------------------- + + let helpers = { + + // ---------------------------------------------------- + // Toggles the display of the chat window. + // ---------------------------------------------------- + + ToggleChatWindow: function () { + chatWindow.toggleClass('opened') + chatHeader.find('.title').text( + chatWindow.hasClass('opened') ? 'Minimize Chat Window' : 'Chat with Support' + ) + }, + + // -------------------------------------------------------------------- + // Show the appropriate display screen. Login screen or Chat screen. + // -------------------------------------------------------------------- + + ShowAppropriateChatDisplay: function () { + (chat.name) ? helpers.ShowChatRoomDisplay() : helpers.ShowChatInitiationDisplay() + }, + + // ---------------------------------------------------- + // Show the enter details form. + // ---------------------------------------------------- + + ShowChatInitiationDisplay: function () { + chatBody.find('.chats').removeClass('active') + chatBody.find('.login-screen').addClass('active') + }, + + // ---------------------------------------------------- + // Show the chat room messages display. + // ---------------------------------------------------- + + ShowChatRoomDisplay: function () { + chatBody.find('.chats').addClass('active') + chatBody.find('.login-screen').removeClass('active') + + setTimeout(function(){ + chatBody.find('.loader-wrapper').hide() + chatBody.find('.input, .messages').show() + }, 2000) + }, + + // ---------------------------------------------------- + // Append a message to the chat messages UI. + // ---------------------------------------------------- + + NewChatMessage: function (message) { + if (message !== undefined) { + const messageClass = message.sender !== chat.email ? 'support' : 'user' + + chatBody.find('ul.messages').append( + `
  • +
    ${message.name}
    +
    ${message.text}
    +
  • ` + ) + + + chatBody.scrollTop(chatBody[0].scrollHeight) + } + }, + + // ---------------------------------------------------- + // Send a message to the chat channel. + // ---------------------------------------------------- + + SendMessageToSupport: function (evt) { + + evt.preventDefault() + + let createdAt = new Date() + createdAt = createdAt.toLocaleString() + + const message = $('#newMessage').val().trim() + + if(false){ + // removed client side trigerring + chat.myChannel.trigger('client-guest-new-message', { + 'sender': chat.name, + 'email': chat.email, + 'text': message, + 'createdAt': createdAt + }); + } + else{ + // added server side trigerring for event handling + let sender = chat.name + let email = chat.email + let text = message + axios.post('/emelit/plugin_pusher/message.json', {sender, email, text, createdAt}).then(response => { + // received: sender, email, text, createdAt + // pass + }) + } + + helpers.NewChatMessage({ + 'text': message, + 'name': chat.name, + 'sender': chat.email + }) + + console.log("Message added!") + + $('#newMessage').val('') + }, + + // ---------------------------------------------------- + // Logs user into a chat session. + // ---------------------------------------------------- + + LogIntoChatSession: function (evt) { + const name = $('#fullname').val().trim() + const email = $('#email').val().trim().toLowerCase() + + // Disable the form + chatBody.find('#loginScreenForm input, #loginScreenForm button').attr('disabled', true) + + if ((name !== '' && name.length >= 3) && (email !== '' && email.length >= 5)) { + axios.post('/emelit/plugin_pusher/guest.json/new', {name, email}).then(response => { + chat.name = name + chat.email = email + chat.myChannel = pusher.subscribe('private-' + response.data.email); + helpers.ShowAppropriateChatDisplay() + }) + } else { + alert('Enter a valid name and email.') + } + + evt.preventDefault() + } + } + + // ------------------------------------------------------------------ + // Listen for a new message event from the admin + // ------------------------------------------------------------------ + + pusher.bind('client-support-new-message', function(data){ + helpers.NewChatMessage(data) + }) + + + // ---------------------------------------------------- + // Register page event listeners + // ---------------------------------------------------- + + chatPage.ready(helpers.ShowAppropriateChatDisplay) + chatHeader.on('click', helpers.ToggleChatWindow) + chatBody.find('#loginScreenForm').on('submit', helpers.LogIntoChatSession) + chatBody.find('#messageSupport').on('submit', helpers.SendMessageToSupport) +}()) diff --git a/examples/molhokwai/script/plugin_pusher.py b/examples/molhokwai/script/plugin_pusher.py new file mode 100644 index 0000000..c4204b9 --- /dev/null +++ b/examples/molhokwai/script/plugin_pusher.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +import sys +sys.path.append('..') + +import time + +import pusherclient +from plugin_pusher import settings + +# Add a logging handler so we can see the raw communication data +import logging +root = logging.getLogger() +root.setLevel(logging.INFO) +ch = logging.StreamHandler(sys.stdout) +root.addHandler(ch) + +global pusher + +def print_usage(filename): + print("Usage: python %s " % filename) + +def channel_callback(data): + print("Channel Callback: %s" % data) + +def connect_handler(data): + for c in channel_names: + if not channel_names[c][0]: + channel = pusher.subscribe(c) + + _events = channel_names[c][1] + for e in _events: + if not _events[e]: + channel.bind(e, channel_callback) + _events[e] = True + channel_names[c][0] = True + + +appkey = settings.appkey or None +appcluster = settings.appcluster or None +channel_names = settings.channel_names or {} + +if __name__ == '__main__': + if not appkey: + if len(sys.argv) != 3: + print_usage(sys.argv[0]) + sys.exit(1) + else: + appkey = sys.argv[1] + appcluster = sys.argv[2] + + """ + Changes: + ------- + Cluster: Added cluster in host name (also in process file arguments) + Channel names, event names: Added chosen event names binding for given channel name + + - Added cluster parameter () + > Added cluster in host name in + > Removed @classmethod attribute + - Added event_names parameter (, ) + > Added event_names binding in + + @acknowledgement: Pysher (https://github.com/nlsdfnbch/Pysher/blob/master/pysher/pusher.py) + @framework: Pusher (https://pusher.com/tutorials/chat-widget-python) + """ + event_names = [] + for c in channel_names: + event_names += channel_names[c][1].keys() + pusher = pusherclient.Pusher(appkey, cluster=appcluster, event_names=event_names) + pusher.connection.bind('pusher:connection_established', connect_handler) + + pusher.connect() + print + print '------------------------------------------------------------' + print + + while True: + time.sleep(1) diff --git a/examples/molhokwai/script/plugin_pusher/__init__.py b/examples/molhokwai/script/plugin_pusher/__init__.py new file mode 100644 index 0000000..4265cc3 --- /dev/null +++ b/examples/molhokwai/script/plugin_pusher/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python diff --git a/examples/molhokwai/script/plugin_pusher/settings.py b/examples/molhokwai/script/plugin_pusher/settings.py new file mode 100644 index 0000000..ce1429d --- /dev/null +++ b/examples/molhokwai/script/plugin_pusher/settings.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +appkey = '1ed4f14aec1b394a4ed4' +appcluster = 'eu' +# channel_names { [name] : [ subscribed (bool), event_names { [name] : bound (bool) } ] } +channel_names = { 'general-channel': [False, { 'client-guest-new-message': False }] } diff --git a/pusherclient/__init__.py b/pusherclient/__init__.py index acd5ec9..6533f13 100755 --- a/pusherclient/__init__.py +++ b/pusherclient/__init__.py @@ -19,7 +19,13 @@ class Pusher(object): client_id = 'PythonPusherClient' protocol = 6 - def __init__(self, key, secure=True, secret=None, user_data=None, log_level=logging.INFO, daemon=True, port=None, reconnect_interval=10): + def __init__(self, key, cluster=None, event_names=[], secure=True, secret=None, user_data=None, log_level=logging.INFO, daemon=True, port=None, reconnect_interval=10): + # https://pusher.com/docs/clusters + if cluster: + self.host = "ws-{cluster}.pusher.com".format(cluster=cluster) + else: + self.host = "ws.pusherapp.com" + self.key = key self.secret = secret self.user_data = user_data or {} @@ -28,7 +34,7 @@ def __init__(self, key, secure=True, secret=None, user_data=None, log_level=logg self.url = self._build_url(key, secure, port) - self.connection = Connection(self._connection_handler, self.url, log_level=log_level, daemon=daemon, reconnect_interval=reconnect_interval) + self.connection = Connection(self._connection_handler, self.url, event_names=event_names, log_level=log_level, daemon=daemon, reconnect_interval=reconnect_interval) def connect(self): """Connect to Pusher""" @@ -122,13 +128,12 @@ def _generate_presence_key(socket_id, key, channel_name, secret, user_data): return auth_key - @classmethod - def _build_url(cls, key, secure, port=None): + def _build_url(self, key, secure, port=None): path = "/app/%s?client=%s&version=%s&protocol=%s" % ( key, - cls.client_id, + self.client_id, VERSION, - cls.protocol + self.protocol ) proto = "ws" @@ -144,7 +149,7 @@ def _build_url(cls, key, secure, port=None): return "%s://%s:%s%s" % ( proto, - cls.host, + self.host, port, path ) diff --git a/pusherclient/connection.py b/pusherclient/connection.py index 75fe53f..05e3c70 100755 --- a/pusherclient/connection.py +++ b/pusherclient/connection.py @@ -10,7 +10,7 @@ class Connection(Thread): - def __init__(self, event_handler, url, log_level=logging.INFO, daemon=True, reconnect_interval=10): + def __init__(self, event_handler, url, event_names=[], log_level=logging.INFO, daemon=True, reconnect_interval=10): self.event_handler = event_handler self.url = url @@ -33,6 +33,8 @@ def __init__(self, event_handler, url, log_level=logging.INFO, daemon=True, reco self.bind("pusher:pong", self._pong_handler) self.bind("pusher:ping", self._ping_handler) self.bind("pusher:error", self._pusher_error_handler) + for event_name in event_names: + self.bind(event_name, event_handler) self.state = "initialized"