• Stars
    star
    1,357
  • Rank 34,618 (Top 0.7 %)
  • Language
    Ruby
  • License
    Other
  • Created about 13 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lamer News -- an HN style social news site written in Ruby/Sinatra/Redis/JQuery

About

Lamer news is an implementation of a Reddit / Hacker News style news web site written using Ruby, Sinatra, Redis and jQuery.

The goal is to have a system that is very simple to understand and modify and that is able to handle a very high load using a small virtual server, ensuring at the same time a very low latency user experience.

This project was created in order to run http://lamernews.com but is free for everybody to use, fork, and have fun with.

We believe it is also a good programming example for Redis as a sole DB of a nontrivial, real world, web application.

Installation

Lamer news is a Ruby/Sinatra/Redis/jQuery application. You need to install Redis and Ruby 1.9.2+ with the following gems:

  • redis 3.0 or greater
  • hiredis
  • sinatra
  • json
  • ruby-hmac
  • net/smtp
  • openssl (not needed but will speedup the authentication if available).

Please note that Redis uses port 6379 by default, so you should either change the port number in the configuration file (which is set to use port 10000), or configure Redis to use a matching port.

How to contribute

I plan to hack on Lamer News in my free time as it is interesting to have a non trivial open source example for Redis that is also an useful application. However contributions are welcomed. Just make sure to:

  • Keep it simple. No complex code, no extreme ruby programming. Ideally non ruby people should understand the code without much efforts.
  • Don't use templates, they suck.
  • If your code slows down significantly the page generation time it will not get merged.
  • Do everything you can to avoid depending on new ruby gems.
  • Open an issue on github before firing your editor to see if there are good chances that your changes will be merged.
  • If you don't want to follow all this rules, forking the code is encouraged! The license is two clause BSD, do with this code what you want. Run your site, turn it into a blog, hack it to the extreme consequences. Have fun :)

Web sites using this code

Data Layout

Users

Every user is represented by the following fields:

A Redis hash named user:<user id> with the following fields:

id -> user ID
username -> The username
password -> Hashed password, PBKDF2(salt|password) note: | means concatenation
ctime -> Registration time (unix time)
karma -> User karma, earned visiting the site and posting good stuff
about -> Some optional info about the user
email -> Optional, used to show gravatars
auth -> authentication token
apisecret -> api POST requests secret code, to prevent CSRF attacks.
flags -> user flags. "a" enables administrative privileges.
karma_incr_time -> last time karma was incremented
pwd_reset -> unix time of the last password reset requested.
replies -> number of unread replies

Additionally for every user there is the following key:

`username.to.id:<lowercase_username>` -> User ID

This is used to lookup users by name.

Frequency of user posting is limited by a key named user:<user_id>:submitted_recently with TTL 15 minutes. If a user attempts to post before that key has expired an error message notifies the user of the amount of time until posting is permitted.

Account creation is rate limited by IP address with a key named limit:create_user:<ip_address> with TTL 15 hours.

Authentication

Users receive an authentication token after a valid pair of username/password is received. This token is in the form of a SHA1-sized hex number. The representation is a simple Redis key in the form:

`auth:<lowercase_token>` -> User ID

News

News are represented as an hash with key name news:<news id>. The hash has the following fields:

id -> News id
title -> News title
url -> News url
user_id => The User ID that posted the news
ctime -> News creation time. Unix time.
score -> News score. See source to check how this is computed.
rank -> News score adjusted by age: RANK = SCORE / AGE^ALPHA
up -> Counter with number of upvotes
down -> Counter with number of downvotes
comments -> number of comments

Note: up, down, comments fields are also available in other ways but we denormalize for speed.

Also recently posted urls have a key named url:<actual full url> with TTL 48 hours and set to the news ID of a recently posted news having this url.

So if another user will try to post a given content again within 48 hours the system will simply redirect it to the previous news.

News is never deleted, but just marked as deleted adding the "del" field with value 1 to the news object. However when the post is rendered into HTML, it is displayed as [deleted news] text.

News votes

Every news has a sorted set with user upvotes and downvotes. The keys are named respectively news.up:<news id> and news.down:<news id>.

In the sorted sets the score is the unix time of the vote creation, the element is the user ID of the voting user.

Posting a news will automatically register an up vote from the user posting the news.

Saved news

