Code Monkey home page Code Monkey logo

syncro's Introduction

Syncro let's you synchronise Ruby classes and state between remote clients.
Syncro also supports offline sync.

You can record changes to a Ruby class, then Syncro will replay them on a remote client,
synchronising state between the two.

Syncro leaves the connection management up to you. You can use any networking library (EventMachine/TCPSockets etc).

Each client is represented by a GUID. Even if your architecture isn't P2P clients, the server is 
considered a "client", and needs a GUID too (even if that's just the string "server").

Syncro is already setup to support ActiveModel compliant classes (such as ActiveRecord/SuperModel).
For example, to synchronise a ActiveRecord class:

class TestSync < ActiveRecord::Base
  include Syncro::Model
end

If you want to use Syncro with non ActiveModel compliant classes, you need to implement the class method "sync_play",
and create Syncro::Scriber::Scribe objects whenever the class changes - checkout Syncro::Scriber::Model and Syncro::Scriber::Observer.

To synchronize a class you need to:
  * Include Syncro::Model on that class
  * Call the following upon connection:
      @client = Syncro::Client.for(:client_uuid1)
      @client.connect(connection_instance)
      @client.sync
  * Call the following when the connection receives data:
      @client.receive_data(data)
  * Call the following when the client disconnects:
      @client.disconnect
      
That's it!

Have a look at the example test client and server.

= More information

To Syncro, everything is a client - even the server. Every client is represented by a unique identifier.
This could be a client ID, or in the case of a server a fixed string.

Each client records changes to its classes. When a class changes, a 'Scribe' is created detailing that change.
Replaying that Scribe on remote clients synchronises class state.

When a client synchronises, it asks the remote client for all Scribes since the last sync. The client then replays
the Scribes, synchronising state. The remote client then does the same. If the clients are connected, and a Scribe
is created, the remote client is immediately notified.

When clients connect for the first time, client objects are created. These record the time synchronisation happened (the last Scribe they processed).

Scribes & Clients can be stored in two ways:
  * Marshaled to disk (see SuperModel::Marshal)
  * In Redis

ActiveRecord support hasn't been added (but could be easily).

You should use Redis on the server for performance reasons.

= Limiting access

By default, all model changes are synced with everyone. This isn't ideal for a lot of use cases - for example if a user had many pages, those pages are specific to the user and shouldn't be synced with anyone else.

To limit access, you need to implement the following methods on the class.

def scribe_clients
 [authed_client_uuid1, authed_client_uuid2]
end

def self.scribe_authorized?(scribe)
  # Check scribe.type and scribe.from_client
  # to work out if the client is authorised to
  # synchronise this scribe.
end

= Quick example

The following is an example of using EM, SuperModel and Syncro.
Any changes to the class "Test" will be reflected across both clients:

  require "syncro"
  require "syncro/marshal"
  require "eventmachine"

  class Test < SuperModel::Base
    include SuperModel::Marshal::Model
    include Syncro::Model
  end

  class MyConnection < EM::Connection
    def connection_complete
      @client = Syncro::Client.for(:server)
      @client.connect(self)
      @client.sync
    end
  
    def receive_data(data)
      puts "Received: #{data}"
      @client.receive_data(data)
    end
  end

  SuperModel::Marshal.path = "dump.db"
  SuperModel::Marshal.load

  at_exit {
    SuperModel::Marshal.dump
  }

  EM.run {
    EM.connect("0.0.0.0", 10000, MyConnection)
  }
  
== Protocol

Syncro uses a very simple JSON protocol. 
Each message is a JSON hash. The only mandatory field is "type".
{"type" => "foo", ...}

Each message is preceded by a short int, representing the message size.
For example, in Ruby:
  data = {:type => "foo", :bar => 1}
  message = [data.length].pack('n') + data

At the moment, there are only two types of message:
  * sync (args: from)
  * add_scribe (args: scribe)
  
Have a look at app.rb for implementation details.

If the messages are split up already, i.e. you don't need the binary length preceding 
the message, you can instead use the method @client.receive_message(json_string_or_hash)
This is particular useful for WebSocket clients.

== Roadmap

* A JavaScript Syncro client for web apps that have offline capabilities, and can use WebSockets to
  sync with the server. WebSockets should be on the iPhone/iPad soon.
* Easier protocol extensions, for things like authenticating clients (which are done by subclassing atm).

syncro's People

Contributors

maccman avatar

Stargazers

 avatar Angus H. avatar Buddhika Laknath avatar  avatar Stig Kleppe-Jørgensen avatar Mattias  avatar Sina Siadat avatar  avatar rookie avatar James Hayton avatar Jay Caines-Gooby avatar Kevin Woods avatar Jerry Tian avatar Julius Francisco avatar Brian Howenstein avatar  avatar Daniel Lamando avatar Petros Amoiridis avatar Lance Pollard avatar  avatar jm avatar Myles Eftos avatar Reuben Thiessen avatar Jon Baer avatar Wil Chung avatar Mark Mansour avatar James Coglan avatar Minofare avatar Nathan Esquenazi avatar Mathias Meyer avatar Alisson Cavalcante Agiani avatar Bill Cromie avatar Josef Pospíšil avatar Tom Beddard avatar Christine Fürst avatar Alexander Sulim avatar Sven Fuchs avatar  avatar Luca G. Soave avatar Timothy Johnson avatar Craig R Webster avatar fannar avatar Tom McKelvey avatar Jaroslaw Zabiello avatar Jeff Lindsay avatar Simon Menke avatar Saimon Moore avatar

Watchers

 avatar James Cloos avatar  avatar

Forkers

iq-scm

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.