Skip to content
Snippets Groups Projects
Commit 22d45735 authored by FERRIEUX Etienne's avatar FERRIEUX Etienne
Browse files

Added simple elixir server

parent a846e744
Branches
No related tags found
No related merge requests found
Showing
with 419 additions and 0 deletions
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
simple_server-*.tar
deps:
mix deps.get
create:
mix ecto.create
mix ecto.migrate
drop:
mix ecto.drop
postgres:
sudo bash -x postgres.sh postgres
install:
make postgres
make deps
make create
run: deps
iex -S mix
# SimpleServer
Simple server simulating answers to some Duniter HTTP requests, testing database manipulations and a beginning of processing distribution.
## Installation
make install
make run
The make install command will try to install postgres and change user "postgres" password to "postgres".
Then it will get dependencies and create the databases.
If you have already completed any of these step, refer to the Makefile. make drop & make create to refresh de db, make run to start the server.
import Config
config :simple_server, Repo,
database: "simple_server_repo",
username: "postgres",
password: "postgres",
hostname: "localhost"
###use mix.ecto commands in cli.
config :simple_server, ecto_repos: [Repo]
defmodule Certification do
use Ecto.Schema
schema "certifications" do
field :uid, :string
field :pubkey, :string
field :from_pubkey, :string
field :written, :boolean
end
end
defmodule Identity do
use Ecto.Schema
schema "identities" do
field :uid, :string
field :pubkey, :string
field :member, :boolean
end
def changeset(id, params \\ %{}) do
id
|> Ecto.Changeset.cast(params, [:uid, :pubkey, :member])
|> Ecto.Changeset.validate_required([:pubkey])
|> Ecto.Changeset.unique_constraint(:pubkey)
|> Ecto.Changeset.unique_constraint(:uid)
end
end
defmodule Identity.ToProcess do
use Ecto.Schema
schema "sandbox_idty" do
field :uid, :string
field :pubkey, :string
field :member, :boolean
end
end
defmodule Repo do
use Ecto.Repo,
otp_app: :simple_server,
adapter: Ecto.Adapters.Postgres
end
defmodule SimpleServer do
@moduledoc """
Documentation for `SimpleServer`.
"""
@doc """
Hello world.
## Examples
iex> SimpleServer.hello()
:world
"""
def hello do
:world
end
end
defmodule SimpleServer.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
use Application
def start(_type, _args) do
children = [
# Starts a worker by calling: SimpleServer.Worker.start_link(arg)
# {SimpleServer.Worker, arg}
Plug.Adapters.Cowboy.child_spec(scheme: :http, plug: SimpleServer.Router, options: [port: 8085]),
Repo,
%{id: Restarter, start: {Restarter, :start, []}},
{DynamicSupervisor, strategy: :one_for_one, name: Identity.DynamicSupervisor,max_restarts: 1000,restart: :transient}
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: SimpleServer.Supervisor]
Supervisor.start_link(children, opts)
#pid = spawn(fn -> start_id_genservers() end)
#{:ok,pid}
end
end
defmodule Constants do
def version, do: "1.0"
def forkWindowSize, do: 10
def sandboxTxSize, do: 200
def sandboxIdSize, do: 5000
def sandboxMemberSize, do: 5000
end
defmodule IDGenserver do
use GenServer
require Logger
import Ecto.Query
@certifs_required 5
def start(id_pubkey) do
case GenServer.start_link(__MODULE__, id_pubkey, name: :"#{id_pubkey}_genserver") do
{:ok, p} ->
{:ok, p}
{:error, {:already_started, p}} ->
{:ok, p}
err -> err
end
end
def init(id_pubkey) do
IO.puts("#{id_pubkey}_genserver")
{:ok, %{id_pubkey: id_pubkey, certifs: []}}
end
def handle_call({:certify, %{"from_pubkey" => from_pubkey}, }, _from ,%{id_pubkey: id_pubkey, certifs: certifs}) do
count = [from_pubkey|certifs] |> Enum.count
if count> @certifs_required do
set_member(id_pubkey)
{:stop,:normal,:ok, %{id_pubkey: id_pubkey, certifs: [from_pubkey | certifs]}}
end
set_member(id_pubkey)
IO.puts(count)
IO.puts(inspect certifs)
{:reply, :ok, %{id_pubkey: id_pubkey, certifs: [from_pubkey | certifs]}}
end
def set_member(pubkey) do
[our_id] = Repo.all(from i in Identity, where: i.pubkey ==^pubkey)
IO.puts(inspect our_id)
changeset = Identity.changeset(our_id,%{member: true})
Repo.update(changeset)
IO.puts("certified!")
end
end
defmodule Restarter do
import Ecto.Query
def start() do
query = from i in "identities",
where: i.member == false,
select: i.pubkey
ids_to_start = query |> Repo.all
for x <- ids_to_start do
IDGenserver.start(x)
end
IO.puts(inspect ids_to_start)
{:ok,self()}
end
end
defmodule SimpleServer.Router do
use Plug.Router
use Plug.Debugger
require Logger
import Ecto.Query
plug(Plug.Logger, log: :debug)
plug(:match)
plug(:dispatch)
# TODO: add routes
get "/node/summary" do
json = Poison.encode!(
%{duniter:
%{software: "duniter",
version: Constants.version,
forkWindowSize: Constants.forkWindowSize
}
}
)
send_resp(conn, 200, json)
end
get "/node/sandboxes" do
#IO.puts(Constants.version)
id_sbx_count = Duniter.Identity.ToProcess |> Repo.all |> Enum.count
json = Poison.encode!(
%{transactions:
%{size: Constants.sandboxTxSize, free: nil} ,
identities:
%{size: Constants.sandboxIdSize, free: Constants.sandboxIdSize - id_sbx_count},
membership:
%{size: Constants.sandboxMemberSize, free: nil}
}
)
send_resp(conn, 200, json)
end
# Basic example to handle POST requests wiht a JSON body
post "/wot/add" do
{:ok, body, conn} = read_body(conn)
body = Poison.decode!(body)
id = %Identity{uid: body["uid"], pubkey: body["pubkey"], member: body["member"]}
Repo.insert(id)
{:ok,child} = DynamicSupervisor.start_child(Identity.DynamicSupervisor, %{id: body["pubkey"], start: {IDGenserver, :start, [body["pubkey"]]}})
#Duniter.Identity |> Duniter.Repo.all
send_resp(conn, 201, "created: #{inspect id}")
end
post "wot/certify" do
{:ok, body, conn} = read_body(conn)
body = Poison.decode!(body)
our_id = Repo.all(from i in Identity, where: i.pubkey == ^body["pubkey"], select: i.member)
case our_id do
[] -> send_resp(conn, 301, "error: ID does not exist")
[true] -> send_resp(conn, 301, "error: ID is already a member")
_ ->
cert = %Certification{uid: body["uid"], pubkey: body["pubkey"], from_pubkey: body["from_pubkey"], written: body["written"]}
Repo.insert(cert)
{:ok, pid} = IDGenserver.start(body["pubkey"])
GenServer.call(pid, {:certify, %{"from_pubkey" => body["from_pubkey"]}}, 20_000)
send_resp(conn, 201, "created: #{inspect cert}")
end
end
# "Default" route that will get called when no other route is matched
match _ do
send_resp(conn, 404, "not found")
end
end
defmodule SimpleServer.MixProject do
use Mix.Project
def project do
[
app: :simple_server,
version: "0.1.0",
elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger,:cowboy, :plug, :poison],
mod: {SimpleServer.Application, []}
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
{:cowboy, "~> 1.0.0"},
{:plug, "~> 1.5"},
{:poison, "~> 3.1"},
{:plug_cowboy, "~> 1.0"},
{:ecto_sql, "~> 3.2"},
{:postgrex, "~> 0.15"}
]
end
end
%{
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
"cowboy": {:hex, :cowboy, "1.0.4", "a324a8df9f2316c833a470d918aaf73ae894278b8aa6226ce7a9bf699388f878", [:make, :rebar], [{:cowlib, "~> 1.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "6a0edee96885fae3a8dd0ac1f333538a42e807db638a9453064ccfdaa6b9fdac"},
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm", "db622da03aa039e6366ab953e31186cc8190d32905e33788a1acb22744e6abd2"},
"db_connection": {:hex, :db_connection, "2.3.0", "d56ef906956a37959bcb385704fc04035f4f43c0f560dd23e00740daf8028c49", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "dcc082b8f723de9a630451b49fdbd7a59b065c4b38176fb147aaf773574d4520"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"ecto": {:hex, :ecto, "3.5.4", "73ee115deb10769c73fd2d27e19e36bc4af7c56711ad063616a86aec44f80f6f", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7f13f9c9c071bd2ca04652373ff3edd1d686364de573255096872a4abc471807"},
"ecto_sql": {:hex, :ecto_sql, "3.5.3", "1964df0305538364b97cc4661a2bd2b6c89d803e66e5655e4e55ff1571943efd", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.5.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2f53592432ce17d3978feb8f43e8dc0705e288b0890caf06d449785f018061c"},
"mime": {:hex, :mime, "1.4.0", "5066f14944b470286146047d2f73518cf5cca82f8e4815cf35d196b58cf07c47", [:mix], [], "hexpm", "75fa42c4228ea9a23f70f123c74ba7cece6a03b1fd474fe13f6a7a85c6ea4ff6"},
"plug": {:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"},
"plug_cowboy": {:hex, :plug_cowboy, "1.0.0", "2e2a7d3409746d335f451218b8bb0858301c3de6d668c3052716c909936eb57a", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "01d201427a8a1f4483be2465a98b45f5e82263327507fe93404a61c51eb9e9a8"},
"plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
"postgrex": {:hex, :postgrex, "0.15.7", "724410acd48abac529d0faa6c2a379fb8ae2088e31247687b16cacc0e0883372", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "88310c010ff047cecd73d5ceca1d99205e4b1ab1b9abfdab7e00f5c9d20ef8f9"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
}
#!/bin/bash
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
function print_info {
echo -n -e '\e[1;36m'
echo -n $1
echo -e '\e[0m'
}
function print_warn {
echo -n -e '\e[1;33m'
echo -n $1
echo -e '\e[0m'
}
function check_install {
if [ -z "`which "$1" 2>/dev/null`" ]
then
executable=$1
shift
while [ -n "$1" ]
do
DEBIAN_FRONTEND=noninteractive apt-get -q -y install "$1"
print_info "$1 installed for $executable"
shift
done
else
print_warn "$2 already installed"
fi
}
check_install postgresql postgresql
sudo service postgresql start
sudo -u postgres psql -c"ALTER user postgres WITH PASSWORD '$1'"
sudo service postgresql restart
\ No newline at end of file
defmodule Duniter.Repo.Migrations.CreateIds do
use Ecto.Migration
def change do
create table(:identities) do
add :uid, :string
add :pubkey, :string
add :member, :boolean
end
end
end
defmodule Duniter.Repo.Migrations.CreateSandboxIdView do
use Ecto.Migration
def change do
execute("""
CREATE VIEW sandbox_idty AS SELECT * FROM identities WHERE identities.member = false;
""")
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment