All predicatesShow sourcechat.pl -- The SWISH collaboration backbone

We have three levels of identity as enumerated below. Note that these form a hierarchy: a particular user may be logged on using multiple browsers which in turn may have multiple SWISH windows opened.

  1. Any open SWISH window has an associated websocket, represented by the identifier returned by hub_add/3.
  2. Any browser, possibly having multiple open SWISH windows, is identified by a session cookie.
  3. The user may be logged in, either based on the cookie or on HTTP authentication.
Source start_chat(+Request)[private]
HTTP handler that establishes a websocket connection where a user gets an avatar and optionally a name.
Source check_flooding(+Session)[private]
See whether the client associated with a session is flooding us and if so, return a resource error.
Source accept_chat(+Session, +Options, +WebSocket)[private]
Source visitor_session(?WSId, ?Session, ?Token)[private]
Source session_user(?Session, ?TmpUser)[private]
Source visitor_data(?TmpUser, ?UserData:dict)[private]
Source subscription(?Session, ?Channel, ?SubChannel)[private]
These predicates represent our notion of visitors.
Arguments:
WSID- is the identifier of the web socket. As we may have to reconnect lost connections, this is may be replaced.
Session- is the session identifier. This is used to connect SWISH actions to WSIDs.
TmpUser- is the ID with which we identify the user for this run. The value is a UUID and thus doesn't reveal the real identity of the user.
UserDict- is a dict that holds information about the real user identity. This can be empty if no information is known about this user.
Source visitor(?WSID) is nondet[private]
True when WSID should be considered an active visitor.
Source inactive(+WSID, +Timeout) is semidet[private]
True if WSID is inactive. This means we lost the connection at least Timeout seconds ago.
Source visitor_session(?WSID, ?Session) is nondet[private]
True if websocket WSID is associated with Session.
Source wsid_visitor(?WSID, ?Visitor)[private]
True when WSID is associated with Visitor
Source existing_visitor(+WSID, +Session, +Token, -TmpUser, -UserData) is semidet[private]
True if we are dealing with an existing visitor for which we lost the connection.
Source create_visitor(+WSID, +Session, ?Token, -TmpUser, -UserData, +Options)[private]
Create a new visitor when a new websocket is established. Options provides information we have about the user:
current_user_info(+Info)
Already logged in user with given information
avatar(Avatar)
Avatar remembered in the browser for this user.
nick_name(NickName)
Nick name remembered in the browser for this user.
Source generate_key(-Key) is det[private]
Generate a random confirmation key
Source destroy_visitor(+WSID)[private]
The web socket WSID has been closed. We should not immediately destroy the temporary user as the browser may soon reconnect due to a page reload or re-establishing the web socket after a temporary network failure. We leave the destruction thereof to the session, but set the session timeout to a fairly short time.
To be done
- We should only inform clients that we have informed about this user.
Source gc_visitors[private]
Reclaim all visitors with whom we have lost the connection and the browser did not reclaim the selection within 5 minutes.
Source create_session_user(+Session, -User, -UserData, +Options)[private]
Associate a user with the session. The user id is a UUID that is not associated with any persistent notion of a user. The destruction is left to the destruction of the session.
Source update_visitor_data(+TmpUser, +Data, +Reason) is det[private]
Update the user data for the visitor TmpUser to Data. This is rather complicates due to all the defaulting rules. Reason is one of:
  • login
  • logout
  • 'set-nick-name'
  • 'profile-edit'
To be done
- Create a more declarative description on where the various attributes must come from.
Source update_avatar_from_email(+Email, +DataIn, -Data)[private]
Update the avatar after a change of the known email. If the avatar comes from the profile, no action is needed. If Email has a gravatar, use that. Else use the know or a new generated avatar.
Source anonymise_user_data(TmpUser, Data)[private]
Create anonymous user profile.
Source set_visitor_data(+TmpUser, +Data, +Reason) is det[private]
Update the user data for the session user TmpUser and forward the changes.
Source inform_visitor_change(+TmpUser, +Reason) is det[private]
Inform browsers showing TmpUser that the visitor data has changed. The first clause deals with forwarding from HTTP requests, where we have the session and the second from websocket requests where we have the WSID.
Source subscribe(+WSID, +Channel) is det[private]
Source sync_gazers(+WSID, +Files:list(atom)) is det[private]
A browser signals it has Files open. This happens when a SWISH instance is created as well as when a SWISH instance changes state, such as closing a tab, adding a tab, bringing a tab to the foreground, etc.
Source add_user_details(+Message, -Enriched) is det[private]
Add additional information to a message. Message must contain a uid field.
Source public_user_data(+UID, -Public:dict) is det[private]
True when Public provides the information we publically share about UID. This is currently the name and avatar.
Source get_visitor_data(-Data:dict, +Options) is det[private]
Optain data for a new visitor. Options include:
identity(+Identity)
Identity information provided by authenticate/2. Always present.
avatar(+URL)
Avatar provided by the user
nick_name(+Name)
Nick name provided by the user.

Data always contains an avatar key and optionally contains a name and email key. If the avatar is generated there is also a key avatar_generated with the value true.

bug
- This may check for avatar validity, which may take long. Possibly we should do this in a thread.
Source reply_avatar(+Request)[private]
HTTP handler for Noble Avatar images. Using create_avatar/2 re-creates avatars from the file name, so we can safely discard the avatar file store.

Not really. A new user gets a new avatar and this is based on whether or not the file exists. Probably we should maintain a db of handed out avatars and their last-use time stamp. How to do that? Current swish stats: 400K avatars, 3.2Gb data.

Source chat_broadcast(+Message) is det
Source chat_broadcast(+Message, +Channel) is det
Send Message to all known SWISH clients. Message is a valid JSON object, i.e., a dict or option list.
Arguments:
Channel- is either an atom or a term Channel/SubChannel, where both Channel and SubChannel are atoms.
Source handle_message(+Message, +Room)[private]
Handle incoming messages
Source json_message(+Message, +WSID) is det[private]
Process a JSON message translated to a dict. The following messages are understood:
  • subscribe channel [subchannel]
  • unsubscribe channel [subchannel] Actively (un)subscribe for specific message channels.
  • unload A SWISH instance is cleanly being unloaded.
  • has-open-files files Executed after initiating the websocket to indicate loaded files.
  • set-nick-name name User set nick name for anonymous identoty
Source forbidden(+Message, +DocID, -Why) is semidet[private]
True if the chat Message about DocID must be forbidden, in which case Why is unified with a string indicating the reason. Currently:
  • Demands the user to be logged on
  • Limits the size of the message and its payloads
To be done
- Call authorized/2 with all proper identity information.
Source block(+User, +Score, -Cummulative, -Count)[private]
Keep a count and cummulative score for a user.
Source chat_add_user_id(+WSID, +Message0, -Message) is det[private]
Decorate a message with the user credentials.
Source chat_about(+DocID, +Message) is det
Distribute a chat message about DocID.
Source chat_relay(+Message) is det[private]
Store and relay a chat message.
Source chat_enrich(+Message0, -Message) is det[private]
Add time and identifier to the chat message.
Source chat_send(+Message)[private]
Relay the chat message Message. If the message has a volatile property it is broadcasted, but not stored.
Source chat_event(+Event) is semidet[private]
Event happened inside SWISH. Currently triggered events:
updated(+File, +From, +To)
File was updated from hash From to hash To.
profile(+ProfileID)
Session was associated with user with profile ProfileID
logout(+ProfileID)
User logged out. If the login was based on HTTP authentication ProfileID equals http.
Source propagate_profile_change(+ProfileID, +Attribute, +Value)[private]
Trap external changes to the profile.
Source broadcast_event(+Event) is semidet[private]
If true, broadcast this event.
Source broadcast_event(+Event, +File, +WSID) is det[private]
Event happened that is related to File in WSID. Broadcast it to subscribed users as a notification. Always succeeds, also if the message cannot be delivered.
To be done
- Extend the structure to allow other browsers to act.
Source event_file(+Event, -File) is semidet[private]
True when Event is associated with File.
Source chat_to_profile(ProfileID, :HTML) is det
Send a HTML notification to users logged in using ProfileID.
Source notifications(+Options)//
The chat element is added to the navbar and managed by web/js/chat.js
Source broadcast_bell(+Options)//
Adds a bell to indicate central chat messages

Re-exported predicates

The following predicates are exported from this file while their implementation is defined in imported modules or non-module files loaded by this module.

Source chat_broadcast(+Message) is det
Source chat_broadcast(+Message, +Channel) is det
Send Message to all known SWISH clients. Message is a valid JSON object, i.e., a dict or option list.
Arguments:
Channel- is either an atom or a term Channel/SubChannel, where both Channel and SubChannel are atoms.