воскресенье, 17 июня 2012 г.

How i wrote server side of my application



First of all i want to tell you about how i write my server using Pharo 1.3.
I used WebSocket to make comunication between Amber and Pharo, so i was need in some WebSocket class in my Pharo 1.3. My mentor helps me to found package of classes that contains WebSocket class.
This package is called "WebClient-Core". In this package there are a lot of classes, so i was needed in class "WebSocket". There is an "example" method:


WebSocket >> class
example "WebSocket example"


"This is a very simple WebSocket example implementing a basic chat system.
Each message sent by a client connection is broadcast to everyone."


| mutex sockets |
mutex := Mutex new.
sockets := OrderedCollection new.
WebServer reset default listenOn: 8081.


WebServer default addService: '/' action:[:req|
"Serves the main html chat page"
        req send200Response: self examplePage contentType: 'text/html'.].


WebServer default addService: '/broadcast' action:[:req| | ws |
"Implements the WebSocket broadcaster"
ws := req asWebSocket.
ws timeout: 300. "5 minutes timeout"

Transcript cr; show: 'New ', ws.


ws onMessage:[:data|
mutex critical:[sockets do:[:s| s send: data]].
Transcript cr; show: data asString.
].
ws onClose:[
Transcript cr; show: 'Closing ', ws.
mutex critical:[sockets remove: ws ifAbsent:[]].
].
ws onError:[:ex|
Transcript cr; show: ws.
Transcript cr; show: ex description.
Transcript cr; show: ex signalerContext longStack.
].
mutex critical:[sockets add: ws].
"We don't need to #fork here, in fact we shouldn't since it ensures
that shutting down WebServer shuts down any WebSockets, too."
ws run.
].


I used this method to write my own server.


WebHMIServer class
instanceVariableNames: 'sockets mutex'


When some server object was needed to emit event, for example "state changed", i used variables "mutex" and "sockets" to send this event to clients.
Also i rewrite "onMessage" part:

WebHMIServer >> class
...
ws onMessage: [ :data | self processMessage: data withMutex: mutex fromSockets: sockets ].
...


WebHMIServer >> class

processMessage: aMessage withMutex: aMutex fromSockets: aSockets
Transcript
cr;
show: aMessage asString;
cr.
(aMessage findString: '@getScheme') = 0
ifFalse: [ WebHMIElement elements do: [ :el | el info ] ].
(aMessage findString: '@switch') = 0
      ifFalse: [ Compiler evaluate: ((aMessage subStrings: '#') at: 2) ].
(aMessage findString: '@changePos') = 0
      ifFalse: [ Compiler evaluate: ((aMessage subStrings: '#') at: 2) ].
(aMessage findString: '@add') = 0
      ifFalse: [ Compiler evaluate: ((aMessage subStrings: '#') at: 2) ].
(aMessage findString: '@remove') = 0
      ifFalse: [ Compiler evaluate: ((aMessage subStrings: '#') at: 2) ]

Also there is method on class side, that runs my server on any port:

WebHMIServer >> class

startServerOnPort: aPort
Transcript
cr;
show: '*** WebHMI server ***';
cr.
mutex := Mutex new.
sockets := OrderedCollection new.
WebServer reset default listenOn: aPort.


WebServer default
addService: '/broadcast'
action: [ :req | 
| ws |
ws := req asWebSocket.
ws timeout: 1000.
Transcript
cr;
show: 'Client connected: ' , ws.
ws send: 'You connected'.
ws onMessage: [ :data | self processMessage: data withMutex: mutex fromSockets: sockets ].
ws
onClose: [ 
Transcript
cr;
show: 'Closing ' , ws.
mutex critical: [ sockets remove: ws ifAbsent: [  ] ] ].
ws onError: [ :ex |  ].


This server allows me to have comunication between Amber and Pharo 1.3.

What i want to do with this server in future
I want to make comunication between client and server parallel. This is very important and one of the most complicated parts of the system.
If you have any suggestions or comments, please, let me know.







Комментариев нет:

Отправить комментарий