Skip to content

Instantly share code, notes, and snippets.

@yehohanan7
Created May 25, 2014 18:13

Revisions

  1. yehohanan7 created this gist May 25, 2014.
    80 changes: 80 additions & 0 deletions gistfile1.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    #Supervisor
    defmodule Torrentex.TrackerSupervisor do
    use Supervisor.Behaviour

    @udp_port 9998
    @tcp_port 9999

    def start_link do
    :supervisor.start_link(__MODULE__, [])
    end

    def init(_) do
    IO.inspect "starting tracker supervisor..."
    supervise([], strategy: :one_for_one)
    end

    def start_tracker(:tcp, torrent) do
    :supervisor.start_child(__MODULE__, worker(Torrentex.TCPTracker, [@tcp_port, torrent], []))
    end

    def start_tracker(:udp, torrent) do
    IO.inspect "starting udp tracker..."
    IO.inspect worker(Torrentex.UDPTracker, [@udp_port, torrent], [])
    :supervisor.start_child(__MODULE__, worker(Torrentex.UDPTracker, [@udp_port, torrent], []))
    end

    end


    #Gen_Server

    defmodule Torrentex.UDPTracker do
    use GenServer.Behaviour
    alias Torrentex.Url

    @actions %{:connect => 0,
    :announce => 1,
    :scrape => 2,
    :error => 3}

    #External API
    def start_link(port, torrent) do
    :gen_server.start_link(__MODULE__, [port, torrent], [])
    end

    #GenServer Callbacks
    def init([port, torrent]) do
    {:ok, socket} = :gen_udp.open(port, [:binary, {:active, true}])
    {:ok, %{:socket => socket, :torrent => torrent}, 0}
    end


    #Utilities
    defp generate_transaction_id do
    :crypto.rand_bytes(4)
    end

    #Outgoing messages
    defp send_message({socket, torrent}, :announce) do
    [domain, port] = Url.host(torrent[:announce])
    :ok = :gen_udp.send(socket, domain, port, "data")
    end

    defp send_message({socket, torrent}, :connect) do
    [domain, port] = Url.host(torrent[:announce])
    :ok = :gen_udp.send(socket, domain, port, <<4497486125440::64,@actions[:connect]::32, generate_transaction_id::binary>>)
    end

    #initializer
    def handle_info(:timeout, %{:socket => socket, :torrent => torrent} = state) do
    send_message({socket, torrent}, :connect)
    {:noreply, state}
    end

    #Incoming messages from socket
    def handle_info({:udp, _, _ip, _port, packet}, state) do
    {:noreply, state}
    end

    end