Git Product home page Git Product logo

teletype's Introduction

Atom and all repositories under Atom will be archived on December 15, 2022. Learn more in our official announcement

Teletype for Atom

An Atom package that lets developers share their workspace with team members and collaborate on code in real time.

Learn more at teletype.atom.io.

demo

Installation

Command Line

  1. Install Atom 1.22 or newer

  2. In the terminal, install the package via apm:

    apm install teletype

GUI

  1. Install Atom 1.22 or newer
  2. Launch Atom
  3. Open Settings View using Cmd+, on macOS or Ctrl+, on other platforms
  4. Click the Install tab on the left side
  5. Enter teletype in the search box and press Enter
  6. Click the "Install" button that appears

Hacking

This package is powered by three main components:

  • teletype-crdt: The string-wise sequence CRDT that enables peer-to-peer collaborative editing.
  • teletype-server: The server-side application that facilitates peer discovery.
  • teletype-client: The editor-agnostic library that manages the interaction with other clients.

Dependencies

To run teletype tests locally, you'll first need to have:

  • Atom 1.22 or later
  • Node 7+
  • PostgreSQL 9.x

Running locally

  1. Clone and bootstrap

    git clone https://github.com/atom/teletype.git
    cd teletype
    createdb teletype-test
    apm install
    
  2. Run the tests

    atom --test test
    

teletype's People

Contributors

50wliu avatar captainjohnyappleseed avatar damieng avatar darangi avatar dependabot[bot] avatar donokuda avatar himankpathak avatar icetee avatar jasonrudolph avatar lee-dohm avatar lkashef avatar okbel avatar rafeca avatar simurai avatar smashwilson avatar tvand7093 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

teletype's Issues

[Feedback] I atom real-time'd, and lived to tell about it

So I did some realtime pairing with @hiimbex this week, and was super impressed with the experience and functionality it provided. It's like it opened up a whole new world of possibilities.

I did have some issues/thoughts/feels about it though, and wanted to share them back. I don't know if anything is necessarily a bug, but I at least hope it's valuable to get another first-time user experience data point.

  • I copied the portal id to my clipboard. i opened the join dialog and it was already there. That's... awesome.
    • Would be cool if there was a registered uri handler so I don't have to copy it though
  • I use the vim-mode plugin to get vi keybindings. When the cursor is not in INSERT mode, it is not colored (so you can't tell who is who). Also it changes the cursors for everyone pairing, but that wasn't as big of an issue.
  • For the next feedback, it is related to my experience as a real time session consumer, not the owner/controller.
    • The whole thing where if the "session owner" changes the file, your file changes is problematic when you're mid keystroke. I don't know a better solution, but it was funky.
    • There was some weird things that caused the current scroll position to jump around. I don't know if we ever figured out what was causing it (I'd be looking at like X, @hiimbex was doing something (scrolling? page up/down? editing text? no clue), and my screen would jump down to her position.
  • I really missed have the project/file view to see what other files were available. We were looking for tests to copy, and without seeing the directory structure myself, I was little help.
  • Along with seeing other files, it would be nice to be able to have other files available for me to peruse and copy text/etc.
  • Similar to how it works when you are taking a screencast, it would be interesting if there were other ways to highlight sections of the editor without doing text selection (show click actions, etc). Maybe it was just how we were interacting, but to me, it was just as much paired typing as it was collaboration, education, and exploration. Having additional focus and annotation tools would be interesting. This also seems horribly out of scope, but feedback is feedback.

Anyway, this was super cool, and totally changes the way I can work on documents in a group. Would use again :)

Add option to summarize data / bandwidth usage

@brianmario asked me for an estimate of the amount of data being sent and received as part of a typical collaborative editing session for planning purposes with the data team. I think something like the following could be valuable:

  • Record timestamps and raw byte sizes of all protocol buffers sent and received for a portal participant.
  • Report statistics (even in the console would be fine)
    • Max message size sent/received
    • Max number of messages sent/received in a N second interval
    • Max total payload size sent/received in a N second interval

Something quick and dirty should be good enough here. It would just be good to gather real-world data from our own usage since we can. @brianmario if there are other stats you think would be valuable, please let us know.

/cc @jasonrudolph @as-cii

Identify Portal Participants

For the very first step on the road to authentication and presence [1] [2], we'll enhance the package to identify all participants in the portal.

Behavior

