Skip to content

Commit

Permalink
Server discovery_register & discovery_unregister functions added
Browse files Browse the repository at this point in the history
  • Loading branch information
alde103 committed May 7, 2020
1 parent 0087ad6 commit 6d3e079
Show file tree
Hide file tree
Showing 3 changed files with 329 additions and 41 deletions.
124 changes: 99 additions & 25 deletions lib/opc_ua/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule OpcUA.Server do
use OpcUA.Common

alias OpcUA.{NodeId}

@moduledoc """
`OpcUA.Server` is implemented as a `__using__` macro so that you can put it in any module you want
to handle the writes to the OPC Server events. Because it is small GenServer, it [accepts the same options for supervision](https://hexdocs.pm/elixir/GenServer.html#module-how-to-supervise)
Expand Down Expand Up @@ -83,7 +84,7 @@ defmodule OpcUA.Server do
"""

@doc """
@doc """
Required callback that handles node values updates from a Client or Server.
It's first argument will a tuple, in which its first element is the `node_id` of the updated node
Expand All @@ -93,7 +94,6 @@ defmodule OpcUA.Server do
"""
@callback handle_write(key :: any, map) :: map


defmacro __using__(opts) do
quote location: :keep, bind_quoted: [opts: opts] do
use GenServer, Keyword.drop(opts, [])
Expand Down Expand Up @@ -194,7 +194,8 @@ defmodule OpcUA.Server do
@doc """
Add a new namespace.
"""
@spec add_namespace(GenServer.server(), binary()) :: {:ok, integer()} | {:error, binary()} | {:error, :einval}
@spec add_namespace(GenServer.server(), binary()) ::
{:ok, integer()} | {:error, binary()} | {:error, :einval}
def add_namespace(pid, namespace) when is_binary(namespace) do
GenServer.call(pid, {:add_namespace, namespace})
end
Expand All @@ -208,12 +209,12 @@ defmodule OpcUA.Server do
* `:browse_name` -> %QualifiedName{}.
* `:type_definition` -> %NodeID{}.
"""
@spec add_variable_node(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec add_variable_node(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def add_variable_node(pid, args) when is_list(args) do
GenServer.call(pid, {:add_variable_node, args})
end


@doc """
Add a new variable type node to the server.
The following must be filled:
Expand All @@ -223,7 +224,8 @@ defmodule OpcUA.Server do
* `:browse_name` -> %QualifiedName{}.
* `:type_definition` -> %NodeID{}.
"""
@spec add_variable_type_node(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec add_variable_type_node(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def add_variable_type_node(pid, args) when is_list(args) do
GenServer.call(pid, {:add_variable_type_node, args})
end
Expand All @@ -237,7 +239,8 @@ defmodule OpcUA.Server do
* `:browse_name` -> %QualifiedName{}.
* `:type_definition` -> %NodeID{}.
"""
@spec add_object_node(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec add_object_node(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def add_object_node(pid, args) when is_list(args) do
GenServer.call(pid, {:add_object_node, args})
end
Expand All @@ -250,7 +253,8 @@ defmodule OpcUA.Server do
* `:reference_type_node_id` -> %NodeID{}.
* `:browse_name` -> %QualifiedName{}.
"""
@spec add_object_type_node(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec add_object_type_node(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def add_object_type_node(pid, args) when is_list(args) do
GenServer.call(pid, {:add_object_type_node, args})
end
Expand All @@ -276,7 +280,8 @@ defmodule OpcUA.Server do
* `:reference_type_node_id` -> %NodeID{}.
* `:browse_name` -> %QualifiedName{}.
"""
@spec add_reference_type_node(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec add_reference_type_node(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def add_reference_type_node(pid, args) when is_list(args) do
GenServer.call(pid, {:add_reference_type_node, args})
end
Expand All @@ -289,7 +294,8 @@ defmodule OpcUA.Server do
* `:reference_type_node_id` -> %NodeID{}.
* `:browse_name` -> %QualifiedName{}.
"""
@spec add_data_type_node(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec add_data_type_node(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def add_data_type_node(pid, args) when is_list(args) do
GenServer.call(pid, {:add_data_type_node, args})
end
Expand All @@ -316,7 +322,8 @@ defmodule OpcUA.Server do
* `:is_forward` -> boolean().
* `:delete_bidirectional` -> boolean().
"""
@spec delete_reference(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
@spec delete_reference(GenServer.server(), list()) ::
:ok | {:error, binary()} | {:error, :einval}
def delete_reference(pid, args) when is_list(args) do
GenServer.call(pid, {:delete_reference, args})
end
Expand All @@ -340,15 +347,40 @@ defmodule OpcUA.Server do
NOTE: before calling this function, this server should have the default configuration.
LDS Servers only supports the Discovery Services. Cannot be used in combination with any other capability.
The following must be filled:
* `:application_uri` -> %NodeID{}.
The following args must be filled:
* `:application_uri` -> binary().
* `:timeout` -> boolean().
"""
@spec set_lds_config(GenServer.server(), binary(), integer()) :: :ok | {:error, binary()} | {:error, :einval}
def set_lds_config(pid, application_uri, timeout \\ nil) when is_binary(application_uri) and (is_integer(timeout) or is_nil(timeout)) do
@spec set_lds_config(GenServer.server(), binary(), integer()) ::
:ok | {:error, binary()} | {:error, :einval}
def set_lds_config(pid, application_uri, timeout \\ nil)
when is_binary(application_uri) and (is_integer(timeout) or is_nil(timeout)) do
GenServer.call(pid, {:set_lds_config, application_uri, timeout})
end

@doc """
Registers a server in a discovery server.
NOTE: The Server sends the request once started. Use port = 0 to dynamically port allocation.
The following must be filled:
* `:application_uri` -> binary().
* `:server_name` -> binary().
* `:endpoint` -> binary().
* `:timeout` -> boolean().
"""
@spec discovery_register(GenServer.server(), list()) :: :ok | {:error, binary()} | {:error, :einval}
def discovery_register(pid, args) when is_list(args) do
GenServer.call(pid, {:discovery_register, args})
end

@doc """
Unregister the server from the discovery server.
NOTE: Server must be started.
"""
@spec discovery_unregister(GenServer.server()) :: :ok | {:error, binary()} | {:error, :einval}
def discovery_unregister(pid) do
GenServer.call(pid, {:discovery_unregister, nil})
end

@doc false
def test(pid) do
Expand Down Expand Up @@ -423,7 +455,10 @@ defmodule OpcUA.Server do
browse_name = Keyword.fetch!(args, :browse_name) |> to_c()
type_definition = Keyword.fetch!(args, :type_definition) |> to_c()

c_args = {requested_new_node_id, parent_node_id, reference_type_node_id, browse_name, type_definition}
c_args =
{requested_new_node_id, parent_node_id, reference_type_node_id, browse_name,
type_definition}

call_port(state, :add_variable_node, caller_info, c_args)
{:noreply, state}
end
Expand All @@ -435,7 +470,10 @@ defmodule OpcUA.Server do
browse_name = Keyword.fetch!(args, :browse_name) |> to_c()
type_definition = Keyword.fetch!(args, :type_definition) |> to_c()

c_args = {requested_new_node_id, parent_node_id, reference_type_node_id, browse_name, type_definition}
c_args =
{requested_new_node_id, parent_node_id, reference_type_node_id, browse_name,
type_definition}

call_port(state, :add_variable_type_node, caller_info, c_args)
{:noreply, state}
end
Expand All @@ -447,7 +485,10 @@ defmodule OpcUA.Server do
browse_name = Keyword.fetch!(args, :browse_name) |> to_c()
type_definition = Keyword.fetch!(args, :type_definition) |> to_c()

c_args = {requested_new_node_id, parent_node_id, reference_type_node_id, browse_name, type_definition}
c_args =
{requested_new_node_id, parent_node_id, reference_type_node_id, browse_name,
type_definition}

call_port(state, :add_object_node, caller_info, c_args)
{:noreply, state}
end
Expand Down Expand Up @@ -529,12 +570,29 @@ defmodule OpcUA.Server do
end

# Discovery Functions.

def handle_call({:set_lds_config, application_uri, timeout}, caller_info, state) do
c_args = {application_uri, timeout}
call_port(state, :set_lds_config, caller_info, c_args)
{:noreply, state}
end

def handle_call({:discovery_register, args}, caller_info, state) do
application_uri = Keyword.fetch!(args, :application_uri)
server_name = Keyword.fetch!(args, :server_name)
endpoint = Keyword.fetch!(args, :endpoint)
timeout = Keyword.get(args, :timeout, nil)

c_args = {application_uri, server_name, endpoint, timeout}
call_port(state, :discovery_register, caller_info, c_args)
{:noreply, state}
end

def handle_call({:discovery_unregister, nil}, caller_info, state) do
call_port(state, :discovery_unregister, caller_info, nil)
{:noreply, state}
end

# Catch all

def handle_call({:test, nil}, caller_info, state) do
Expand All @@ -543,28 +601,33 @@ defmodule OpcUA.Server do
end

def handle_call(invalid_call, _caller_info, state) do
Logger.error("#{__MODULE__} Invalid call: #{inspect invalid_call}")
Logger.error("#{__MODULE__} Invalid call: #{inspect(invalid_call)}")
{:reply, {:error, :einval}, state}
end

def handle_info({_port, {:exit_status, code}}, state) do
Logger.warn("(#{__MODULE__}) Error code: #{inspect code}.")
Process.sleep(@c_timeout) #retrying delay
Logger.warn("(#{__MODULE__}) Error code: #{inspect(code)}.")
# retrying delay
Process.sleep(@c_timeout)
{:stop, :restart, state}
end

def handle_info({:EXIT, _port, reason}, state) do
Logger.debug("(#{__MODULE__}) Exit reason: #{inspect(reason)}")
Process.sleep(@c_timeout) #retrying delay
# retrying delay
Process.sleep(@c_timeout)
{:stop, :restart, state}
end

def handle_info(msg, state) do
Logger.warn("(#{__MODULE__}) Unhandled message: #{inspect msg}.")
Logger.warn("(#{__MODULE__}) Unhandled message: #{inspect(msg)}.")
{:noreply, state}
end

defp handle_c_response({:write, {ns_index, type, name}, c_value}, %{controlling_process: c_pid} = state) do
defp handle_c_response(
{:write, {ns_index, type, name}, c_value},
%{controlling_process: c_pid} = state
) do
variable_node = NodeId.new(ns_index: ns_index, identifier_type: type, identifier: name)
value = parse_c_value(c_value)
send(c_pid, {variable_node, value})
Expand Down Expand Up @@ -670,9 +733,20 @@ defmodule OpcUA.Server do
state
end

# C Handlers Add & Delete Functions.
# C Handlers "Discovery".

defp handle_c_response({:set_lds_config, caller_metadata, data}, state) do
GenServer.reply(caller_metadata, data)
state
end

defp handle_c_response({:discovery_register, caller_metadata, data}, state) do
GenServer.reply(caller_metadata, data)
state
end

defp handle_c_response({:discovery_unregister, caller_metadata, data}, state) do
GenServer.reply(caller_metadata, data)
state
end
end
Loading

0 comments on commit 6d3e079

Please sign in to comment.