VRでMapみたいのを使いたいとNeosVRのときから思っていました
なので、ElixirとResoniteで簡易的に仕組みを考えました
- httpのGetでやり取りをする
- エンドポイント
- /insert?キー1=値1&キー2=値2&キー3=値3 …
- 返却値: 登録ID
- /get?id=登録ID&key=キー
- 返却値: insertで登録した登録IDとキーの組み合わせの結果
- /delete?id=登録ID
- 返却値:true
- /insert?キー1=値1&キー2=値2&キー3=値3 …
- エンドポイント
- Elixr側でメモリ管理をする
- Elixirを止めるとデータは消えます
- つまりetsを使います
実行イメージ
Resoniteで値取得
ブラウザーで検証例
ブラウザーで出来ることはResoniteでも出来る想定です
通信例
// 追加 マップ(name: ymn, a: 99)
get /insert?name=ymn&a=99
2
// 取得 登録ID: 2 マップのキーはname
get /get?id=2&key=name
ymn
// 取得 登録ID: 2 マップのキーはa
get /get?id=2&key=a
99
// 削除 登録ID: 2
/delete?id=2
true
// 削除されたデータを取得する空白で返ってくる
get /get?id=2&key=nama
[空白]
プログラムを書く
ets(インメモリDB)
lib/web_map/ets_map.ex
defmodule WebMap.EtsMap do
@ets_table :data_store
def init() do
:ets.new(@ets_table, [:set, :public, :named_table])
:ets.insert(@ets_table, {:id, 0})
end
def get_next_id() do
:ets.update_counter(@ets_table, :id, 1)
end
def insert(id, map) do
:ets.insert(@ets_table, {id_from_name(id), map})
end
def insert(map) do
id = get_next_id()
:ets.insert(@ets_table, {id_from_name(id), map})
id
end
def get(id) when is_integer(id) do
:ets.lookup(@ets_table, id_from_name(id))
|> get_map_from_no()
end
defp get_map_from_no([{_, data}]) do
data
end
defp get_map_from_no([]) do
%{}
end
def delte(id) do
:ets.delete(@ets_table, id_from_name(id))
end
defp id_from_name(id) do
"id_#{id}"
end
end
ETSを使ったメモリ管理です
機能は関数名と同じ
参考
コントローラー
Web部分のプログラムです
lib/web_map_web/controllers/map_controller.ex
defmodule WebMapWeb.MapController do
use WebMapWeb, :controller
alias WebMap.EtsMap
def insert(conn, params) do
EtsMap.insert(params)
|> Integer.to_string()
|> plain(conn)
end
def get(conn, %{"id" => id, "key" => key}) do
String.to_integer(id)
|> EtsMap.get()
|> Map.get(key, "")
|> plain(conn)
end
def delete(conn, %{"id" => id}) do
String.to_integer(id)
|> EtsMap.delte()
|> inspect()
|> plain(conn)
end
defp plain(body, conn) do
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, body)
end
end
機能は関数名と同じ
ポイントは defp plain(body, conn) の中で
put_resp_content_type("text/plain")を書いていること
これでhtmlでなくてテキストデータを送信できます
ルーター
lib/web_map_web/router.ex
defmodule WebMapWeb.Router do
use WebMapWeb, :router
# 省略 #
scope "/", WebMapWeb do
pipe_through :browser
get "/", PageController, :home
+ get "/insert", MapController, :insert
+ get "/get", MapController, :get
+ get "/delete", MapController, :delete
end
# 省略 #
end
起動時にETSを初期化
lib/web_map/application.ex
defmodule WebMap.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
+ WebMap.EtsMap.init()
children = [
WebMapWeb.Telemetry,
{DNSCluster, query: Application.get_env(:web_map, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: WebMap.PubSub},
# Start a worker by calling: WebMap.Worker.start_link(arg)
# {WebMap.Worker, arg},
# Start to serve requests, typically the last entry
WebMapWeb.Endpoint
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: WebMap.Supervisor]
Supervisor.start_link(children, opts)
end
# Tell Phoenix to update the endpoint configuration
# whenever the application is updated.
@impl true
def config_change(changed, _new, removed) do
WebMapWeb.Endpoint.config_change(changed, removed)
:ok
end
end
これで実現できました
これを応用すればIoT連携で各ポートのデータをMapに入れたりとか
GetでGPIOを直接いじるとか技術的には可能です
AtomVMに実装できればWifiでダイレクトで操作できれば面白いかも
ソース

