lib/app.ex

defmodule CIPHER do
  require Record
  require N2O
  use Application

  # CIPHER.send 1, "mix.exs"
  # CIPHER.down "123412341234"

  def start(_, _) do
      :logger.add_handlers(:n2o)
      app = Supervisor.start_link([], strategy: :one_for_one, name: CIPHER)
      login = :application.get_env(:n2o, :login, "")
      pass = :application.get_env(:n2o, :pass, "")
      :n2o_pi.start(N2O.pi(module: CIPHER, table: :cipher, sup: CIPHER,
             state: {"cipherLink", login, pass, 0}, name: "cipherLink"))
      app
  end

  def send(to, doc)  do
      :gen_server.cast :n2o_pi.pid(:cipher, "cipherLink"), {:send, "cipherLink", to, doc}
  end

  def down(id)  do
      :gen_server.cast :n2o_pi.pid(:cipher, "cipherLink"), {:download, id}
  end

  def proc(:init, pi) do
      {:ok, pi}
  end

  def proc({:send, from, to, doc}, N2O.pi(state: {_, login, pass, cnt}) = pi) do
      CIPHER.UP.start(login, pass, from, to, doc, cnt)
      {:noreply, pi}
  end

  def proc({:download, msg_id}, N2O.pi(state: {_, login, pass, _}) = pi) do
      CIPHER.DOWN.start(login, pass, msg_id)
      {:noreply, pi}
  end

  # helpers

  def error(f, x), do: :logger.error(:io_lib.format('CIPHER ' ++ f, x))
  def warning(f, x), do: :logger.warning(:io_lib.format('CIPHER ' ++ f, x))
  def debug(f, x), do: :logger.debug(:io_lib.format('CIPHER ' ++ f, x))
  def info(f, x), do: :logger.info(:io_lib.format('CIPHER ' ++ f, x))

  # REST/JSON API

  def cancel(doc), do: spawn(fn -> :n2o_pi.stop(:cipher, doc) end)

  def publish(bearer,id,_) do
      url = :application.get_env(:n2o, :cipher_upload, []) ++ id
      headers = [{'Authorization',bearer}]
      {:ok,{status,_headers,body}} = :httpc.request(:put, {url, headers},
                                    [{:timeout,100000}], [{:body_format,:binary}])
      CIPHER.debug 'PUBLISH: ~ts ~p', [id,status]
      body
  end

  def metainfo(bearer,id,doc) do
      author = [firstName: "Максим",
                              surname: "Сохацький",
                              position: "Провідний інженер",
                              department: "Розробки інформаційних систем",
                              organization: "ІНФОТЕХ"]

      body = :jsone.encode([fileName: doc, description: "Бінарний файл", ownNumber: "123/20",
                            comment: "Коментар від архіваріуса", authors: [author], outerId: "123/20"])
      url = :application.get_env(:n2o, :cipher_upload, []) ++ id ++ '/metadata'
      app_json = 'application/json'
      headers = [{'Content-Type',app_json},{'Authorization',bearer}]
      {:ok,{status,_headers,body}} = :httpc.request(:put, {url, headers, app_json, body},
                                    [{:timeout,100000}], [{:body_format,:binary}])
      case status do
         {_,200,_} -> CIPHER.debug 'METAINFO: ~ts ~p', [id,status]
           _ -> res = :jsone.decode body
                msg = :maps.get "message", res
                code = :maps.get "code", res
                CIPHER.error 'METAINFO: id: ~ts, code: ~ts, message: ~ts', [id,code,msg]
      end
      body
  end

  def upload(bearer,doc) do
      case :file.read_file(doc) do
         {:error, reason} -> {[],reason}
         {:ok, file} ->
      file_len = :io_lib.format('~p',[:erlang.size(file)])
      url = :application.get_env(:n2o, :cipher_upload, []) ++ '1'
      octet = 'application/octet-stream'
      headers = [{'Authorization',bearer},{'Content-Type',octet},{'Content-Length', file_len}]
      {:ok,{status,_headers,body}} = :httpc.request(:post, {url, headers, octet, file},
                                      [{:timeout,100000}], [{:body_format,:binary}])
      CIPHER.debug 'UPLOAD: ~p', [status]
      res = :jsone.decode body
      id = :maps.get("id", res, []) |> :erlang.binary_to_list
      {id,res}
      end
  end

  def uploadSignature(bearer,id,doc) do
      case :file.read_file(doc <> ".p7s") do
      {:error, _reason} -> CIPHER.warning 'P7S is not available for ~p ~p.', [id,doc]
      {:ok, file} ->
         url = :application.get_env(:n2o, :cipher_upload, []) ++ id ++ '/signature'
         octet = 'application/octet-stream'
         headers = [{'Authorization',bearer},{'Content-Type',octet}]
         {:ok,{status,_headers,body}} = :httpc.request(:put, {url, headers, octet, file},
                                      [{:timeout,100000}], [{:body_format,:binary}])
         case status do
            {_,200,_} -> CIPHER.debug 'UPLOAD SIGNATURE: ~ts ~p', [id,status]
              _ -> res = :jsone.decode body
                   msg = :maps.get "message", res
                   code = :maps.get "code", res
                   CIPHER.error 'UPLOAD SIGNATURE: id: ~ts, code: ~ts, message: ~ts', [id,code,msg]
         end
         CIPHER.debug 'UPLOAD SIGNATURE: ~p', [status]
         {id,body}
      end
  end

  def download(bearer,id) do
      url = :application.get_env(:n2o, :cipher_upload, []) ++ id ++ '/data'
      headers = [{'Authorization',bearer}]
      {:ok,{status,_headers,body}} = :httpc.request(:get, {url, headers},
                                     [{:timeout,100000}], [{:body_format,:binary}])
      CIPHER.debug 'DOWNLOAD ~ts: ~p', [id,status]
      {status,id,body}
  end

  def downloadSignature(bearer,id) do
      url = :application.get_env(:n2o, :cipher_upload, []) ++ id ++ '/signature'
      headers = [{'Authorization',bearer}]
      {:ok,{status,_headers,body}} = :httpc.request(:get, {url, headers},
                                      [{:timeout,100000}], [{:body_format,:binary}])
      case status do
        {_,200,_} -> CIPHER.debug 'DOWNLOAD SIGNATURE: ~ts ~p', [id,status]
          _ -> res = :jsone.decode body
               msg = :maps.get "message", res
               code = :maps.get "code", res
               CIPHER.error 'DOWNLOAD SIGNATURE: id: ~ts, code: ~ts, message: ~ts', [id,code,msg]
      end
      {status,id,:jsone.decode(body)}
  end

  def auth(login,pass) do
      url = :application.get_env(:n2o, :cipher_auth, [])
      body = :jsone.encode([grant_type: "password", username: login, client_id: "arch-client", password: pass])
      len = :io_lib.format('~p',[:erlang.size(body)])
      app_json = 'application/json'
      headers = [{'Content-Type',app_json},{'Content-Length', len}]
      {:ok,{_status,_headers,body}} = :httpc.request(:post, {url, headers, app_json, body},
                                    [{:timeout,10000}], [{:body_format,:binary}])
      res = :jsone.decode body
      bearer = :maps.get "token_type", res
      CIPHER.debug 'AUTH: ~p', [bearer]
      token = :maps.get "access_token", res
      bearer <> " " <> token |> :erlang.binary_to_list
  end

end