This initial staff-ship will provide the following behavior:

  • As a user, when I attempt to share or join a portal, and the real-time package does not yet have a GitHub OAuth token for me, the package prompts me to obtain a token and paste that token into Atom (#87)
  • As a host, when a guest joins my portal, I see a notification saying, "@<guest-username> has joined your portal" [3] (#87)
  • As a guest, when I join a portal, I see a notification saying, "You're now collaborating with @<host-username>" [3]
  • As a guest, when another guest joins the portal, I see a notification saying, "@<guest-username> has joined the portal" [3]

TODO

This is a partial task list, largely intended to help me keep track of things going on across various repositories ๐Ÿ˜„. We'll know that everything is actually done when the package provides the behavior described above. โ˜๏ธ


[1] Portals roadmap
[2] Buddy list exploration
[3] We'll likely tweak the copy before shipping โœจ

Improve guest UX when there is no active editor for host

Steps to reproduce:

  1. Host opens a file in Atom.
  2. Host shares a portal.
  3. Guest joins the portal, and sees a new tab open with the contents of the file that the host is editing.
  4. Host activates the Git tab to stage some changes. (At this point, the git diff view becomes the active pane item in the host's workspace center.)
  5. Guest sees the portal tab disappear.

Step 5 is a bit jarring for the guest. The guest doesn't know why the tab is gone.

From an implementation perspective, we close the tab because the active pane item in the host's workspace center is not an editor (i.e., on the host, atom.workspace.getActiveTextEditor() returns undefined). Instead of closing the tab for the guest, perhaps we can keep the tab open and provide some indication that the host doesn't have an active text editor right now.

/fyi @nathansobo @as-cii

Define plan for open sourcing package without open sourcing real-time-server module

Currently, the real-time package and the real-time-client module both list the real-time-server module as dev dependency:

It's my understanding that we plan to open source the real-time package and the real-time-client module, but not open source the real-time-server module. I think that plan would require removing the real-time-server module from the development dependencies in the real-time package and the real-time-client module, but many of the tests in real-time and real-time-client are dependent on the real-time-server. Let's figure out how we want to address this issue.

Exception when sharing large file

How to reproduce

  1. Host shares a portal
  2. Guest joins a portal
  3. Host gives focus to a large file (e.g., src/text-editor-component.js in atom/atom)
  4. Guest sees an "Invalid byte length!" error

Atom: 1.20.0-dev-ad7e206a7 x64
Electron: 1.6.9
OS: Mac OS X 10.12.6
Thrown From: real-time package version 6780a08

Stack Trace

Uncaught AssertionError: Failure: Invalid byte length!

At /Users/j/.dotfiles/atom/packages/real-time/node_modules/google-protobuf/google-protobuf.js:105

AssertionError
    at /packages/real-time/node_modules/google-protobuf/google-protobuf.js:105:603)
    at Object.goog.asserts.fail (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:107:89)
    at jspb.BinaryDecoder.readBytes (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:337:276)
    at jspb.BinaryReader.readBytes (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:362:405)
    at proto.NetworkMessage.StarUnicast.deserializeBinaryFromReader (/packages/real-time/node_modules/@atom/real-time-client/lib/real-time_pb.js:3652:54)
    at jspb.BinaryReader.readMessage (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:352:329)
    at Function.proto.NetworkMessage.deserializeBinaryFromReader (/packages/real-time/node_modules/@atom/real-time-client/lib/real-time_pb.js:3000:14)
    at Function.proto.NetworkMessage.deserializeBinary (/packages/real-time/node_modules/@atom/real-time-client/lib/real-time_pb.js:2961:31)
    at StarOverlayNetwork.receive (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:129:43)
    at Function.module.exports.Emitter.simpleDispatch (/Users/j/github/real-time/node_modules/event-kit/lib/emitter.js:25:14)
    at Emitter.module.exports.Emitter.emit (/Users/j/github/real-time/node_modules/event-kit/lib/emitter.js:141:28)
    at PeerPool.didReceiveMessage (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-pool.js:75:18)
    at PeerConnection.finishReceiving (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:136:15)
    at PeerConnection.receive (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:127:14)
    at emitOne (events.js:96:13)
    at Peer.emit (events.js:188:7)
    at addChunk (/packages/real-time/node_modules/readable-stream/lib/_stream_readable.js:284:12)
    at readableAddChunk (/packages/real-time/node_modules/readable-stream/lib/_stream_readable.js:271:11)
    at Peer.Readable.push (/packages/real-time/node_modules/readable-stream/lib/_stream_readable.js:238:10)
    at Peer._onChannelMessage (/packages/real-time/node_modules/simple-peer/index.js:702:8)
    at RTCDataChannel.self._channel.onmessage (/packages/real-time/node_modules/simple-peer/index.js:339:12)

Commands

     -0:14.3.0 core:close (input.hidden-input)
     -0:13.9.0 command-palette:toggle (atom-workspace.workspace.scrollbars-visible-always.theme-one-light-syntax.theme-native-ui)
     -0:13.1.0 core:confirm (input.hidden-input)
     -0:13.1.0 real-time:join-portal (atom-workspace.workspace.scrollbars-visible-always.theme-one-light-syntax.theme-native-ui)
     -0:12.6.0 core:confirm (input.hidden-input)

Non-Core Packages

activate-power-mode 2.1.0 
advanced-open-file 0.16.6 
atom-beautify 0.30.4 
atom-fuzzy-grep 0.16.0 
atom-math 0.0.9 
autocomplete-emojis 2.5.0 
busy-signal 1.4.3 
cautious-octo-broccoli 0.2.1 
dash 1.7.1 
dracula-syntax 2.0.5 
file-icons 2.1.9 
git-pear 1.2.1 
git-time-machine 1.5.9 
indent-guide-improved 1.4.13 
intentions 1.1.5 
jumpy 3.1.3 
language-applescript 0.3.0 
language-gherkin 1.0.4 
language-lua 0.9.11 
language-protobuf 0.7.1 
linter 2.2.0 
linter-jshint 3.1.5 
linter-ui-default 1.6.3 
markdown-scroll-sync 2.1.2 
maximize-panes 0.2.0 
native-ui 0.21.0 
nucleus-dark-ui 0.12.3 
nuclide 0.243.0 
pen-paper-coffee-syntax 0.14.9 
platformio-ide-terminal 2.5.4 
project-folder 1.4.0 
real-time 0.1.0 
revert-buffer 0.5.0 
script 3.15.0 
shell-it 0.2.1 
significant-other 0.3.0 
sort-lines 0.14.0 
standard-formatter 2.8.0 
standardjs-snippets 2.6.0 
Sublime-Style-Column-Selection 1.7.4 
tablr 1.8.3 
toggle-markdown-task 0.6.0 
toggle-quotes 1.0.1 
transform 0.4.0 

Having a list or number of people currently connected

Would be good to have a list of number of people currently connected.
You can also just count the cursors you see to get this number.

For example, Maybe I'm expecting to walk through code or a document with 6 people, Having the number of people connected can give me a sense of knowledge that everyone I'm expecting is here and connected. If that number drops I know someone left.

/cc @simurai This looks related to #22

Uncaught AssertionError: Failure: Type not convertible to Uint8Array.

[Enter steps to reproduce:]

  1. Install atom real-time collaboration 0.1.0

  2. Open a portal to share

  3. Click around and this error pops up

gif:
realtime

The only way to make the error stop is to reload atom

Atom: 1.19.2 x64
Electron: 1.6.9
OS: Mac OS X 10.12.6
Thrown From: real-time package 0.1.0

Stack Trace

Uncaught AssertionError: Failure: Type not convertible to Uint8Array.

At /Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/text-buffer.js:904

AssertionError
    at /packages/real-time/node_modules/google-protobuf/google-protobuf.js:98:603)
    at Object.goog.asserts.fail (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:100:89)
    at Object.jspb.utils.byteSourceToUint8Array (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:247:257)
    at jspb.BinaryWriter.writeBytes (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:285:83)
    at proto.RouterMessage.Notification.serializeBinaryToWriter (/packages/real-time/node_modules/@atom/real-time-client/lib/real-time_pb.js:2301:12)
    at jspb.BinaryWriter.writeMessage (/packages/real-time/node_modules/google-protobuf/google-protobuf.js:285:342)
    at Function.proto.RouterMessage.serializeBinaryToWriter (/packages/real-time/node_modules/@atom/real-time-client/lib/real-time_pb.js:2147:12)
    at proto.RouterMessage.serializeBinary (/packages/real-time/node_modules/@atom/real-time-client/lib/real-time_pb.js:2132:23)
    at Router.notify (/packages/real-time/node_modules/@atom/real-time-client/lib/router.js:30:42)
    at TextEditor.setSelectionRanges (/packages/real-time/node_modules/@atom/real-time-client/lib/text-editor.js:71:17)
    at EditorBinding.relayLocalSelections (/packages/real-time/lib/editor-binding.js:117:23)
    at marker.onDidChange (/packages/real-time/lib/editor-binding.js:36:30)
    at Function.module.exports.Emitter.simpleDispatch (/Applications/Atom.app/Contents/Resources/app/node_modules/event-kit/lib/emitter.js:25:20)
    at Emitter.module.exports.Emitter.emit (/Applications/Atom.app/Contents/Resources/app/node_modules/event-kit/lib/emitter.js:141:34)
    at Marker.module.exports.Marker.emitChangeEvent (/Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/marker.js:424:26)
    at Marker.module.exports.Marker.update (/Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/marker.js:365:18)
    at Marker.module.exports.Marker.setHeadPosition (/Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/marker.js:144:25)
    at DisplayMarker.module.exports.DisplayMarker.setHeadBufferPosition (/Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/display-marker.js:146:38)
    at DisplayMarker.module.exports.DisplayMarker.setHeadScreenPosition (/Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/display-marker.js:154:25)
    at /Applications/Atom.app/Contents/Resources/app/src/cursor.js:60:37
    at Cursor.module.exports.Cursor.changePosition (/Applications/Atom.app/Contents/Resources/app/src/cursor.js:644:13)
    at Cursor.module.exports.Cursor.setScreenPosition (/Applications/Atom.app/Contents/Resources/app/src/cursor.js:58:25)
    at /Applications/Atom.app/Contents/Resources/app/src/text-editor.js:1970:29
    at /Applications/Atom.app/Contents/Resources/app/src/text-editor.js:2180:19
    at TextBuffer.module.exports.TextBuffer.transact (/Applications/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/text-buffer.js:899:24)
    at TextEditor.module.exports.TextEditor.transact (/Applications/Atom.app/Contents/Resources/app/src/text-editor.js:1673:32)
    at TextEditor.module.exports.TextEditor.moveCursors (/Applications/Atom.app/Contents/Resources/app/src/text-editor.js:2174:25)
    at TextEditor.module.exports.TextEditor.setCursorScreenPosition (/Applications/Atom.app/Contents/Resources/app/src/text-editor.js:1969:25)
    at TextEditorComponent.didMouseDownOnContent (/Applications/Atom.app/Contents/Resources/app/src/text-editor-component.js:1776:25)

Commands

     -1:54.1.0 application:reopen-project (input.hidden-input)
     -1:23.9.0 command-palette:toggle (input.hidden-input)
     -1:21.9.0 core:move-down (input.hidden-input)
     -1:21.6.0 core:confirm (input.hidden-input)
     -1:21.6.0 real-time:share-portal (input.hidden-input)

Non-Core Packages

real-time 0.1.0 

Migrate to decentralized eviction policy

Switch from a centralized eviction policy (i.e., script/evictor) to a decentralized one:

  • Clients will send heartbeats to the server, which in turn will broadcasts them to all the other clients participating in a portal.
  • When a client doesn't hear from a particular peer in n seconds it will either:
    • Stop showing the disconnected client's cursors if it is just another guest, or
    • Disconnect itself from the portal if the disconnected client is the host

Review portal status bar UI/UX

@simurai: #15 adds a status bar icon for each portal that the user is participating in:

switching-portals

We'd love to get your feedback on the UI/UX. We welcome any and all feedback, but we're especially interested in your thoughts on:

  • How do you feel about the icon choice?
  • For a guest that has joined multiple portals, how do you feel about the use of color to identify the icon associated with the currently-focused portal?
  • Right now, the user can click the portal icon to copy the portal ID to the clipboard. Soon, we may want to allow the host to use the icon to close a portal, and allow a guest to use the icon to leave a portal. Do you have any thoughts or UX suggestions for using the icon to expose both of these behaviors (i.e., copy portal ID to clipboard and close/leave portal)?

cc @as-cii @nathansobo

Error loading package on Atom 1.19 Beta

Me and @rsese are seeing different issues on different versions of atom.

Atom off master(10a7cb5badc56ac6b5d02476fe330d6e53f1cedd):

Atom: 1.20.0-dev-4b2a26e74 x64
Electron: 1.6.9
OS: Mac OS X 10.12.5
Thrown From: real-time package 0.1.0

Stack Trace

Failed to load the real-time package

At Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".


EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".

    at Function (<anonymous>)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/tachyon/lib/tachyon_pb.js:10:14)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/tachyon/lib/tachyon_pb.js:1849:3)
    at Module.get_Module._compile (/Applications/Atom.app/Contents/Resources/app/src/native-compile-cache.js:106:36)
    at Object.value [as .js] (/Applications/Atom.app/Contents/Resources/app/src/compile-cache.js:239:29)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (Applications/Atom.app/Contents/Resources/app/static/index.js:47:45)
    at require (/Applications/Atom.app/Contents/Resources/app/src/native-compile-cache.js:66:33)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/tachyon/lib/serialization.js:1:212)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/tachyon/lib/serialization.js:157:3)
    at Module.get_Module._compile (/Applications/Atom.app/Contents/Resources/app/src/native-compile-cache.js:106:36)
    at Object.value [as .js] (/Applications/Atom.app/Contents/Resources/app/src/compile-cache.js:239:29)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (Applications/Atom.app/Contents/Resources/app/static/index.js:47:45)
    at require (/Applications/Atom.app/Contents/Resources/app/src/native-compile-cache.js:66:33)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/tachyon/index.js:5:5)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/tachyon/index.js:13:3)
    at Module.get_Module._compile (/Applications/Atom.app/Contents/Resources/app/src/native-compile-cache.js:106:36)
    at Object.value [as .js] (/Applications/Atom.app/Contents/Resources/app/src/compile-cache.js:239:29)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (Applications/Atom.app/Contents/Resources/app/static/index.js:47:45)
    at require (/Applications/Atom.app/Contents/Resources/app/src/native-compile-cache.js:66:33)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/real-time-client/lib/shared-buffer.js:4:5)
    at Object.<anonymous> (/Users/bungdonuts/github/real-time/node_modules/@atom/real-time-client/lib/shared-buffer.js:130:3)

