james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Benoit Tellier (Jira)" <server-...@james.apache.org>
Subject [jira] [Created] (JAMES-3581) As a JMAP extension writer, I want to PUSH state changes for my extensions
Date Tue, 11 May 2021 03:16:00 GMT
Benoit Tellier created JAMES-3581:

             Summary: As a JMAP extension writer, I want to PUSH state changes for my extensions
                 Key: JAMES-3581
                 URL: https://issues.apache.org/jira/browse/JAMES-3581
             Project: James Server
          Issue Type: Improvement
          Components: JMAP
    Affects Versions: 3.6.0
            Reporter: Benoit Tellier
            Assignee: Antoine Duprat
             Fix For: 3.7.0

# Why?

JMAP specifications defines the minimal features to get a basic email reading/writing experience.

However, as part of our job at Linagora, writing a collaborative email suite, we need advanced
collaborative features that uses custom, off-spec, JMAP extensions.

We thus want to implement these collaborative features as JMAP extensions (because JMAP is
so much of a nice protocol!).

We were able to:

 - Write custom methods pretty much directly.

 - We needed to contribute modular definition of session "capabilities" to be advertising
our custom ones.

But we are missing the push for custom extensions.

# What?

As an extension developper I want to be able to register my type states and have states matching
my format:

object IntState {
  def parse(string: String): Either[IllegalArgumentException, IntState] = Try(Integer.parseInt(string))
    .left.map(new IllegalArgumentException(_))

case class IntState(i: Int) extends State {
  override def serialize: String = i.toString

case object CustomTypeName extends TypeName {
  override val asString: String = "MyTypeName"

  override def parse(string: String): Option[TypeName] = string match {
    case CustomTypeName.asString => Some(CustomTypeName)
    case _ => None

  override def parseState(string: String): Either[IllegalArgumentException, IntState] = IntState.parse(string)

Given this, I want to be injecting my extensions to the push in the guice module definition:

    Multibinder.newSetBinder(binder(), classOf[TypeName])
    Multibinder.newSetBinder(binder(), classOf[GuiceProbe])

Doing so should allow me to emit 'custon' state change push notifications:

    val stateChangeEvent: StateChangeEvent = StateChangeEvent(eventId = CustomMethodContract.eventId,
username = BOB, map = Map(CustomTypeName -> intState))
    SMono(jmapEventBus.dispatch(stateChangeEvent, AccountIdRegistrationKey(accountId))).block()

Which allows generating state change events PUSH notifications carried over via webSocket
or SSE for your extensions :-)

# How?

Modularize the definition of State (extensions might not want to have it backed by a UUID),
allow creating custom type states (parse them, and from them be able to parse the associated
state). We also need to transport these additional type states as part of our event system.

# Definition of done

Write an integration test where you emit a custom type state with an exotic state implementation
(meaning not backed by a UUID) and have the StateChange event carried over to the client,
for instance using WebSocket.

# Proof of concept

Quan had been putting this PR together: https://github.com/apache/james-project/pull/391

This message was sent by Atlassian Jira

To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org

View raw message