WEB: Implemented terrible routing control.
This commit is contained in:
commit
07d553ab92
4
.formatter.exs
Normal file
4
.formatter.exs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Used by "mix format"
|
||||||
|
[
|
||||||
|
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||||
|
]
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# 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").
|
||||||
|
rl_repo-*.tar
|
||||||
|
|
||||||
|
# Temporary files, for example, from tests.
|
||||||
|
/tmp/
|
36
README.md
Normal file
36
README.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# RlRepo
|
||||||
|
|
||||||
|
## API Usage
|
||||||
|
/<repo_name>/<?sub_repo_name>/<pkg_name>/download
|
||||||
|
|
||||||
|
### Repo management
|
||||||
|
/repo/<action>
|
||||||
|
|
||||||
|
#### Repo Creation
|
||||||
|
/repo/create
|
||||||
|
|
||||||
|
|
||||||
|
#### Repo deletion
|
||||||
|
/repo/delete
|
||||||
|
|
||||||
|
### Sub-repo management
|
||||||
|
/<repo_name>/create
|
||||||
|
/<repo_name>/delete
|
||||||
|
|
||||||
|
|
||||||
|
### Package management
|
||||||
|
/<repo_name>/<action>
|
||||||
|
|
||||||
|
#### Create
|
||||||
|
/<repo_name>/create
|
||||||
|
|
||||||
|
#### Delete
|
||||||
|
/<repo_name>/delete
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Package Info
|
||||||
|
/<repo_name>/<pkg_name>/<action>
|
||||||
|
|
||||||
|
|
||||||
|
|
89
lib/client_handler.ex
Normal file
89
lib/client_handler.ex
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
defmodule RlRepo.ClientHandler do
|
||||||
|
require Logger
|
||||||
|
@moduledoc """
|
||||||
|
"""
|
||||||
|
|
||||||
|
def process_request(client_socket) do
|
||||||
|
Logger.info("Processing client request.")
|
||||||
|
|
||||||
|
client_socket
|
||||||
|
|> read_request
|
||||||
|
|> create_response()
|
||||||
|
|> create_response_header()
|
||||||
|
|> write_response(client_socket)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_request(client_socket) do
|
||||||
|
Logger.info("Reading request.")
|
||||||
|
{:ok, request} = :gen_tcp.recv(client_socket, 0)
|
||||||
|
Logger.info("Request recieved.")
|
||||||
|
request
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_response(request) do
|
||||||
|
Logger.info("Building body.")
|
||||||
|
|
||||||
|
# NOTE: Reliability testing.
|
||||||
|
if String.match?(request, ~r{GET /error}) do
|
||||||
|
raise(request)
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: Handle routing here.
|
||||||
|
a = String.split(request, "\n\r");
|
||||||
|
Logger.info a
|
||||||
|
[get_line | rest] = a
|
||||||
|
|
||||||
|
b = String.split(get_line, " ");
|
||||||
|
[request_type | rest] = b
|
||||||
|
[path | rest] = rest
|
||||||
|
Logger.info "#{request_type} #{path}"
|
||||||
|
|
||||||
|
# Parse path
|
||||||
|
split_path = String.split(path, "/");
|
||||||
|
# Ignore the first slash.
|
||||||
|
[_ | rest ] = split_path
|
||||||
|
|
||||||
|
split_path_length = length(rest)
|
||||||
|
Logger.info split_path_length
|
||||||
|
|
||||||
|
ret = case split_path_length do
|
||||||
|
3 ->
|
||||||
|
RlRepo.Router.parse_3_segment_path(rest)
|
||||||
|
|> RlRepo.Router.route_3(request_type)
|
||||||
|
4 ->
|
||||||
|
RlRepo.Router.parse_4_segment_path(rest)
|
||||||
|
|> RlRepo.Router.route_4(request_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def create_return_code_string(return_code) do
|
||||||
|
case return_code do
|
||||||
|
200 -> "200 OK"
|
||||||
|
404 -> "404 Not Found"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_response_header(body) do
|
||||||
|
{return_code, content_type, body} = body
|
||||||
|
|
||||||
|
"""
|
||||||
|
HTTP/1.1 #{create_return_code_string(return_code)}\r
|
||||||
|
Content-Type: #{content_type}\r
|
||||||
|
Content-Length: #{byte_size(body)}\r
|
||||||
|
\r
|
||||||
|
#{body}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def write_response(response, client_socket) do
|
||||||
|
:ok = :gen_tcp.send(client_socket, response)
|
||||||
|
|
||||||
|
# Logger.info("Response:\n\n#{response}")
|
||||||
|
|
||||||
|
:gen_tcp.close(client_socket)
|
||||||
|
end
|
||||||
|
end
|
8
lib/json.ex
Normal file
8
lib/json.ex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
defmodule RlRepo.Json do
|
||||||
|
require Logger
|
||||||
|
@moduledoc """
|
||||||
|
"""
|
||||||
|
def fmt_json(a) do
|
||||||
|
"{\"pkg_names\": 10}"
|
||||||
|
end
|
||||||
|
end
|
31
lib/rl_repo.ex
Normal file
31
lib/rl_repo.ex
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
defmodule RlRepo do
|
||||||
|
require Logger
|
||||||
|
@moduledoc """
|
||||||
|
"""
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
"""
|
||||||
|
def start(port) do
|
||||||
|
{:ok, listener_socket} = :gen_tcp.listen(port, [:binary, packet: :raw, active: false, reuseaddr: true])
|
||||||
|
|
||||||
|
Logger.info("Listening on port #{port}")
|
||||||
|
|
||||||
|
loop_acceptor(listener_socket)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def loop_acceptor(listener_socket) do
|
||||||
|
Logger.debug "Waiting for connection."
|
||||||
|
|
||||||
|
{:ok, client_socket} = :gen_tcp.accept(listener_socket)
|
||||||
|
|
||||||
|
Logger.info "Client Connected."
|
||||||
|
|
||||||
|
process_pid = spawn(fn -> RlRepo.ClientHandler.process_request(client_socket) end)
|
||||||
|
Logger.info "Handling client connection at PID #{inspect(process_pid)}"
|
||||||
|
Logger.info "Handing over socket control."
|
||||||
|
:ok = :gen_tcp.controlling_process(client_socket, process_pid)
|
||||||
|
|
||||||
|
loop_acceptor(listener_socket)
|
||||||
|
end
|
||||||
|
end
|
23
lib/rl_repo/application.ex
Normal file
23
lib/rl_repo/application.ex
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
defmodule RlRepo.Application do
|
||||||
|
# See https://hexdocs.pm/elixir/Application.html
|
||||||
|
# for more information on OTP Applications
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use Application
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def start(_type, _args) do
|
||||||
|
port = String.to_integer(System.get_env("PORT") || "10002")
|
||||||
|
|
||||||
|
children = [
|
||||||
|
# Starts a worker by calling: RlRepo.Worker.start_link(arg)
|
||||||
|
# {RlRepo.Worker, arg}
|
||||||
|
Supervisor.child_spec({Task, fn -> RlRepo.start(port) end}, restart: :permanent)
|
||||||
|
]
|
||||||
|
|
||||||
|
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||||
|
# for other strategies and supported options
|
||||||
|
opts = [strategy: :one_for_one, name: RlRepo.Supervisor]
|
||||||
|
Supervisor.start_link(children, opts)
|
||||||
|
end
|
||||||
|
end
|
45
lib/routing.ex
Normal file
45
lib/routing.ex
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
defmodule RlRepo.Router do
|
||||||
|
require Logger
|
||||||
|
@moduledoc """
|
||||||
|
|
||||||
|
"""
|
||||||
|
def route_3( path, request_type) do
|
||||||
|
Logger.info "#{request_type}"
|
||||||
|
{repo_name, pkg_name, action} = path
|
||||||
|
|
||||||
|
if action == "info" do
|
||||||
|
Logger.info "fetching json"
|
||||||
|
end
|
||||||
|
|
||||||
|
{200, "application/json", "{\"pkg_name\": \"#{pkg_name}\"}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
def route_4(path, request_type) do
|
||||||
|
Logger.info "#{request_type}"
|
||||||
|
{repo_name, sub_repo_name, pkg_name, action} = path
|
||||||
|
{200, "text/html", "<p>Hi</p>"}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def parse_3_segment_path(path) do
|
||||||
|
[repo_name | rest ] = path
|
||||||
|
[pkg_name | rest] = rest
|
||||||
|
[action | _ ] = rest
|
||||||
|
|
||||||
|
Logger.info "REPO #{repo_name} PKG #{pkg_name} ACTION #{action}"
|
||||||
|
|
||||||
|
{repo_name, pkg_name, action}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def parse_4_segment_path(path) do
|
||||||
|
[repo_name | rest ] = path
|
||||||
|
[sub_repo_name | rest] = rest
|
||||||
|
[pkg_name | rest] = rest
|
||||||
|
[action | _ ] = rest
|
||||||
|
|
||||||
|
Logger.info "REPO #{repo_name} SUB_REPO #{sub_repo_name} PKG #{pkg_name} ACTION #{action}"
|
||||||
|
|
||||||
|
{repo_name, sub_repo_name, pkg_name, action}
|
||||||
|
end
|
||||||
|
end
|
29
mix.exs
Normal file
29
mix.exs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
defmodule RlRepo.MixProject do
|
||||||
|
use Mix.Project
|
||||||
|
|
||||||
|
def project do
|
||||||
|
[
|
||||||
|
app: :rl_repo,
|
||||||
|
version: "0.1.0",
|
||||||
|
elixir: "~> 1.12",
|
||||||
|
start_permanent: Mix.env() == :prod,
|
||||||
|
deps: deps()
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run "mix help compile.app" to learn about applications.
|
||||||
|
def application do
|
||||||
|
[
|
||||||
|
extra_applications: [:logger],
|
||||||
|
mod: {RlRepo.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"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
8
test/rl_repo_test.exs
Normal file
8
test/rl_repo_test.exs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
defmodule RlRepoTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest RlRepo
|
||||||
|
|
||||||
|
test "greets the world" do
|
||||||
|
# assert RlRepo.hello() == :world
|
||||||
|
end
|
||||||
|
end
|
1
test/test_helper.exs
Normal file
1
test/test_helper.exs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ExUnit.start()
|
Loading…
Reference in a new issue