Skip to content
Sn0wFox edited this page Jan 28, 2016 · 2 revisions
/***************************************************************
 ***************************************************************
 *					  OMNICHAT - Interfaces
 *			
 *	Disclaimer :	This document is NOT part of the OmniChat
 *					sources files. This is just a brainstorming
 *					about how to construct OmniChat and an help
 *					to specifie wich interfaces OmniChat library
 *					provides to users.
 *
 *	This document were created to help developpers to specify
 *	most of the interfaces that OmniChat library will provides
 *	to users. However, somes interfaces will be shown as classes
 *	and some methods will show a small body. This is just in
 *	order to help us to have a bigger understanding of the way
 *	that the library will work.
 *
 * 	Some parts of this documents will probably become a more
 *	official wiki later on. That's why it's written mostly in
 *	english. The french parts are for developpers only.
 *
 ***************************************************************
 ***************************************************************/

 
/***************************************************************
 * Client is the entry point for the library.
 * Maintains the list of available proxies and connected users.
 ***************************************************************/
/***************************************************************
 * Le tableau proxies est en fait un tableau de constructeurs
 * de proxy : un pour chaque classe XXXProxy implementant
 * l'interface de StaticProxy et que le client est capable
 * de gerer.
 * Plus de details sur les proxys dans l'interface en question.
 ***************************************************************/
class Client{
  proxies: StaticProxy[];	// Les proxys disponibles pour ce client
  users: User[];			// Les utilisateurs connectes a ce client

  //	useProxy(p: Proxy);	
  //	Cette methode est commentee : cela signifie que son fonctionnement
  //	n'est pas encore clair, ou qu'elle sera supprimee.

  getProxyFor(protocol: string): StaticProxy{
  //	Retourne le premier constructeur de de proxy dont la classe
  // 	sera compatible avec le protocole de communication protocol.
  //	Protocol sera peut-etre encapsule dans une enum ou une struct
  //	par la suite.
    for(let i=0; i<this.proxies.length; i++){
      if(this.proxies[i].isCompatibleWith(protocol)){
        return this.proxies[i];
      }
    }
  }
}

/***************************************************************
 * Proxies are specific ways to connect to an account.
 * For example, send a message to someone using IRC won't be
 * done than for someone using facebook.
 * This imply that creating a new module (i.e to allow OmniChat
 * to communicate with other accounts) devs must create a new
 * proxy too.
 * In the way we thought about it, a proxy must not be
 * instanciate to do some actions. It just exists.
 * So the implemented classes will probably define these methods
 * as static (impossible to do in an interface).
 ***************************************************************/
/***************************************************************
 * Cette interface est probablement incomplete.
 * A en croire le corps desormais vide de la seconde interface
 * de proxy, Proxy, toutes les methodes des proxys seront
 * statiques. C'est pour cela que le tableau de proxys de Client
 * est un tableau de constructeurs : on pourra appeler les
 * methodes de classe dessus.
 * En revanche, cela ne facilite pas la comprehension du code (et
 * en particulier pour les eventuels devs qui voudront rajouter
 * un module : que se passera-t-il s'ils ne creent pas une classe
 * proxy en declarant les methodes statiques ? Car pour le
 * moment, rien ne les empeche de le faire).
 * Separer les interfaces en deux parties - statique etc
 * d'instance - est toutefois une pratique tres courante.
 ***************************************************************/
interface StaticProxy{
  isCompatibleWith(protocol: string): boolean;
  //	Retourne vrai si le protocole protocol est compatible avec ce proxy.
  //	Protocol sera peut-etre encapsule dans une enum ou une struct
  //	par la suite.
  
  getContacts(account: Account): Contact[];
  //	Accede a la liste des contacts du compte Account,
  //	et les retourne sous forme de tableau de contacts.
  //	
  
  sendMessage(target: Contact, discussion: Discussion);
}
//	interface Proxy{}	//	Cette interface est commentee : cela signifie que son fonctionnement
						//	n'est pas encore clair, ou qu'elle sera supprimee.
						
// Un exemple d'implementation de proxy :
class ProxyIRC implements StaticProxy{
  static isCompatibleWith(protocol: string): boolean{
    return protocol === 'irc';		// Triple egal pour eviter la cast sauvage par le compilo
  };
  
  static getContacts() {
	// Some code here
  }
  
