Message Boards Message Boards

3
|
2307 Views
|
0 Replies
|
3 Total Likes
View groups...
Share
Share this post:

Implement a ChannelFramework-based chat system in Mathematica

Posted 6 years ago

This was reasonably popular on the StackExchange and people here sometimes like framework development things, so I'm copying it over from here for those who don't spend time on StackExchange.


Building a chat framework in Mathematica

The basic question is: "how can I use the ChannelFramework to build a chat system?"

This is place where OOP comes in very useful, so I'll use my latest OOP framework to implement this. I've cooked this into an entire package here

Basic System

But before we get into the OOP, we should establish how this should work. My thought is that we should be as unrestrictive as possible, and the best way to do that is by simply passing Cell objects through our channel.

Recieved Cell action

So if we think about what we expect to receive, we'll want to Compress our Cell, send it through, and then decompress at the other end.

Each message is passed with a few metadata parameters, including "Timestamp" and "RequesterWolframID". We'll use these to build a CellFrameLabel to attach to each Cell.

In the linked package this can be seen here

Notebook Setup

The heart of this system is just a plain notebook that will act as our interface. The way I built this out was just having something that would NotebookPut a "ChatLog" into a notebook to start and then write new Cells after the final chat cell in the notebook.

These functions are implemented here and here

We'll also stick on a DockedCell which will check for updates to our baseline object and call our "Write" function and NotebookEventActions to catch "HandleShiftReturn" when it's called outside of a cell.

Channel Setup

With our Notebook out of the way we can move to handling our ChannelObject. The ChannelObject we'll build based on config options we cook into our underlying object. The ChannelListener we make will simply dump new messages to our object's "ChatLog".

The set up functions to these are here

Chat Object

Everything before this has been really standard, but this part will be new for pretty much everyone (but not hard in anyway). So I'll go over it in a bit more detail.

Basically we're going to build a class for instantiating chat objects. In my newest OOP framework this is handled by creating a basic object with a "New" member function that calls SObjInstantiate.

SObjInstantiate then takes the attributes cooked into "ObjectInstanceProperties" and just wraps them in.

You can see the entire class declaration <a href="">here but there are a few things to note. First off, most of the object properties are basically just wrappers on the package functions we defined, e.g. in our "ObjectInstanceProperties" we'll have:

"StartChat" ->
 SObjMethod@
  Function[chatObjectCreateChannel[#];
   chatObjectChannelListen[#];
   #["OpenChat"][]
   ]

The SObjMethod just declares that when accessed this should be bound to the instance it's called from.

We do the same for our other parameters and implementation functions.

Finally, we add a single method to the class itself, which is simply a convenience function so that we can create and start a chat in one call:

"StartChat" ->
 SObjMethod[
  With[{n = #["New"][##]},
    n["StartChat"][];
    n
    ] &
  ]

This is a classic thing to do in python, adding a classmethod that both instantiates and does something--and python is what this OOP system is inspired by.

Example

Finally, the fun part, we can see how we can use this package.

First we'll make a new chat instance:

(* Just a Check to see if you have the ChatSystem installed already *)
 Quiet[
  Check[
   <<ChatSystem`,
   Get["https://github.com/b3m2a1/mathematica-tools/raw/master/ChatSystem.wl"]
   ],
  Get::noopen
  ];
(* Makes a new ChatObject instance and opens the chat notebook *)
ChatObject["StartChat"][]

And we can use it like a normal NotebookObject:

And press Shift-Enter at the bottom of the NB to send the data to the ChannelObject:

Cells that have been sent through or received from the ChannelObject get a timestamp attached to them and lose their Editability.

As a test we can send ourselves a message from a cloud notebook. First we'll add the other users as allowed contributors to our channel via the "AddChannelMember" method of our chat object, then I can log into my cloud account and send myself a message:

enter image description here

And the chat system supports relatively few features at the moment (it's only been alive for about a day), but it has the big ones I see, like changing the usernames and messages display.

You do this with the "ChatCellSettings" option, which can take any basic Cell options and two for the timestamp, "NameMapping", and "NameStyling".

Hope this is a decent example of how OOP and the ChannelFramework can play nicely together.

If you have questions or want clarification on how things work let me know.

POSTED BY: b3m2a1 ​ 
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract