Skip to content

Latest commit

 

History

History
277 lines (212 loc) · 6.11 KB

README.md

File metadata and controls

277 lines (212 loc) · 6.11 KB

Feedx

Build Status Coverage Status

Generic feed adding social features to current applications.



Details

RabbitMQ as event producer. This app consumes, stores, and serves. The goal is to create a plug-n-play social feed for existing applications. May be easy to consume events from other sources.

Design

This is an OTP umbrella application, containing other 3 OTP applications within the apps folder.

/apps/bus
/apps/store
/apps/web

bus

  • Bus contains the RabbitMQ Consumer generic server, which responsibility is to store events into the feed.

store

  • FeedRepo is the main data store for our feed. Can be backed by any ecto's supported databases.
  • SourceRepo contains a connection to other app database, in which user's are stored. We should be able to get user name, id, and profile pic from one table. The store app implements a simple caching using con_cache, so that we don't hit the Source database too much. The caching mecanisms and access to the database can be configured, if we don't setup a TTL, each user will only be looked up once per app restart. (We can avoid apps restart using erlang's code hot swap 🙂)
  • Feed gen_server is the main API for consuming the feed.
  • FeedBuilder gen_server is an API for building up the feed.
  • Users gen_server retrieves and caches users given an id. Mostly accessed by the feed server.
  • Comments gen_server is an API for showing, creating, updating, and deleting comments.
  • Likes gen_server is an API for liking and unliking feed events.

web

  • The web project contains a json API and websockets for consuming and updating the feed. Uses phoenix framework

Usage

An app should post events to RabbitMQ with a given format, in order for this app to consume and process events to build the feed. We can always shutdown AMQP, and feed the Store.FeedBuilder using distributed erlang, the API, or building some other mecanism.

We support 3 kind of events. create, update, delete. In order for us to handle an update or delete correctly, we should have already processed the create. udpate wont work once the event is deleted.

Our generic event looks like this.

{
	"event": {
		"type": "create",
		"tenant": 0,
		"user_id": 0,
		"content": "Main data content",
		"extra": {},
		"date": "ISOz date"
	}
}

This app exposes an API endpoint.

GET @ /api/v1/feed

{
	data: [{
		"id": 1,
		"user": {
			"id": 1,
			"full_name": "Nombre",
			"profile_pic": "profile"
		},
		"type": "post",
		"content": "some content",
		"comments": {
			"total": 10,
			"preview": [{
				"user":...,
				"comment": "hello world!"
			}]
		}
	}]
}

GET @ /api/v1/feed/:tenant_id

{
	data: [{
		"id": 1,
		"user": {
			"id": 1,
			"full_name": "Nombre",
			"profile_pic": "profile"
		},
		"type": "post",
		"content": "some content",
		"comments": {
			"total": 10,
			"preview": [{
				"user":...,
				"comment": "hello world!",
				"id": 1
			}]
		}
	}]
}

GET @ /api/v1/feed/:tenant_id/event/:event_id/comments

{
	data: [{
		"user": ...,
		"comment": "Content",
		"id": 1
	}]
}

POST @ /api/v1/feed/:tenant_id/event/:event_id/comments

{
	content: "Hello world!"
}

DELETE @ /api/v1/feed/:tenant_id/event/:event_id/comments/:comment_id

GET @ /api/v1/feed/:tenant_id/event/:event_id/like

GET @ /api/v1/feed/:tenant_id/event/:event_id/unlike

Websockets

We can also subscibe for updates using phoenix channels.

Websocket @ /ws/v1/feed

Channel Subscriptions

Subscribe for company events @ company:<id>

// new event
{
	"type": "create",
	"data": {},
	"id": 0
}

// update event
{
	"type": "create",
	"data": {},
	"id": 0
}

// delete event
{
	"id": 0
}

Subscribe for event changes @ event:<id>

// new comment
{
	"type": "create_comment",
	"data": {},
	"id": 0
}

// update comment
{
	"type": "update_comment",
	"data": {},
	"id": 0
}

// delete comment
{
	"type": "delete_comment",
	"id": 0
}

// new like state
{
	"type": "update_likes",
	"data": {}
}

// someone is typing
{
	"type": "typing",
	"data": {}
}

setup

Change RabbitMQ config on apps/bus/config/{dev, test, prod}.exs.

config :bus, :rabbitmq, "amqp://guest:guest@127.0.0.1"

Change feed data store settings on apps/store/config/{dev, test, prod}.exs

config :store, Store.FeedRepo,
  adapter: Ecto.Adapters.Postgres,
  username: "postgres",
  password: "postgres",
  database: "store_db_dev",
  hostname: "localhost",
  pool_size: 10

Setup your app's database connection, and the name of the table and columns to pull the users parameters.

config :store, Store.SourceRepo,
  adapter: Ecto.Adapters.Postgres,
  username: "postgres",
  password: "postgres",
  database: "store_db_dev",
  hostname: "localhost",
  pool_size: 10

config :store, :external_db_table_name, "tabla"
config :store, :external_db_full_name, :full_name
config :store, :external_db_user_id, :id
config :store, :external_db_profile_pic, :image_url

Cache mecanism for users and other feed interactions can be customized. TTL is not active by default.

config :store, :user_cache,
  ttl: true,
  touch_on_read: true,
  global_ttl: 20,
  check_interval: 2

config :store, :interactions_cache,
  ttl: false

TODO

  • Better docs
  • More tests
  • Generic authentication and authorization mecanism
  • Explore other ways of retrieving user's data.
  • Explore other ways of storing data. Cassandra, Riak, Mnesia 🤔

Easy deploy using edeliver