The system stores a list of upvoted news for every user using a sorted set named user.saved:<user id>, index by unix time. The value of the sorted set elements is the <news id>.

Submitted news

Like saved news every user has an associated sorted set with news he posted. The key is called user.posted:<user id>. Again the score is the unix time and the element is the news id.

Top and Latest news

news.cron is used to generate the "Latest News" page. It is a sorted set where the score is the Unix time the news was posted, and the value is the news ID.

news.top is used to generate the "Top News" page. It is a sorted set where the score is the "RANK" of the news, and the value is the news ID.

Comments

Comments are represented using a very memory efficient pattern. The system is implemented in the comments.rb file.

In short every thread (that is a collection of comments for a given news) is represented by an hash. Every hash entry represents a single comment:

  • The hash field is the comment ID.
  • The hash value is a JSON representation of the "comment object".

The comment object has many fields, like ctime (creation time), body, user_id, and so forth. In order to render all the comments for a thread we simply do an HGETALL to fetch everything. Then we run the list of returned comments and build a graph of comments, calling a recursive function with this graph as input.

Comments are never deleted, but just marked as deleted adding the "del" field with value 1 to the comment object. However when the thread is rendered into HTML deleted comments without childs are not displayed. Deleted comments with childs are displayed as [deleted comment] text.

Please check comments.rb for details, it is trivial to read.

User comments

All the comments posted by a given user are also taken into a sorted set of comments, keyed by creation time. The key name is: user.comments:<userid>.

In this sorted set the score is the unix time and the value is a string composed in this way: <newsid>-<commentid>. So a unique comment is referenced by the news id and the id of the comment inside the hash of comments for this news. Example of an actual comment pointer: 882-15.

More Repositories

1

disque

Disque is a distributed message broker
C
7,969
star
2

kilo

A text editor in less than 1000 LOC with syntax highlight and search.
C
6,839
star
3

smallchat

A minimal programming example for a chat server
C
6,606
star
4

sds

Simple Dynamic Strings library for C
C
4,649
star
5

linenoise

A small self-contained alternative to readline and libedit
C
3,348
star
6

dump1090

Dump1090 is a simple Mode S decoder for RTLSDR devices
C
2,232
star
7

neural-redis

Neural networks module for Redis
C
2,218
star
8

hping

hping network tool
C
1,327
star
9

smaz

Small strings compression library
C
1,096
star
10

rax

A radix tree implementation in ANSI C
C
1,043
star
11

botlib

C Telegram bot framework
C
754
star
12

load81

SDL based Lua programming environment for kids similar to Codea
C
586
star
13

disque-module

Disque ported as Redis module
C
480
star
14

protoview

Flipper Zero app to display known and unknown signals
C
445
star
15

shapeme

Evolve images using simulated annealing
C
382
star
16

aocla

A small stack based, written to bring Advent of Code 2022 Day 13 puzzle to the extreme consequences
C
371
star
17

retwis

A Twitter-toy clone written in PHP and Redis, used in the early days to introduce Redis data types.
PHP
357
star
18

lua-cmsgpack

A self contained Lua MessagePack C implementation.
C
343
star
19

freakwan

A MicroPython driver for the SX1276 LoRa chip
C++
274
star
20

otree

a simple btree implementation with automatic space reclaiming
C
268
star
21

redis-sampler

Small program to understand the composition of your Redis data set
Ruby
260
star
22

redis-rb-cluster

Redis Cluster Ruby client based on redis-rb
Ruby
246
star
23

stonky

Stock market Telegram bot
C
242
star
24

RESP3

RESP protocol V3 repository. Contains the specification, and other related resource
221
star
25

redlock-rb

Redlock Redis-based distributed locks implementation in Ruby
Ruby
197
star
26

lloogg

LLOOGG realtime web log analyzer
PHP
195
star
27

redis-timeseries

Ruby library for Redis backed time series.
Ruby
195
star
28

redis-tools

Abandoned project "Redis tools". What was relevant is now part of redis-cli & redis-benchmark
C
194
star
29

pngtostl

Turn PNG images into STL 3D models that will "develop" in front of a light source
C
157
star
30

iconping

Icon Ping - visual ping to 4.2.2.2
Objective-C
129
star
31

jsrt

Javascript ray tracing engine
118
star
32

adventofcode2022

A few Advent of Code puzzles (2022 edition) in C
C
102
star
33