  static sendMessage(target: Contact, discussion: Discussion) {
	// Some code here
  }
}
// A NOTER :	On pourrait implementer uniquement certaines methodes en faisant
//				une implementation implicite : on ne declare pas la classe comme
//				"implements ...", mais on redefinie uniquement les methodes qui nous
//				interessent. Le compilo TypeScript comprendra alors que la classe
//				implemente tout de meme l'interface en question.
//				Ce fonctionnement est toutefois DANGEREUX : que se passe-t-il si
//				on tente d'appeler une methode de maniere polymorphe (par exemple
//				une methode statique sur l'un des constructeurs du tableau proxies
//				de la classe Client, mais que celle-ci n'est pas defini pour la classe
//				en question) ?

// Exemple d'instanciation d'un proxy :
let a:StaticProxy = ProxyIRC;			// Mais est-ce vraiment utile ?

/***************************************************************
 * Contact is the representation of someone you can chat with.
 * A contact may be the same for differents accounts. That's why
 * it contains a list of accounts : those were the contact is
 * identified as the same as in the others.
 ***************************************************************/
/***************************************************************
 * La seule maniere de discuter avec un contact et de commencer
 * une discussion avec lui : creer un objet Discussion.
 * Des participants a la discussion pourront etre ajoutes via
 * l'interface de Discussion. On pourrait eventuellement definir
 * une methode addToDiscussion(d : Discussion); ici.
 * En revanche, le fait de pouvoir creer une discussion ici
 * commence a faire penser au pattern factory. Il serait peut
 * etre interessant de creuser cette branche et d'eventuellement
 * se reposer completement sur ce pattern.
 ***************************************************************/
interface Contact{
  accounts: Account[];	//	La liste des comptes connus de l'utilisateur
						//	pour lesquels ce contact est le meme.
					// A NOTER :	ce sont les comptes du contact qui sont connus
					//				de l'utiliateurs, ou les comptes de l'utilisateur
					//				qui connaissent ce contact sous differents pseudos ?
					
  name: string;			//	Le nom du contact
  _id: any;				//	Un eventuel identifiant

  startDiscussion() : Discussion;
  //	Permet de commencer une discussion avec un contact.
  //	C'est le seul moyen de communiquer avec quelqu'un.
  
  getAccounts(): Account[];
  //	Retourne la liste des comptes connus de l'utilisateur
  //	pour lesquels ce contact est le meme.
}

/***************************************************************
 * User is the representation of someone connected with OmniChat.
 * An user works quite like a Contact : you just have more
 * rights as an user (for example acceed to your own contacts).
 * So User will probably inherit from Contact.
 ***************************************************************/
/***************************************************************
 * Seul point a noter : le fonctionnement recursif de
 * getAccounts(). Voir plus bas.
 * Attention si on venait a faire heriter User the Contact.
 * Cela serait certes pratique, mais bien que les deux classes
 * partageront a priori des attributs communs, leurs
 * significations et utilisations pourront differer.
 ***************************************************************/
interface User{
  getAccounts(): Account[];
  //	Retourne la liste des comptes de l'utilisateurs.
  //	Ce comptes peuvent bien entendu etre de tout type :
  //	IRC, Skype, Facebook... mais aussi OmniChat (recursivite).
  //	Probablement une surcharge de celle de Contact.
  
  getContacts(): Contact[];
  //	Retourne la liste des contacts de l'utilisateur courant.
  //	Fera appel a StaticProxy.getContacts(a: Accounts) pour
  //	chaque compte de lie a l'utiliateur.
}

/***************************************************************
 * Discussion is the only thing you can use to chat with someone.
 * It provides you methods to send a message, do something when
 * you receive a message and so on.
 ***************************************************************/
/***************************************************************
 * Petit probleme concernant le fonctionnement de Discusssion :
 * imaginons Bob et Boby utilisant chacun OmniChat et etant
 * chacun dans la liste des contacts de l'autre. Bob commence
 * une conversation avec Boby. Il possede donc un objet de type
 * Discussion. A quel moment l'objet Discussion de Boby est-il
 * cree ? Est-il partage avec celui de Bob ? Et si Bob etait sur
 * Facebook ?
 * Deuxieme petit probleme avec le fonctionnement de Discussion:
 * reprenons Bob et Boby tout deux sur Omnichat, avec le probleme
 * de la conversation regle en la partageant. La methode
 * onMessage(lambda) devient commune, et Boby ne peut plus faire
 * ce qu'il veut des messages de Bob, il doit faire comme Bob.
 * Reste donc a regler la question de comment une discussion est
 * creee depuis l'exterieur d'OmniChat, lorsque Bob n'a pas
 * l'initiative d'une Discussion avec un vilain utilisateur qui
 * n'utilise pas OmniChat.
 * Troisieme petit probleme avec le fonctionnement de Discussion:
 * lorsqu'on envoie un message aux membres de la discussion,
 * comment choisir le compte du contact sur lequel envoyer le
 * message ? Il ne faut pas spammer tout les comptes... Une
 * reponse se trouve peut-etre dans la description de
 * addParticipants(...).
 ***************************************************************/