Commands

Non-Core Packages

real-time 0.1.0 

After leaving portal, "reopen closed item" opens empty buffer

Steps to Reproduce

All of the following steps are performed as a portal guest:

  1. Join a portal
  2. Close the tab for the portal (i.e., command-w)
  3. Reopen the last closed item (i.e., shift-command-t)

Actual behavior: Atom opens an empty, untitled, unsaved buffer.

Expected behavior: Instead of opening an empty buffer, we could do nothing at all. (This may or may not be the best choice, but there's already some precedent for this behavior: If you open a new Atom instance that has no open editors, and you tell Atom to reopen the last closed item, Atom does nothing at all.)

Reproduces how often: 100%

Demo

demo

No feedback given when attempting to join a nonexistent portal

How to reproduce

  1. Trigger "Join Portal" command
  2. Enter an invalid portal ID (e.g., the portal ID for a portal that has already been closed) and hit "enter"
  3. Observe that nothing happens

Expected behavior

Show an error message (or some other feedback) to inform the user that the attempt to join the portal was unsuccessful.

Demo

demo

Provide better error message when attempting to join portal with empty portal ID

How to reproduce

  1. Trigger "Join Portal" command
  2. When prompted for a portal ID, hit "enter" without providing a portal ID
  3. Observe error message

Expected behavior

If the user doesn't provide a portal ID, we shouldn't even attempt to join the portal. Instead, we should tell the user that they need to provide a valid portal ID.

Demo

demo

Uncaught Error: Ice connection failed

Using version ffc8473 of the real-time package, the host and guest can experience an "Ice connection failed" exception if the Twilio stun requests take too long.

Screenshot

screenshot

Stacktrace

events.js:160
Error: Ice connection failed.
    at Peer._onIceStateChange (/Users/j/github/real-time/node_modules/simple-peer/index.js:492:19)
    at RTCPeerConnection.Peer.self._pc.oniceconnectionstatechange (/Users/j/github/real-time/node_modules/simple-peer/index.js:91:10)

Demo

Video on Google Drive

To reproduce this issue, I'm using Little Snitch to manually approve each request that Atom is making to the Twilio servers. The delay that's introduced by my manual approval of requests seems to be enough to cause a timeout that leads to the exception seen in Atom.

Excepted Behavior

If we can't complete the ICE connection within the timeout period, I think we should gracefully handle the problem and present a friendly error message to the user (as opposed to encouraging the user to open an issue).


fyi @nathansobo: This is the issue that we observed together yesterday.

Possible dataloss scenario with auto-save

Enable autosave before the following steps

  1. Host has a file with no changes
  2. Other user deletes the entire file
  3. Host closes the file
  4. File is saved without host actually saving it.

This could be the expected behavior but also seeing how the host can't undo the other person's edits, if they choose to delete everything, the host can't do anything about it.

Whitespace package while others are editing during save

Repro steps:

  1. Other user is typing on the last line of the file
  2. Host saves the file
  3. Whitespace adds a new line in the end of the file
  4. Other users cursor moves to the last (new) line and the line they are typing on is split up

Change server URL prior to release and/or ensure client can handle redirects

The real-time package currently accesses the real-time server at
https://atom-tachyon.herokuapp.com. We'll likely want to eventually use a github.com or atom.io URL instead of a Heroku URL. Prior to the public beta release, I think we should do one or both of the following:


[1] โš ๏ธ Choosing the "right" domain could be quite the bikeshedding exercise ๐Ÿ˜ฌ

Ensure package handles expired ICE server credentials

In the real-time package, we create and memoize a single RealTimeClient instance. The RealTimeClient instance creates a PeerPool instance. The PeerPool instance fetches the current ICE server URLs/credentials, and stores them for the life of the PeerPool instance. However, the ICE server URLs/credentials expire within 24 hours [1].

With this context in mind, I wonder what happens if you open an Atom instance, leave it open for more than 24 hours, and then try to share or join a portal. I suspect that any attempt to access the ICE server URLs would fail.

@nathansobo: Does that โ˜๏ธ sound right? If so, I'm guessing that we'll need some way for the RealTimeClient to ensure that it always has fresh (i.e., not-yet-expired) ICE server URLs/credentials.


[1] Twilio API docs: https://www.twilio.com/docs/api/rest/token

Display some sort of progress when joining a portal/session

Currently when joining a portal, if you're on a latent network or are receiving a large buffer from the host it can take a couple of seconds. Sometimes that amount of time can leave me feeling a little bit like "did it work? is something happening?"

My suggestion, which may or may not be the right thing to do is to have some sort of progress indicator during the handshake and/or receiving buffer portion while joining.

In my head I'm imagining something in the place where we show the popups at the top of the window, like where the "Join Portal" UI appears, which says something like: "Receiving host buffer 47%" (and obviously updates in realtime as progress is made).

I'm not married to any of this, especially because I'm not familiar with what the proper UX paradigms would be inside Atom for something like this. Maybe it should be in the status bar at the bottom? Not sure...

Consider using URL instead of portal ID to join portal

Instead of requiring the guests to use the "Join Portal" command and then enter the portal ID, consider providing the host with a URL to the portal, and allow guests to click on that URL to automatically open the portal in Atom.

Note: #22 has the potential to negate the need for portal IDs and URLs entirely.

Uncaught TypeError: item.serialize is not a function

Right click on the tab for Portal: No Active File and select Split Right

split right thing

Uncaught TypeError: item.serialize is not a function
    at TabBarView.module.exports.TabBarView.copyItem (file:///I:/atom_master/atom/out/app/node_modules/tabs/lib/tab-bar-view.coffee:203:56)
    at TabBarView.module.exports.TabBarView.splitTab (file:///I:/atom_master/atom/out/app/node_modules/tabs/lib/tab-bar-view.coffee:199:24)
    at Object.TabBarView.addElementCommands.tabs:split-right (file:///I:/atom_master/atom/out/app/node_modules/tabs/lib/tab-bar-view.coffee:54:31)
    at HTMLUListElement.commandsWithPropagationStopped.(anonymous function) (file:///I:/atom_master/atom/out/app/node_modules/tabs/lib/tab-bar-view.coffee:40:11)
    at CommandRegistry.handleCommandEvent (I:\atom_master\atom\src\command-registry.js:381:30)
    at CommandRegistry.dispatch (I:\atom_master\atom\src\command-registry.js:266:17)
    at AtomEnvironment.module.exports.AtomEnvironment.dispatchContextMenuCommand (file:///I:/atom_master/atom/out/app/src/atom-environment.coffee:1070:15)
    at EventEmitter.outerCallback (file:///I:/atom_master/atom/out/app/src/application-delegate.coffee:230:7)
    at emitThree (events.js:116:13)
    at EventEmitter.emit (events.js:194:7)

Uncaught NetworkError: Failed to execute 'send' on 'RTCDataChannel': Could not send data

I ran into this error via the following steps:

  1. Share a portal
  2. Have other people join the portal
  3. Collaborate for a bit
  4. Close my laptop
  5. Re-open my laptop

Atom: 1.21.0-dev-4cef36e56 x64
Electron: 1.6.9
OS: Mac OS X 10.12.6
Thrown From: real-time package 0.1.0

Stack Trace

Uncaught NetworkError: Failed to execute 'send' on 'RTCDataChannel': Could not send data

At /Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/text-buffer.js:899

Error: Failed to execute 'send' on 'RTCDataChannel': Could not send data
    at PeerConnection.send (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:164:24)
    at PeerPool.send (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-pool.js:59:22)
    at spokes.forEach (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:240:23)
    at Set.forEach (native)
    at StarOverlayNetwork.forwardBroadcast (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:238:17)
    at StarOverlayNetwork.broadcast (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:97:12)
    at Router.notify (/packages/real-time/node_modules/@atom/real-time-client/lib/router.js:29:18)
    at TextEditor.setSelectionRanges (/packages/real-time/node_modules/@atom/real-time-client/lib/text-editor.js:71:17)
    at EditorBinding.relayLocalSelections (/packages/real-time/lib/editor-binding.js:117:23)
    at marker.onDidChange (/packages/real-time/lib/editor-binding.js:36:30)
    at Function.module.exports.Emitter.simpleDispatch (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/event-kit/lib/emitter.js:25:20)
    at Emitter.module.exports.Emitter.emit (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/event-kit/lib/emitter.js:141:34)
    at Marker.module.exports.Marker.emitChangeEvent (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/marker.js:424:26)
    at Marker.module.exports.Marker.update (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/marker.js:365:18)
    at Marker.module.exports.Marker.setHeadPosition (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/marker.js:144:25)
    at DisplayMarker.module.exports.DisplayMarker.setHeadBufferPosition (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/display-marker.js:146:38)
    at DisplayMarker.module.exports.DisplayMarker.setHeadScreenPosition (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/display-marker.js:154:25)
    at /Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/cursor.js:60:37
    at Cursor.module.exports.Cursor.changePosition (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/cursor.js:644:13)
    at Cursor.module.exports.Cursor.setScreenPosition (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/cursor.js:58:25)
    at /Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/text-editor.js:1970:29
    at /Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/text-editor.js:2180:19
    at TextBuffer.module.exports.TextBuffer.transact (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/node_modules/text-buffer/lib/text-buffer.js:894:24)
    at TextEditor.module.exports.TextEditor.transact (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/text-editor.js:1673:32)
    at TextEditor.module.exports.TextEditor.moveCursors (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/text-editor.js:2174:25)
    at TextEditor.module.exports.TextEditor.setCursorScreenPosition (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/text-editor.js:1969:25)
    at TextEditorComponent.didMouseDownOnContent (/Users/j/github/atom/out/Atom.app/Contents/Resources/app/src/text-editor-component.js:1784:25)

Undo/Redo with multiple people

One weird scenario we saw was:

  1. Host has a file with no changes
  2. Host makes a change somewhere
  3. Host undoes the change they made
  4. Other user deletes the entire file
  5. File is not marked as modified for Host <- #54
  6. Host does a redo of the undo
  7. File gets marked as modified but nothing is redone because the line doesn't exist or something

Also, with autosave on, if the other user deletes the entire file and autosave kicks it, the host is unable to undo the changes the guest did. Of course this is malicious from the guest user but it could also occur by accident.

/cc @Ben3eeE @rsese

When a participant is typing, other participants cannot use autocomplete

In the demo below, the user on the left types a few characters and triggers autocomplete. Before that user can select an item in the autocomplete list, the user on the right types a character elsewhere in the buffer, which causes the other user's autocomplete selection list to disappear.

demo

This behavior effectively prevents users from using autocomplete if both users are typing at once.

Given just the usefulness of autocomplete in everyday development, it would be great to allow each user to interact with their own autocomplete selections while other users are typing.

Joining the same portal again while being connected throws error

[Enter steps to reproduce:]

  1. Host shares a portal
  2. You connect to that portal
  3. Join the same portal again.

Expected: given warning that you're already connected to that portal

Actual: see below on error thrown

Atom: 1.22.0-dev-1f25cda7c x64
Electron: 1.6.9
OS: Mac OS X 10.12.6
Thrown From: real-time package 0.1.0

Stack Trace

Uncaught TypeError: this.resolveConnectionPromise is not a function

At /Users/bungdonuts/github/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:203

TypeError: this.resolveConnectionPromise is not a function
    at StarOverlayNetwork.receiveConnectionAck (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:203:10)
    at StarOverlayNetwork.receive (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:167:12)
    at Function.module.exports.Emitter.simpleDispatch (/packages/real-time/node_modules/event-kit/lib/emitter.js:25:14)
    at Emitter.module.exports.Emitter.emit (/packages/real-time/node_modules/event-kit/lib/emitter.js:141:28)
    at PeerPool.didReceiveMessage (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-pool.js:90:18)
    at PeerConnection.finishReceiving (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:205:10)
    at PeerConnection.receive (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:196:14)
    at RTCDataChannel.channel.onmessage (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:109:47)

Commands

     -0:26 real-time:join-portal (input.hidden-input)
     -0:25.5.0 core:confirm (input.hidden-input)
     -0:21.3.0 command-palette:toggle (input.hidden-input)
     -0:19.7.0 core:move-down (input.hidden-input)
     -0:19.4.0 core:confirm (input.hidden-input)
     -0:19.4.0 real-time:leave-portal (input.hidden-input)
     -0:18.8.0 command-palette:toggle (input.hidden-input)
     -0:16.1.0 core:move-down (input.hidden-input)
     -0:13.9.0 core:confirm (input.hidden-input)
     -0:13.9.0 real-time:join-portal (input.hidden-input)
     -0:13.2.0 core:confirm (input.hidden-input)
     -0:12.1.0 command-palette:toggle (input.hidden-input)
     -0:10.7.0 core:move-down (input.hidden-input)
     -0:10.4.0 core:confirm (input.hidden-input)
     -0:10.4.0 real-time:join-portal (input.hidden-input)
     -0:09.3.0 core:confirm (input.hidden-input)

Non-Core Packages

real-time 0.1.0 

Buddy list

This issue continues from #18 (comment) and is for brainstorming how the buddy list could look and work.

No feedback given when joining a closed portal

Steps to Reproduce

  1. Host: In one Atom instance, share a portal and then close the portal. Leave Atom open.
  2. Guest: In another Atom instance, attempt to join the portal created in Step 1.

Expected behavior: Guest should receive some feedback that the portal cannot be joined.

Actual behavior: Guest sees nothing.

Reproduces how often: 100%

Additional Information

If the host closes their Atom instance before the guest attempts to join the portal, the guest will see the following error when attempting to join the portal:

Failed to join portal
Attempting to join portal 6c2935e5-5cda-4f7c-a46b-dd4ca1c63d89 failed with error: Connecting to peer timed out

But, when the host still has their Atom instance open, we instead observe the bug described above.

Demo

demo

Suggestions from bug bash meeting

These are suggestions we found during our bug bash sessions between @Ben3eeE @rsese and @ungb.

  • Highlighting is the same color. Hard to figure out who's highlighting.

  • In a large file it's hard to find where people are editing. Is there a way to Go to cursor or something to find where others are editing.

  • When clicking on the real-time icon in toolbar to copy portal id, after clicking, the tooltip doesn't let the user name that it's copied. Example: when clicking on file copies file name:
    image

image

  • Portal notification should have a button to copy portal id, similar to when seeing a exception to report a bug.
    image

image

Readonly mode

I think it would be useful for presentation if people want to follow what's going on in Atom on their computer, but not allow anyone else to edit. Also, having the ability to give people access to edit would be useful too

Provide command to gather networking diagnostics

To help debug things that may interfere with real-time collaboration, consider providing a command that attempts to diagnose the user's current networking situation. For example:

  • Can Atom contact the Teletype server?
  • Can Atom contact Twilio?
  • Can Atom contact Pusher, and can Pusher contact Atom?
    etc.

Then, display the results in a way that the user can read and also share with us to help us debug any connectivity issues.

Uncaught TypeError: this.resolveConnectionPromise is not a function

  1. Bryant closed the connection
  2. Robert and I disconnected
  3. Bryant Opened a connection
  4. Robert was able to join
  5. I got a notification that it failed to join
  6. I tried to connect again and saw this

image

Atom: 1.22.0-dev-006ebc744 x64
Electron: 1.6.9
OS: Microsoft Windows 10 Pro
Thrown From: real-time package 0.1.0

Stack Trace

Uncaught TypeError: this.resolveConnectionPromise is not a function

At C:\Users\bene\.atom\packages\real-time\node_modules\@atom\real-time-client\lib\star-overlay-network.js:203

TypeError: this.resolveConnectionPromise is not a function
    at StarOverlayNetwork.receiveConnectionAck (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:203:10)
    at StarOverlayNetwork.receive (/packages/real-time/node_modules/@atom/real-time-client/lib/star-overlay-network.js:167:12)
    at Function.module.exports.Emitter.simpleDispatch (/packages/real-time/node_modules/event-kit/lib/emitter.js:25:14)
    at Emitter.module.exports.Emitter.emit (/packages/real-time/node_modules/event-kit/lib/emitter.js:141:28)
    at PeerPool.didReceiveMessage (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-pool.js:90:18)
    at PeerConnection.finishReceiving (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:201:10)
    at PeerConnection.receive (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:192:14)
    at RTCDataChannel.channel.onmessage (/packages/real-time/node_modules/@atom/real-time-client/lib/peer-connection.js:105:47)

Commands

  3x -7:29.3.0 core:move-down (input.hidden-input)
  4x -7:28.4.0 editor:newline (input.hidden-input)
     -5:04.8.0 tabs:split-right (div.title)
     -2:59.4.0 command-palette:toggle (div.package-detail.panels-item)
     -2:58.1.0 core:confirm (input.hidden-input)
     -2:58.1.0 real-time:join-portal (div.package-detail.panels-item)
     -2:57.7.0 core:paste (input.hidden-input)
     -2:56.9.0 core:undo (input.hidden-input)
     -2:53.7.0 core:confirm (input.hidden-input)
     -2:11.3.0 command-palette:toggle (div.package-detail.panels-item)
     -2:10.5.0 core:confirm (input.hidden-input)
     -2:10.5.0 real-time:join-portal (div.package-detail.panels-item)
     -2:05.3.0 command-palette:toggle (div.package-detail.panels-item)
     -2:04.8.0 core:confirm (input.hidden-input)
     -2:04.8.0 real-time:join-portal (div.package-detail.panels-item)
     -2:04.0 core:confirm (input.hidden-input)

Non-Core Packages

advanced-open-file 0.16.6 
atom-beautify 0.30.5 
atom-dark-fusion-syntax 2.2.0 
atom-ide-ui 0.1.11 
atom-material-syntax 1.0.6 
atom-material-ui undefined 
autocomplete-emojis 2.5.0 
busy-signal 1.4.3 
chester-atom-syntax 0.3.0 
chestnut-light-atom-syntax 0.2.1 
color-picker 2.2.5 
editor-stats 0.17.0 
fizzy 0.21.0 
golden-ratio 0.3.0 
hey-pane 1.0.0 
highlight-selected 0.13.1 
honor-altgraph 0.1.0 
intentions 1.1.5 
language-latex 1.1.1 
language-markdown 0.25.1 
latex 0.46.0 
less-than-slash 0.17.0 
linter 2.2.0 
linter-js-standard 4.0.0 
linter-ui-default 1.6.8 
markdown-pdf 1.5.4 
minimap 4.29.6 
minimap-autohider 1.5.3 
minimap-find-and-replace 4.5.2 
minimap-highlight-selected 4.6.1 
nebula-syntax 0.4.4 
nebula-ui 0.6.0 
no-caffeine-syntax 0.18.1 
nucleus-dark-ui 0.12.3 
pastel-jelly-syntax 0.2.0 
php-cs-fixer 4.1.0 
pigments 0.40.2 
platformio-ide-terminal 2.5.5 
preview-inline 1.4.7 
real-time 0.1.0 
remote-edit 1.9.0 
seti-syntax 1.1.3 
seti-ui 1.9.0 
Sublime-Style-Column-Selection 1.7.4 
tab-title 0.3.5 
toggler 0.3.0 
vim-mode-plus 1.3.3 
zentabs 0.8.8 

No-op guest's save operation when host is sharing untitled buffer

As a portal guest, the portal tab is always showing you a remote file. That file doesn't exist on your local filesystem; it only exists on the host's filesystem. For that reason, if the guest executes the save command, we treat it as a no-op.

โ˜๏ธ This works when the host is sharing a pre-existing file. However, if the host shares a new file that has not yet been saved to the host's filesystem, and the guest executes the save operation, we currently show the "save as" dialog.

How to reproduce

  1. Host shares a portal
  2. Guest joins a portal
  3. Host opens a new file (i.e., command-n)
  4. Guest executes the core:save command (e.g., command-s)
  5. Guest sees "save as" dialog

Expected behavior

At step 4, nothing should happen. The core:save operation should be a no-op, just as it would be if the host were sharing a pre-existing file.


โš ๏ธโ— When testing the fix for this issue, ensure that #72 is still resolved (i.e., ensure that our fix for this issue doesn't reintroduce the bug described in #72).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.