redimension

Redis multi-dimensional query library
Ruby
98
star
34

gopher2redis

A Ruby script that translates a directory structure and its files into the Redis keys to be served via Redis Gopher protocol
Ruby
92
star
35

mc-benchmark

Memcache port of Redis benchmark
C
85
star
36

listpack

A serialization format and implementation for backward-traversable lists of strings.
C
79
star
37

visitors

Visitors fast web log analyzer
C
76
star
38

Bigdis

Bigdis - a file-based KV store speaking the Redis protocol
Tcl
76
star
39

book-examples

Redis The Definitive Guide book code examples
Ruby
51
star
40

flipper-asteroids

Asteroids for Flipper Zero
C
50
star
41

Gitan

Gitan is a very basic web interface to create and inspect bare git repositories
Ruby
45
star
42

aspark

ASCII sparklines for the Enterprise
C
41
star
43

Jim

Jim is a small footprint Tcl interpreter, with some changes to the original language but mostly compatible.
40
star
44

nolate

NO LAme TEmplate System for Ruby
Ruby
40
star
45

recidiv

minimal continuous integration framework written in Tcl (used for Redis CI)
Tcl
38
star
46

tclircd

An IRC server I wrote in 2004 for fun, using the Tcl language.
Tcl
37
star
47

partitions

Partitions.tcl is a Tcl program to simulate partitions between physical hosts
Tcl
36
star
48

connect4-montecarlo

Simple connect 4 AI using Monte Carlo method
C
31
star
49

talk32

C program to talk via serial to MicroPython powered ESP32 boards
C
28
star
50

failed-3d-prints-bot

A Telegram bot that detects failed prints and send you an image of your printer
C
22
star
51

iqmeteo

Meteo widget for the Garmin Vivoactive HR powered by Yahoo Weather API
Shell
21
star
52

siphash

A modification of SipHash reference implementation to make it more practical for Redis usage
C
20
star
53

yaku-ns

a DNS server I wrote 10 years ago. Here for historical reasons
C
18
star
54

redisdotphp

Legacy Redis PHP client lib. A best-effort support repository.
18
star
55

strabo

Turns HGT elevation maps into 2D images or 3D models
C
18
star
56

nn-2003

2003 Neural Networks experiments -- when it was not mainstream ;-)
C
17
star
57

zx2040

RP2040 ZX Spectrum emulator
C
15
star
58

crack-checksum

Find checksum (crc8, xor, add) parameters in a set of messages.
C
13
star
59

hiredis

WARNING: hiredis repository moved to http://github.com/redis/hiredis. Just my private fork.
13
star
60

dict-scan-fuzz-tester

Fuzz testing for the SCAN underlying algorithm
C
11
star
61

Siboom

A simple markup system for writing books drafts
Ruby
10
star
62

sbignum

Old code about C library for big numbers plus Tcl bindings
C
9
star
63

codakido

Redirects to Load81 project
8
star
64

redis-cp-rewrite-sim

Redis/Raft snapshotting rewriting simulation
C
8
star
65

cache-mem-tester

Test memory efficiency of Redis / Memcached against values with a given size distribution.
Ruby
7
star
66

rascan

A prototype for a multi processes port scanner I wrote in 1998. Here only to archive it for myself.
C
6
star
67

LLM-FTC-sampling

First token cutoff sampling inference example
Python
6
star
68

micropython-telegram-bot

MicroPython telegram bot library: simple way to put your IoT projects on the cloud
Python
5
star
69

bma423-pure-mp

Pure MicroPython BMA423 accelerometer driver
Python
4
star
70

t-watch-s3-micropython

Minimal MicroPython programming example for the Lilygo T-WATCH S3
Python
4
star
71

simple-language-model

Code for the video on feed-forward language model
Python
4
star
72

gif-pure-tcl

Pure TCL GIF generator
Tcl
4
star
73

bme680-pure-mp

Pure MicroPython Bosch BME680 sensor driver
Python
3
star
74

uc8151_micropython

UC8151 / IL0373 MicroPython e-paper display driver with support for greyscales and fast updates
Python
2
star
75

vl53l0x-nb

Fork of MicroPython driver for vl53l0x TOF sensor to add non-blocking mode.
Python
1
star
76

micropython-ft6x06

Simple driver for FT6x06 capacitive touch sensor in pure Python
Python
1
star