interface Discussion{
  creationDate: Date;	// Date de creation de la conversatio
  name: String;			// Nom de la conversation
  
  getMessages(): Message[];
  //	Retourne une liste des messages echanges pendant la discussion.
  //	Equivalent a un espece de getHistory {dateMax, dateMin, nbMessages}.
  //	Un filtre pourra certainement etre applique par la suite,
  // 	via utilisation de lambdas ou/et de hasmaps.
  
  sendMessage(msg: Message);
  //	Envoie le message à tous les participants de la discussion.
  //	Devra sans doute faire appel a StaticProxy.sendMessage().
  //	Mais un probleme se pose : sur quel compte du contact envoyer
  //	le message ?
  
  addParticipants(p: Contacts[]);
  //	Ajoute des participants a la conversation.
  //	Peut etre n'ajouter qu'un seul compte des contacts,
  //	et transformer la discussion en tant qu'agregation
  //	de comptes et non plus de Contacts.
  
  getParticipants(): Contact[];
  //	Retourne une liste des participants a la conversation.
  
  onMessage(callback: (msg: Message) => any);
  //	Appelle la methode a executer lors de la reception du message.
  //	Le detection d'un message se fera sans doute via un ecouteur
  //	qui ecoutera... quoi ?
  
  getName(): string;
  //	Retourne le nom de la discussion.
  
  getDescription(): string;
  // 	Retourne une description de la discussion.
  //	Reste a definir ce que doit etre cette description.
  
  getSettings(): any;
  //	Retourne tout les paramètres de la discussion, même spécifiques (map).
  //	Bien evidemment, nous ne pourrons pas tout traiter.
  //	Nous essayerons cependant de faire du mieux possible sans pour autant
  //	y passer des heures entieres.
}

/***************************************************************
 * Message is the object exchanged during a Discussion.
 * Examples of classes which can inherit from Message are :
 * TextMessage, ImageMessage, VideoMessage...
 ***************************************************************/
/***************************************************************
 * Un debat avait eu lieu concernant comment traiter les
 * messages. L'utilisation du polymorphisme reste la plus saine,
 * mais risque d'etre insuffisante pour certains cas.
 * L'utilisation de instanceof ou d'un equivalent deviendra
 * peut-etre necessaire. Il faudra definir ces cas.
 ***************************************************************/
interface Message{
  getText(): string;
  //	Retourne une representation du message sous forme de String.
  //	Tout message (texte, image, autre fichier) doit avoir cette
  //	représentation pour toujours avoir quelque chose à afficher
  //	(erreur de chargement, etc).
  
  getCreationDate(): Date;
  //	Retourne la date de creation du message.
  
  getLastUpdateDate(): Date;
  //	Retourne la date de derniere modification du message.
  //	Cela ne vaut bien sur que si les messages sont editables,
  //	ce qui conduira peut-etre a supprimer cette methode
  //	de l'interface globale.
  
  getAuthor(): Contact;
  //	Retourne l'auteur du message.
  
  getContent(): any;
  //	Renvoi un contenu plus pertinent.
  //	Chaque type de message devra implementer elle-meme cette methode.
}

/***************************************************************
 * Account is the representation of a chat account.
 * Examples of classes which can inherit from Account are :
 * IRCAccount, FacebookAccount... and OmniChatAccount.
 ***************************************************************/
/***************************************************************
 * La classe Account reste encore partiellement a definir.
 * Quelle methodes pourront etre appelees sur un compte ?
 ***************************************************************/
class Account{
  protocols: string;	//	Une representation du protocole de communication
						//	utilise par ce compte.
						//	Protocol sera peut-etre encapsule dans une enum ou une struct
						//	par la suite.
  data: any;			//	Les donnees du comptes. A definir
}
Clone this wiki locally