Skip to content

Commit

Permalink
PR review
Browse files Browse the repository at this point in the history
  • Loading branch information
hubertp committed Aug 11, 2022
1 parent e1c98e3 commit 0f67a00
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
BufferRegistry.props(
fileManager,
runtimeConnector,
TimingsConfig.default().withAutoSave(60.seconds)
TimingsConfig.default().withAutoSave(6.seconds)
),
"buffer-registry"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,23 @@ import scala.concurrent.duration._

/** TimingsConfig encapsulates information about timings or delays in messages being sent between services.
*
* @param autoSave a request timeout
* @param autoSave if non-empty value, determines the delay when auto-save should be triggered
*/
class TimingsConfig(private[this] var autoSave: Option[FiniteDuration]) {
def this() = {
this(None)
class TimingsConfig(
private[this] val timeout: FiniteDuration,
private[this] var autoSave: Option[FiniteDuration]
) {
def this(timeout: FiniteDuration) = {
this(timeout, None)
}

/** A request timeout.
*
* @return a duration to wait for the request to be handled
*/
def requestTimeout: FiniteDuration = timeout

/** Auto-save delay.
*
* @return if non-empty, determines the delay when auto-save should be triggered after the last edit
Expand All @@ -29,5 +39,5 @@ class TimingsConfig(private[this] var autoSave: Option[FiniteDuration]) {
}

object TimingsConfig {
def default(): TimingsConfig = new TimingsConfig()
def default(): TimingsConfig = new TimingsConfig(10.seconds)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,50 @@ import org.enso.text.buffer.Rope
*
* @param file the file linked to the buffer.
* @param contents the contents of the buffer.
* @param inMemory determines if the buffer is in-memory
* @param version the current version of the buffer contents.
*/
case class Buffer(file: File, contents: Rope, version: ContentVersion)
case class Buffer(
file: File,
contents: Rope,
inMemory: Boolean,
version: ContentVersion
)

object Buffer {

/** Creates a new buffer with a freshly generated version.
*
* @param file the file linked to the buffer.
* @param contents the contents of this buffer.
* @param inMemory determines if the buffer is in-memory
* @param versionCalculator a digest calculator for content based versioning.
* @return a new buffer instance.
*/
def apply(
file: File,
contents: Rope
contents: Rope,
inMemory: Boolean
)(implicit versionCalculator: ContentBasedVersioning): Buffer =
Buffer(file, contents, versionCalculator.evalVersion(contents.toString))
Buffer(
file,
contents,
inMemory,
versionCalculator.evalVersion(contents.toString)
)

/** Creates a new buffer with a freshly generated version.
*
* @param file the file linked to the buffer.
* @param contents the contents of this buffer.
* @param inMemory determines if the buffer is in-memory
* @param versionCalculator a digest calculator for content based versioning.
* @return a new buffer instance.
*/
def apply(
file: File,
contents: String
contents: String,
inMemory: Boolean
)(implicit versionCalculator: ContentBasedVersioning): Buffer =
Buffer(file, Rope(contents))
Buffer(file, Rope(contents), inMemory)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,18 @@ import org.enso.text.{ContentBasedVersioning, ContentVersion}
import org.enso.text.editing._
import org.enso.text.editing.model.TextEdit

import scala.concurrent.duration._
import scala.language.postfixOps

/** An actor enabling multiple users edit collaboratively a file.
*
* @param bufferPath a path to a file
* @param fileManager a file manger actor
* @param runtimeConnector a gateway to the runtime
* @param timeout a request timeout
* @param versionCalculator a content based version calculator
* @param timingsConfig a config with timeout/delay values
*/
class CollaborativeBuffer(
bufferPath: Path,
fileManager: ActorRef,
runtimeConnector: ActorRef,
timeout: FiniteDuration,
timingsConfig: TimingsConfig
)(implicit
versionCalculator: ContentBasedVersioning
Expand All @@ -73,7 +68,7 @@ class CollaborativeBuffer(
path,
client.clientId
)
readFile(client, path, Map.empty)
readFile(client, path)

case OpenBuffer(client, path) =>
context.system.eventStream.publish(BufferOpened(path))
Expand All @@ -82,28 +77,28 @@ class CollaborativeBuffer(
path,
client.clientId
)
openBuffer(client, path, Map.empty)
openBuffer(client, path)
}

private def waitingForFileContent(
rpcSession: JsonSession,
replyTo: ActorRef,
timeoutCancellable: Cancellable,
autoSave: Map[ClientId, Cancellable]
inMemoryBuffer: Boolean
): Receive = {
case ReadTextualFileResult(Right(content)) =>
handleFileContent(rpcSession, replyTo, content, autoSave)
handleFileContent(rpcSession, replyTo, content, inMemoryBuffer, Map.empty)
unstashAll()
timeoutCancellable.cancel()

case ReadTextualFileResult(Left(failure)) =>
replyTo ! OpenFileResponse(Left(failure))
timeoutCancellable.cancel()
stop(autoSave)
stop(Map.empty)

case IOTimeout =>
replyTo ! OpenFileResponse(Left(OperationTimeout))
stop(autoSave)
stop(Map.empty)

case _ => stash()
}
Expand Down Expand Up @@ -241,7 +236,7 @@ class CollaborativeBuffer(
currentAutoSaves.get(clientId).foreach(_.cancel())

val timeoutCancellable = context.system.scheduler
.scheduleOnce(timeout, self, IOTimeout)
.scheduleOnce(timingsConfig.requestTimeout, self, IOTimeout)
context.become(
saving(
buffer,
Expand Down Expand Up @@ -312,11 +307,9 @@ class CollaborativeBuffer(
expressionValue
)
)
val newAutoSave: Map[ClientId, Cancellable] = upsertAutoSaveTimer(
autoSave,
clientId,
modifiedBuffer.version
)
val newAutoSave: Map[ClientId, Cancellable] =
if (buffer.inMemory) autoSave
else upsertAutoSaveTimer(autoSave, clientId, modifiedBuffer.version)
context.become(
collaborativeEditing(modifiedBuffer, clients, lockHolder, newAutoSave)
)
Expand Down Expand Up @@ -406,7 +399,12 @@ class CollaborativeBuffer(
.applyEdits(buffer.contents, edits)
.leftMap(toEditFailure)
.map(rope =>
Buffer(buffer.file, rope, versionCalculator.evalVersion(rope.toString))
Buffer(
buffer.file,
rope,
buffer.inMemory,
versionCalculator.evalVersion(rope.toString)
)
)
}

Expand All @@ -421,37 +419,46 @@ class CollaborativeBuffer(

private def readFile(
rpcSession: JsonSession,
path: Path,
autoSave: Map[ClientId, Cancellable]
path: Path
): Unit = {
fileManager ! FileManagerProtocol.ReadFile(path)
val timeoutCancellable = context.system.scheduler
.scheduleOnce(timeout, self, IOTimeout)
.scheduleOnce(timingsConfig.requestTimeout, self, IOTimeout)
context.become(
waitingForFileContent(rpcSession, sender(), timeoutCancellable, autoSave)
waitingForFileContent(
rpcSession,
sender(),
timeoutCancellable,
inMemoryBuffer = false
)
)
}

private def openBuffer(
rpcSession: JsonSession,
path: Path,
autoSave: Map[ClientId, Cancellable]
path: Path
): Unit = {
fileManager ! FileManagerProtocol.OpenBuffer(path)
val timeoutCancellable = context.system.scheduler
.scheduleOnce(timeout, self, IOTimeout)
.scheduleOnce(timingsConfig.requestTimeout, self, IOTimeout)
context.become(
waitingForFileContent(rpcSession, sender(), timeoutCancellable, autoSave)
waitingForFileContent(
rpcSession,
sender(),
timeoutCancellable,
inMemoryBuffer = true
)
)
}

private def handleFileContent(
rpcSession: JsonSession,
originalSender: ActorRef,
file: TextualFileContent,
inMemoryBuffer: Boolean,
autoSave: Map[ClientId, Cancellable]
): Unit = {
val buffer = Buffer(file.path, file.content)
val buffer = Buffer(file.path, file.content, inMemoryBuffer)
val cap = CapabilityRegistration(CanEdit(bufferPath))
originalSender ! OpenFileResponse(
Right(OpenFileResult(buffer, Some(cap)))
Expand Down Expand Up @@ -602,24 +609,21 @@ object CollaborativeBuffer {
* @param bufferPath a path to a file
* @param fileManager a file manager actor
* @param runtimeConnector a gateway to the runtime
* @param timeout a request timeout
* @param versionCalculator a content based version calculator
* @param timingsConfig a config with timing/delay values
* @param versionCalculator a content based version calculator
* @return a configuration object
*/
def props(
bufferPath: Path,
fileManager: ActorRef,
runtimeConnector: ActorRef,
timeout: FiniteDuration = 10 seconds,
timingsConfig: TimingsConfig
)(implicit versionCalculator: ContentBasedVersioning): Props =
Props(
new CollaborativeBuffer(
bufferPath,
fileManager,
runtimeConnector,
timeout,
timingsConfig
)
)
Expand Down

0 comments on commit 0f67a00

Please sign in to comment.