From f3b3d4b1a26eba872c32ad95fc112650011b625c Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 23 Nov 2025 17:05:53 +0100 Subject: Add the tiny-chat project from the Pharo MOOC --- .../src/TinyChat-client/TCConsole.class.st | 62 ++++++++++ .../src/TinyChat-client/TinyChat.class.st | 130 +++++++++++++++++++++ .../tiny-chat/src/TinyChat-client/package.st | 1 + 3 files changed, 193 insertions(+) create mode 100644 pharo-mooc/tiny-chat/src/TinyChat-client/TCConsole.class.st create mode 100644 pharo-mooc/tiny-chat/src/TinyChat-client/TinyChat.class.st create mode 100644 pharo-mooc/tiny-chat/src/TinyChat-client/package.st (limited to 'pharo-mooc/tiny-chat/src/TinyChat-client') diff --git a/pharo-mooc/tiny-chat/src/TinyChat-client/TCConsole.class.st b/pharo-mooc/tiny-chat/src/TinyChat-client/TCConsole.class.st new file mode 100644 index 0000000..3f7055e --- /dev/null +++ b/pharo-mooc/tiny-chat/src/TinyChat-client/TCConsole.class.st @@ -0,0 +1,62 @@ +Class { + #name : 'TCConsole', + #superclass : 'SpPresenter', + #instVars : [ + 'chat', + 'list', + 'input' + ], + #category : 'TinyChat-client', + #package : 'TinyChat-client' +} + +{ #category : 'as yet unclassified' } +TCConsole class >> attach: aTinyChat [ + + | window | + window := self new chat: aTinyChat. + window open whenClosedDo: [ aTinyChat disconnect ]. + ^ window +] + +{ #category : 'as yet unclassified' } +TCConsole class >> defaultLayout [ + ^ SpBoxLayout newTopToBottom + add: #list; add: #input; yourself +] + +{ #category : 'accessing' } +TCConsole >> chat: anObject [ + chat := anObject +] + +{ #category : 'accessing' } +TCConsole >> initializeWidgets [ + + list := SpListPresenter new. + input := SpTextInputFieldPresenter new + placeholder: 'Type your message here...'; + enabled: true; + whenSubmitDo: [ :string | chat send: string. input text: '' ]. + self focusOrder add: input +] + +{ #category : 'accessing' } +TCConsole >> input [ + ^ input +] + +{ #category : 'accessing' } +TCConsole >> list [ + ^ list +] + +{ #category : 'accessing' } +TCConsole >> print: aCollectionOfMessages [ + list items: (aCollectionOfMessages collect: [ :m | m printString ]) +] + +{ #category : 'accessing' } +TCConsole >> title [ + ^ 'TinyChat' +] diff --git a/pharo-mooc/tiny-chat/src/TinyChat-client/TinyChat.class.st b/pharo-mooc/tiny-chat/src/TinyChat-client/TinyChat.class.st new file mode 100644 index 0000000..f19e3a4 --- /dev/null +++ b/pharo-mooc/tiny-chat/src/TinyChat-client/TinyChat.class.st @@ -0,0 +1,130 @@ +Class { + #name : 'TinyChat', + #superclass : 'Object', + #instVars : [ + 'url', + 'login', + 'exit', + 'messages', + 'console', + 'lastMessageIndex' + ], + #category : 'TinyChat-client', + #package : 'TinyChat-client' +} + +{ #category : 'as yet unclassified' } +TinyChat class >> connect: aHost port: aPort login: aLogin [ + + ^ self new + host: aHost port: aPort login: aLogin; + start +] + +{ #category : 'initialization' } +TinyChat >> cmdLastMessageID [ + ^ self command: '/messages/count' +] + +{ #category : 'initialization' } +TinyChat >> cmdMessagesFromLastIndexToEnd [ + "Returns the server messages from my current last index to the last on the server." + ^ self command: '/messages' argument: lastMessageIndex +] + +{ #category : 'initialization' } +TinyChat >> cmdNewMessage [ + ^self command: '/messages/add' +] + +{ #category : 'initialization' } +TinyChat >> command: aPath [ + ^'{1}{2}' format: { url . aPath } +] + +{ #category : 'initialization' } +TinyChat >> command: aPath argument: anArgument [ + ^'{1}{2}/{3}' format: { url . aPath . anArgument asString } +] + +{ #category : 'initialization' } +TinyChat >> disconnect [ + self sendNewMessage: (TCMessage from: login text: 'I exited from the chat room.'). + exit := true +] + +{ #category : 'as yet unclassified' } +TinyChat >> host: aHost port: aPort login: aLogin [ + url := 'http://' , aHost , ':' , aPort asString. + login := aLogin +] + +{ #category : 'initialization' } +TinyChat >> initialize [ + super initialize. + exit := false. + lastMessageIndex := 0. + messages := OrderedCollection new +] + +{ #category : 'initialization' } +TinyChat >> readLastMessageID [ + | id | + id := (ZnClient new url: self cmdLastMessageID; get) asInteger. + id = 0 ifTrue: [ id := 1 ]. + ^ id +] + +{ #category : 'initialization' } +TinyChat >> readMissingMessages [ + "Gets the new messages that have been posted since the last request." + | response receivedMessages | + response := (ZnClient new url: self cmdMessagesFromLastIndexToEnd; get). + ^ response + ifNil: [ 0 ] + ifNotNil: [ + receivedMessages := response substrings: (String crlf). + receivedMessages do: [ :msg | messages add: (TCMessage fromString: msg) ]. + receivedMessages size + ] +] + +{ #category : 'initialization' } +TinyChat >> refreshMessages [ + [ + [ exit ] whileFalse: [ + (Delay forSeconds: 2) wait. + lastMessageIndex := lastMessageIndex + (self readMissingMessages). + console print: messages + ] + ] fork +] + +{ #category : 'initialization' } +TinyChat >> send: aString [ + "When we send a message, we push it to the server and in addition + we update the local list of posted messages" + + | msg | + msg := TCMessage from: login text: aString. + self sendNewMessage: msg. + lastMessageIndex := lastMessageIndex + (self readMissingMessages). + console print: messages +] + +{ #category : 'initialization' } +TinyChat >> sendNewMessage: aMessage [ + ^ ZnClient new + url: self cmdNewMessage; + formAt: 'sender' put: (aMessage sender); + formAt: 'text' put: (aMessage text); + post +] + +{ #category : 'initialization' } +TinyChat >> start [ + console := TCConsole attach: self. + self sendNewMessage: (TCMessage from: login text: 'I joined the chat room'). + lastMessageIndex := self readLastMessageID. + self refreshMessages +] diff --git a/pharo-mooc/tiny-chat/src/TinyChat-client/package.st b/pharo-mooc/tiny-chat/src/TinyChat-client/package.st new file mode 100644 index 0000000..acbdb12 --- /dev/null +++ b/pharo-mooc/tiny-chat/src/TinyChat-client/package.st @@ -0,0 +1 @@ +Package { #name : 'TinyChat-client' } -- cgit v1.2.3