Pichat developer documentation
Last update 25/May/2011 by Mark Seuffert
Overview:
1. Introduction2.1. Simple chat clients
2.2. Simple chat status query
3. Plugin programming
4. Join the development team
Appendix A: Pichat class diagram example
Appendix B: Pichat information flow example
Appendix C: Pichat development philosophy
1. Introduction
Learn how to write own chat features and awake the chat with more life. This document is for
developers who want to extend their chat and gives you an introduction of how to communicate
with chat servers and write own plugins. There is also a software development kit (Pichat SDK)
for download which comes with libraries, examples and unit tests.
2.1. Simple chat clients
Pichat supports a text chat protocol which makes it very easy to access chatrooms on a chat
server. The idea is to enable the implementation of small, simple chat clients and also to
simplify the communication between multiple chat applications.
What you need to do in your client: Connect to a chat server and send the login sequence below
as first line, all arguments are optionally. A chat server identifies itself by sending "PICHAT"
(hex 0x50 0x49 0x43 0x48 0x41 0x54) as first six bytes of identification, otherwise terminate
connection immediately. If you are successfully connected show received text lines to the user
and send typed in text lines to the server. The chat server does the rest and provides you with a
complete text description of what's happening in the chat. No parsing required, easy peasy lemon
squeezy.
Optionally, clients can suppport ping replies and lag detection. For this you need to enable the
PINGSUPPORT setting when connecting, e.g. by sending the command /ECHO SETSILENT PINGSUPPORT.
The chat server will then send additional text lines beginning with "!PING" or "!SERVER_PING",
which the client has to answer immediately with a /PINGREPLY and the received text. The client can
also send in regular intervalls a /PINGREPLY KEEPALIVE (e.g. after 150 seconds without server ping).
| Syntax: | PICHAT/TEXTCHAT nickname, chatroom, language, authentication, useragent, format, localtime, timehours | |||||||||||||||||||||||||||||||||||||||||||||
| Arguments: |
| |||||||||||||||||||||||||||||||||||||||||||||
| Examples: | PICHAT/TEXTCHAT Moak | |||||||||||||||||||||||||||||||||||||||||||||
| PICHAT/TEXTCHAT Moak, Flirt, de,, talker, TEXT, 14:30:05, 24 | ||||||||||||||||||||||||||||||||||||||||||||||
| PICHAT/TEXTCHAT Moak,,, YWxhZGRpbjpvcGVuc2VzYW1l |
First example connects to a chat server using the nickname 'Moak'. The second example connects a
text client with German language to the chatroom 'Flirt' and also sets a local time. The third
example connects as registered user with the user name 'aladdin' and password 'opensesame'.
Notes: The protocol is line based plaintext (8-bit-characters), each line is
separated through \r\n (CRLF). Default listening port of a chat server is 9009
TCP. Under no circumstances must the login sequence be extended with more
arguments. which would lead to incompatibility. Application specific extensions
shall go into separate lines, for example echo settings.
2.2. Simple chat status query
Pichat offers a simple chat status query, you can check if a chat server is
online and see how many users are there. Connect to a chat server and send the
status sequence below. A chat server identifies itself by sending "PICHAT" as
first six bytes of identification, then returns version information, server
status (users, activity, dedicated, chat mode, lag), extended server status
(users-served, traffic, uptime, interests) and another line with server name,
entrance and welcome message. After that the client will be disconnected.
| Syntax: | PICHAT/STATUS user-identification, name, language, useragent | |||||||||||||||
| Arguments: |
| |||||||||||||||
| Examples: | PICHAT/STATUS moak@unknown, Moak | |||||||||||||||
| PICHAT/STATUS moak@unknown, Moak, sv, mybot/1.0 (+http://myserver) |
First example queries chat status as user 'Moak', the second example requests
chat status in Swedish language and includes an detailed user agent description.
Here's a typical chat server response:
PICHAT
!SERVER_VERSION Pichat Server v0.4.2 b60
!SERVER_STATUS 4,38,0,1,0
!SERVER_STATUS_EXTENDED 64,64738,6510,chat,music,pizza
!SERVER_INFO Moak's Chat,Entrance,Welcome to Moak's chat
!CONNECT_STATUS 203 Done, end of connection
!SERVER_VERSION Pichat Server v0.4.2 b60
!SERVER_STATUS 4,38,0,1,0
!SERVER_STATUS_EXTENDED 64,64738,6510,chat,music,pizza
!SERVER_INFO Moak's Chat,Entrance,Welcome to Moak's chat
!CONNECT_STATUS 203 Done, end of connection
Notes: Clients should not request the chat status more than once per minute to
avoid flooding a chat server. Alternatively, the chat status is also available as
web page and RSS feed (XML format). For further information please see
status and statistics.
3. Plugin programming
Pichat supports plugins to add additional features to chat and web server.
Plugins can be used for a variety of things, from handling chat actions such as
users joining a chatroom up to chat bots that interact independently with users
in the chat. Plugin are typically written in the C++ programming language.
What you need to do in your own plugin: Basically are all plugins shared
libraries that implement a C++ interface and export a function called
CreatePlugin().
Here's an example source code:
using namespace PichatCore;
namespace Plugin
{
class CImplementation : public IPluginInterface
{
public:
CImplementation(IApplicationInterface* pApi)
{
//TODO: more code here
}
virtual ~CImplementation() { }
virtual void DeleteThis() const { delete this; }
virtual const char* GetVersionName() const { return "Example.Simple"; }
virtual const char* GetVersionDescription() const { return "Chat plugin example"; }
virtual int GetVersionNumber() const { return 0x000101; } //note: v0.1.1
virtual const char* GetAuthor() const { return "Created by Moaky Moak"; }
};
};
PLUGINEXAMPLE_EXPORT IPluginInterface* CreatePlugin(IApplicationInterface* pApi)
{
return new Plugin::CImplementation(pApi);
}
When a plugin is created it usually receives a pointer to an application interface
which gives access to chat functionality ('pApi' in code above).
Here another example source code, with some extensions to the previous example:
using namespace PichatCore;
namespace Plugin
{
class CImplementation : public IPluginInterface, public ICoreServerInterface
{
public:
CImplementation(IApplicationInterface* pApi)
{
m_pApi = pApi;
if(m_pApi) m_pApi->SetCoreServerHandler(this, this);
}
virtual ~CImplementation() { }
virtual void DeleteThis() const { delete this; }
virtual const char* GetVersionName() const { return "Example.Simple"; }
virtual const char* GetVersionDescription() const { return "Chat plugin example"; }
virtual int GetVersionNumber() const { return 0x000102; } //note: v0.1.2
virtual const char* GetAuthor() const { return "Created by Moaky Moak"; }
protected:
virtual void OnChatServer(int nChatAction, ChatActions::ChatCallbackData data)
{
ASSERT(m_pApi);
if(nChatAction == ChatActions::CHAT_SERVER_ONLINE) m_pApi->ProcessChatCommand("/STATUSTEXT Hello world");
}
virtual void OnHttpServer(int nRequestType, ChatActions::HttpCallbackData data) {}
private:
IApplicationInterface* m_pApi; //application interface
};
};
PLUGINEXAMPLE_EXPORT IPluginInterface* CreatePlugin(IApplicationInterface* pApi)
{
return new Plugin::CImplementation(pApi);
}
The plugin uses an interface to request chat events from the server ('ICoreServerInterface'
in code above) and outputs 'Hello world' when the server goes online. It's good to have a look
at existing plugins and investigate how they work. There are examples showing you how to read
preferences or how to create own chat bots, there are also two libraries PichatCore and
SharkEngine to assist you in writing plugins. For further information please see Pichat SDK.
Notes: All plugins are loaded on application startup. You can see present plugins
with the /PLUGIN command in the chat. The plugin version
name has the format 'category.type', where category describes the offered service
such as 'bot' or 'webcam'.
4. Join the development team
You enjoy creating software with graphics and networking. Why not working
together and improve this project together? Pichat is technically based on C++,
STL and a platform independent core that runs on Linux, BSD and Windows. Doesn't
that sound like fun programming to you... :)
- Plugin development: Write chat plugins for all kind of nice stuff, improve chat and webchat with new features. Download the Pichat SDK and start coding your own chat features. Basic programming skills in C++ required.
- Client development: Write native code for a specific platform or programming language. Create a new chat client in your favourite programming language, how about a chat for a mobile phone? Basic programming skills required.
- PichatCore development: Write platform independent code and design new chat features. Pichat is constantly envolving and new features will be added. Good knowledge of peer-to-peer networks (P2P) and chat systems required.
See what's planned next on the road map.
Appendix A: Pichat class diagram example
The following diagram shows an example design for a peer-to-peer chat application.
Usually an application is client and server at once, plus a graphical user
interface on top. Basically the same design is also used in existing Pichat
software. Lines show HasA relationships between classes and not inheritance. An
asterisk emphasises a many-to-one relationship.
CPichat
|
. . . . . . | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
DATA CPichat ________ CPichat _______________________________________________________________________________________________
PART MainFrame MainData | | |
| | | | CPichatClientManager CPichatServerManager CPichatPluginManager
| | | | | | |
| | | |___ CPichatMain |___ CSocketClientPreferences |___ CSocketServerPreferences |___ CPichatPluginPreferences
| | | | Preferences | | |
| | | | |___*CClientConnection |___ CSocketServerPichat |___*CPichatPlugin
| | | |___ CPichatGui |___ CSocketClientPichat |___ CSocketServerHttp
| | | | Preferences |___ CSocketHelperDns |___ CSocketObserverPichat
| | | |
| | | |___ CPichatContacts
| | | Preferences
| | |
. . . . . | | | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
| | |
GUI | | |_____ CSystemTray
PART | |
| |_______ CPichatDialogManager ___________________________________________________
| | | |
CPichat CPichat *CPichat |___ CPichat
Dialog3D DialogMain DialogChat | DialogAbout
| | |
|___*CPichatViewConnection |___ CPichatViewConnection |___ CPichat
| |___ CTextBoxChat |___ CTextBoxChat | DialogStatus
| |___ CListBoxSide |___ CListBoxSide |
| |___ CEditBoxChat |___ CEditBoxChat |___ CPichat
| DialogOptions
|___ CPichatViewStatus
|___ CPichatViewContacts
|___ CPichatViewButtons
Figure 1: Example class design
While the 'DATA PART' typically is implemented platform independent and shared
between different platforms, the 'GUI PART' is implemented platform specific to
match best to the native user interface and therefore offers a native look and
feel. A special case is the class CPichat that kicks off the application
framework, it is different for each purpose.
Pichat is created with the idea of agile software development in mind: First make
it work, then make it better. So it's no big surprise that one of the biggest
design goal for Pichat is maintainability (design to fit the needs, but at the
same time love and expect changes). There are two main software design factors I
am personally looking at: First, which functionality does a class offer, is its
(public) interface intuitive and safe to use? Secondly, how does the information
flow work, is it elegant and efficient?
Appendix B: Pichat information flow example
This diagram shows information flow of text input with an example. Typically text
input comes from a view, a client sends it then to a server, data is being
processed there, again received by the client and finally text output is shown in
a chat window. Both client side and server side are able to process chat commands.
CClientConnectionView CClientConnection
::SendInput() ---------> ::SendInput() -----------------------
| |
\ / \ /
CClientConnection CSocketClient
::ProcessChatCommand() --> ::SendInput()
|
------------------------|
| |
| \ /
| CSocketClient CSocketNode
| ::Send() ------------ TCP --> ::OnReceiveLine()
| |
| \ /
| CSocketNode CSocketServer
| ::ProcessChatCommand() --> ::SendAll()
| | |
| \ / |
| CSocketClient CSocketNode |
|--------------- ::OnReceiveLine() <-- TCP --- ::Send() <-----------------------
| |
| |
| |
| \ /
| CSocketClient
\ / ::ProcessChatAction()
CClientConnectionView CClientConnection |
::OnChatText() <----------- ::OnChatClientCallback() <-------
|
\ /
CClientConnectionStatusView CClientConnectionManager
::OnChatNetwork() <-------- ::SendAllStatus()
Figure 2: Example information flow of text input
Appendix C: Pichat development philosophy
The development philosophy behind Pichat.
- Improve technology. Are open minded for new ways, learn and are curious!
- Share information. Collaboration and good processes make life easier!
- Have fun in life. Keep motivation high all the time!
Let me explain what I mean with good processes. I think that processes are more
important than the organisation or the structure of a system (e.g. processes are
in my experience more relevant than the hierarchy of a development group). A
structure is always something static that tries to organise the information flow
and the purpose of individuals inside. But what we actually want to achieve is
creating an efficient system that delivers maximised output (software in our case)
and adapts itself to changing circumstances.
Let's see it from this perspective and accordingly optimise information flow and
its key components: Such as information distribution, communication between
individuals, organisation of team work and safe guards to minimise risks or
problems that show up on the way. Structures are better built on processes than
the other way around (e.g. when you wrongly build processes on existing
structures you have already made design decisions that weaken structural self
organisation, possibly limit information flow and efficiency of team work). In a
similar way are individuals better defined by their tasks and strengths rather
than by a position (e.g. there is generally the sneaking danger of hierarchical
structures defining themself by their position and less by the real purpose they
fullfill or the processes that would otherwise be applied, people in key positions
are tempted to put personal interests over goals of the whole system).
Organisation of team work is best when different planing parties (e.g. technical
and non technical planing) work equally together and define their tasks as a
looking ahead assistance for others. For example take commercial software projects
which often suffer from "management" trying to control instead of aiding the
creative design processes. As a result are problems and product shortcomings
often denied until it is too late. A proper management would requires that
different planing parties work together, including engineers and customers.
There is also a deeply rooted misunderstanding of what "software engineering" is,
I believe it's a design discipline and not a deterministic engineering discipline
at all (software engineers spend more time on software design decisions than on
building software, eminent requirements will emerge during the whole development
life cycle). However, a bigger problem than technical hurdles are usually
individuals and the lack of communication between them. For example let five
people work together, watch how misunderstandings and dislikes grow and opinions
collide in a non productive way. Let's face it, we all have to deal with
incompetence and insensitivity, hopefully not every day, but we need to develop
strategies to deal with it and also how to integrate problematic persons into our
day to day work. Some tips: allow people to create a personal relationship to
you, explore problems and feelings in a personal dialogue (not in front of
others). A few more psychological aspects to look at: a lack of clearness and
security cause humans to feel unhappy, a lack of vision and purpose causes humans
to disconnect from a project. But on the other hand (a manageable level of)
responsibility and challenge are directly related to higher productivity and joy.
Ideally, there should be processes in place to monitor and improve the overall
effectiveness and health status of a system (or 'Wohlfühlstatus' in German, a word
that describes the feeling-good-state of a complete system and its individuals,
it's an empathic expression that underlines the importance of the human side).
For example take a development group that produces output but is unhappy, it will
sooner or later collapse or needs time to raise to a next level. On the other
hand take a motivated but inefficient development group, it will produce no
satisfying output and needs time to raise productivity and quality. There is
generally nothing you can do against bad politics and wrong people in powerful
positions other than to de-power those people quickly (remember to focus on
building processes not structures).
Summing it up, I believe that software processes are utterly important for any
software project, to create an environment where ideas are allowed to be realised
and people enjoy working with each other.

