| Предыдущая версия справа и слева
Предыдущая версия
Следующая версия
|
Предыдущая версия
|
lm3:ce:t_multi_lang [2020/11/27 13:33] ruben |
lm3:ce:t_multi_lang [2020/11/30 15:06] (текущий) ruben |
| Такой подход удобен, и данные легко обновлять. | Такой подход удобен, и данные легко обновлять. |
| |
| Пример реализации | ==== Пример реализации ==== |
| |
| Платформа Лямбда-Мю 3 может использоваться как back end сервер веб-проекта. Одним из таких проектов является «Сомнология B2C» – мобильное приложение на Android. | Платформа Лямбда-Мю 3 может использоваться как back end сервер веб-проекта. Одним из таких проектов является «Сомнология B2C» – мобильное приложение на Android. |
| ==== Репозитарий ==== | ==== Репозитарий ==== |
| |
| [[https://gitlab.com/lm3.examples/lm3.multi_lang_example|lm3.multi_lang_example]] | Файловая структура проекта представлена ниже. |
| | |
| | Необходимые скрипты туториала находятся в репозитарии [[https://gitlab.com/lambda-mu/lm.ver3/lm3.examples/multi_lang|lm3.examples/multi_lang]]. |
| | |
| | Чтобы запустить платформу скачайте бинарный файл и необходимые библиотеки из репозитария [[https://gitlab.com/lambda-mu/lm.ver3/lm3.engine.ce|lm3.engine.ce]] и скопируйте в корень проекта. |
| |
| ==== Исходные данные ==== | ==== Исходные данные ==== |
| |
| Требованием к проекту является минимальные изменения исходного проекта [client] и [server]. Требование достигается использованием того же протокола, который разработан в исходном проекте. | Требованием к проекту является минимальные изменения исходного проекта [client] и [server]. Требование достигается использованием того же протокола, который разработан в исходном проекте. |
| | |
| | **Авторизация:** |
| | |
| | Запрос: |
| | |
| | <code lua> |
| | { |
| | { Object = "Auth", Command = "Set", Name = "UserName", Data = <string> }, |
| | { Object = "Auth", Command = "Set", Name = "UserMail", Data = <string> }, |
| | { Object = "Settings", Command = "Event", Name = "DoChangeLang", Data = <string> }, |
| | } |
| | |
| | </code> |
| | |
| | Ответ: |
| | |
| | <code lua> |
| | { { Object = "Auth", Command = "Value", Name = "TaskObject", Data = <string> } } |
| | |
| | </code> |
| | |
| | **Запрос списка курсов:** |
| | |
| | Запрос: |
| | |
| | <code lua> |
| | { { Object = "Info", Command = "Event", Name = "CourceList" } } |
| | |
| | </code> |
| | |
| | Ответ: |
| | |
| | <code lua> |
| | { { Object = "Info", Command = "Value", Name = "CourceList", Data = <array[table[CourceID:string, Name:string, Description:string]]> } } |
| | |
| | </code> |
| | |
| | **Смена локализации:** |
| | |
| | Запрос: |
| | |
| | <code lua> |
| | { { Object = "Auth", Command = "Value", Name = "TaskObject", Data = <string> } } |
| | |
| | </code> |
| | |
| | ==== Файловая структура проекта ==== |
| | |
| | {{ :lm3:ce:multi_lang_files.png.png?direct& }} |
| | |
| | ==== Взаимосвязи ==== |
| | |
| | Объекты основной логической машины: |
| | * TCP-server server: прием и передача данных клиенту |
| | * DataPack packer: распаковка и запаковка данных клиенту |
| | * Auth: авторизация клиента; вызов создания ЛМ; связь клиента с соответвующей ЛМ |
| | * Сlients (наследник LMList): управление ЛМ |
| | |
| | {{ :lm3:ce:multi_lang_main.png?direct& }} |
| | |
| | Объекты логических машин: |
| | * Info: обработка запрос списка курсов |
| | * Settings: обработка запроса на смену локализации |
| | |
| | {{ :lm3:ce:multi_lang_lm.png?direct& }} |
| | |
| | ==== Скрипты ==== |
| | |
| | **main / start.lua** |
| | |
| | <code lua> |
| | lm3:Log("Starting server") |
| | |
| | lm3:LoadLibrary( {Alias = "sys", FileName = "lm3system"} ) |
| | lm3:Include("main_lib.lua") |
| | |
| | lm3:CreateLObject( { LibAlias = "sys", Type = "TCPServer", Name = "server" } ) |
| | server:SetAttr("SocCount", lmconf.MaxClientCount) |
| | |
| | lm3:CreateLObject( { LibAlias = "sys", Type = "DataPack", Name = "packer" } ) |
| | packer:SetAttr("BufCount", lmconf.MaxClientCount) |
| | |
| | lm3:CreateObject( { Type = "LMList", Name = "clients" } ) |
| | |
| | init_Auth("Auth") |
| | |
| | lm3:AddHandler("OnStart", function(o, ev) |
| | -- проверка конфигурации ЛМ |
| | if clients:DoPrepare(lmconf.BasePath.."client_lm/config.lua") == false then |
| | lm3:Log("client_lm prepare failed") |
| | end |
| | end) |
| | |
| | Auth:AddHandler("OnReply", function(o, ev) |
| | lm3:Log("Auth: OnReply: tag: "..tostring(ev.Tag).." : "..lm3:DataToString(ev.Data)) |
| | end) |
| | |
| | -- связи объектов |
| | server:Connect("OnConnect", "Auth", "DoConnect") |
| | server:Connect("OnDisconnect", "Auth", "DoDisconnect") |
| | server:Connect("OnIncoming", "packer", "DoUnpack") |
| | packer:Connect("OnUnpack", "Auth", "DoIncoming") |
| | Auth:Connect("OnReply", "packer", "DoPackTagged") |
| | packer:Connect("OnPack", "server", "DoSend") |
| | Auth:Connect("OnStartClientLM", "clients", "DoStart") |
| | Auth:Connect("OnStopClientLM", "clients", "DoStop") |
| | Auth:Connect("OnClientEvent", "clients", "DoEvent") |
| | clients:Connect("OnEvent", "Auth", "DoClientEvent") |
| | </code> |
| | |
| | **main / main_lib.lua** |
| | |
| | <code lua> |
| | -- объект Auth |
| | -- авторизирует клиента |
| | -- вызывает создание ЛМ |
| | -- связывает клиента с соответвующей ЛМ |
| | function init_Auth(_name) |
| | local obj = lm3:CreateObject( { Type = "Base", Name = _name } ) |
| | |
| | obj.ClientList = {} |
| | for i = 1, lmconf.MaxClientCount do |
| | obj.ClientList[i] = { |
| | isConnected = false, |
| | UserName = "", |
| | UserMail = "", |
| | LMName = "", |
| | } |
| | end |
| | |
| | function obj.TagFromLMName(_name) |
| | return tonumber(_name:sub(5)) |
| | end |
| | |
| | -- подключение нового клиента |
| | -- старт ЛМ |
| | obj:AddInEvent("DoConnect", "int", function(o, ev) |
| | lm3:Log("New client connected:"..tostring(ev)) |
| | obj.ClientList[ev].isConnected = true |
| | obj.ClientList[ev].UserName = "N/A" |
| | obj.ClientList[ev].UserMail = "N/A" |
| | obj.ClientList[ev].LMName = "clm_"..tostring(ev) |
| | lm3:Log("Start client LM...") |
| | if obj:OnStartClientLM( { Name = obj.ClientList[ev].LMName } ) == true then |
| | lm3:Log("Start client LM complete.") |
| | else |
| | lm3:Log("ERROR: Start client LM failed.") |
| | obj.ClientList[ev].isConnected = false |
| | end |
| | end) |
| | |
| | -- отключение клиента |
| | -- остановка ЛМ |
| | obj:AddInEvent("DoDisconnect", "int", function(o,ev) |
| | lm3:Log("Client disconnected:"..tostring(ev)) |
| | obj:OnStopClientLM(obj.ClientList[ev].LMName) |
| | obj.ClientList[ev].isConnected = false |
| | end) |
| | |
| | -- распределение данных от клиента |
| | obj:AddInEvent("DoIncoming", "table[Tag:int,Data:array[table[Object:string,Command:string,Name:string,[Data]:any]]]", function(o, ev) |
| | if obj.ClientList[ev.Tag].isConnected ~= true then |
| | lm3:Log("ERROR: Incoming data from not connected client: "..tostring(ev.Tag)) |
| | else |
| | lm3:Log("Incoming data from client with tag: "..tostring(ev.Tag).." : "..lm3:DataToString(ev.Data)) |
| | local data = ev.Data |
| | for i = 1,#data do |
| | local ObjName = data[i].Object |
| | if ObjName == "Auth" then |
| | obj:DoCommand( { Tag = ev.Tag, Data = data[i] } ) |
| | elseif ObjName == "Info" or ObjName == "Settings" then |
| | obj:OnClientEvent({ LMName = obj.ClientList[ev.Tag].LMName, EventName = "OnExtEvent", Data = data[i] }) |
| | else |
| | lm3:Log("Warning: Incoming command to unknown object: "..lm3:DataToString(ObjName)) |
| | end |
| | end |
| | end |
| | end) |
| | |
| | -- обработка данных от ЛМ |
| | obj:AddInEvent("DoClientEvent", "table[LMName:string,EventName:string,Data:any]", function(o, ev) |
| | local iClient = obj.TagFromLMName(ev.LMName) |
| | obj:OnReply( { Tag = iClient, Data = ev.Data } ) |
| | end) |
| | |
| | -- обработка запросов клиента к основной ЛМ |
| | obj:AddInEvent("DoCommand", "table[Tag:int,Data:table[Object:string,Command:string,Name:string,Data:any]]", function(o, ev) |
| | if ev.Data.Command == "Set" then |
| | if ev.Data.Name == "UserName" then |
| | obj.ClientList[ev.Tag].UserName = ev.Data.Data |
| | elseif ev.Data.Name == "UserMail" then |
| | obj.ClientList[ev.Tag].UserMail = ev.Data.Data |
| | obj:OnReply( { Tag = ev.Tag, Data = { {Object = "Auth", Command = "Value", Name = "TaskObject", Data = "Task"} } } ) |
| | end |
| | end |
| | end) |
| | |
| | -- отправь данные клиенту |
| | obj:AddOutEvent("OnReply", "table[Tag:int,Data:array[table[Object:string,Command:string,Name:string,[Data]:any]]]") |
| | |
| | -- отправить данные в ЛМ |
| | obj:AddOutProc("OnClientEvent", "table[LMName:string,EventName:string,Data:any]", "bool") |
| | |
| | obj:AddOutProc("OnStartClientLM", "table[Name:string]", "bool") |
| | |
| | obj:AddOutProc("OnStopClientLM", "string", "bool") |
| | |
| | return obj |
| | end |
| | </code> |
| | |
| | **main / client_lm / start.lua** |
| | |
| | <code lua> |
| | lm3:LoadLibrary( {Alias = "sys", FileName = "lm3system"} ) |
| | lm3:Include("client_lib.lua") |
| | |
| | -- объект Timer для alive сообщение |
| | lm3:CreateObject( { Type = "Timer", Name = "timer" } ) |
| | timer:SetAttr("Interval", 30*1000) |
| | |
| | -- объект Settings |
| | -- позволяет менять конфигурацию ЛМ |
| | init_Settings("Settings") |
| | |
| | -- объект Info |
| | -- возвращает информацию о курсах |
| | init_Info("Info") |
| | |
| | lm3:CreateLObject( { LibAlias = "sys", Type = "FileSystem", Name = "files" } ) |
| | |
| | lm3:CreateObject( { Type = "LuaData", Name = "lualoader" } ) |
| | |
| | lm3:AddHandler("OnStart", function(o, ev) |
| | Info:DoInitCourceList() |
| | timer:DoEnable(true) |
| | end) |
| | |
| | -- обработчик ивента с основной логической машины |
| | -- распределяет запросы по клиентам |
| | lm3:AddHandler("OnExtEvent", function(o, ev) |
| | local work_obj = lm3:GetObject(ev.Object) |
| | if work_obj ~= nil then |
| | if ev.Command == "Event" then |
| | lm3:Log("Fire client event:"..ev.Name.."("..lm3:DataToString(ev.Data)..")") |
| | work_obj:FireEvent(ev.Name, ev.Data) |
| | end |
| | else |
| | lm3:Log("ERROR: Incoming command to unknown object:"..lm3:DataToString(ev)) |
| | end |
| | end) |
| | |
| | -- обработчик ответа от объекта |
| | Info:AddHandler("OnCourceList", function(o, ev) |
| | lm3:DoExtEvent({ { Object = "Info", Command = "Value", Name = "CourceList", Data = ev } }) |
| | end) |
| | |
| | timer:AddHandler("OnTick", function(o, ev) |
| | --lm3:Log("OnTick: send Alive") |
| | local data = {} |
| | data[1] = { Object = "Settings", Command = "Event", Name = "Alive" } |
| | lm3:DoExtEvent(data) |
| | end) |
| | </code> |
| | |
| | ==== Логи ==== |
| | |
| | **[client]** |
| | |
| | <code> |
| | 2020-11-26 18:34:50.542 23236-23236/com.example.lm3_client D/lm3: application: onCreate |
| | 2020-11-26 18:34:50.559 23236-23236/com.example.lm3_client D/lm3: application: setNetworkStatus: 2 |
| | -- подключение к серверу |
| | 2020-11-26 18:34:50.559 23236-23236/com.example.lm3_client D/lm3: connect: startServerConnection |
| | 2020-11-26 18:34:50.560 23236-23285/com.example.lm3_client D/lm3: connect: start |
| | 2020-11-26 18:34:50.561 23236-23284/com.example.lm3_client D/lm3: application: setNetworkStatus: 2 |
| | 2020-11-26 18:34:50.578 23236-23285/com.example.lm3_client D/lm3: connect: setServerConnection: true |
| | 2020-11-26 18:34:50.579 23236-23285/com.example.lm3_client D/lm3: connect: done |
| | 2020-11-26 18:34:50.579 23236-23285/com.example.lm3_client D/lm3: connect: end |
| | 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: connect: start listen |
| | -- авторизация |
| | 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: auth: auth |
| | 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: auth: SetName: testtest |
| | 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: listen: serverSend |
| | 2020-11-26 18:34:50.580 23236-23287/com.example.lm3_client D/lm3: auth: SetMail: test@test.test |
| | 2020-11-26 18:34:50.580 23236-23287/com.example.lm3_client D/lm3: listen: serverSend |
| | -- установка локализации |
| | 2020-11-26 18:34:50.581 23236-23287/com.example.lm3_client D/lm3: settings: SetLanguage: EN |
| | 2020-11-26 18:34:50.581 23236-23287/com.example.lm3_client D/lm3: listen: serverSend |
| | 2020-11-26 18:34:50.589 23236-23236/com.example.lm3_client D/lm3: activity: main: OnCreate |
| | 2020-11-26 18:34:50.643 23236-23287/com.example.lm3_client D/lm3: auth: setTaskObject |
| | 2020-11-26 18:34:50.643 23236-23287/com.example.lm3_client D/lm3: info: GetCourseList |
| | 2020-11-26 18:34:50.643 23236-23287/com.example.lm3_client D/lm3: listen: serverSend |
| | 2020-11-26 18:34:50.697 23236-23236/com.example.lm3_client D/lm3: activity: main: onResume |
| | -- запрос списка курсов |
| | 2020-11-26 18:34:50.886 23236-23287/com.example.lm3_client D/lm3: info: setCourseList: |
| | 2020-11-26 18:34:50.887 23236-23287/com.example.lm3_client D/lm3: info: Introduction to Somnology |
| | 2020-11-26 18:34:50.887 23236-23287/com.example.lm3_client D/lm3: info: Snoring problems |
| | 2020-11-26 18:35:07.609 23236-23236/com.example.lm3_client D/lm3: activity: main: onPause |
| | 2020-11-26 18:35:07.624 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate |
| | 2020-11-26 18:35:07.674 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: current locale: en |
| | 2020-11-26 18:35:07.674 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: locale in memory: EN |
| | 2020-11-26 18:35:07.682 23236-23236/com.example.lm3_client D/lm3: activity: settings: onResume |
| | -- установка локализации |
| | 2020-11-26 18:35:09.775 23236-23236/com.example.lm3_client D/lm3: activity: settings: changeLocale: start: RU |
| | 2020-11-26 18:35:09.775 23236-23236/com.example.lm3_client D/lm3: activity: settings: changeLocale: change from: EN |
| | 2020-11-26 18:35:09.776 23236-23236/com.example.lm3_client D/lm3: settings: SetLanguage: RU |
| | 2020-11-26 18:35:09.777 23236-23236/com.example.lm3_client D/lm3: listen: serverSend |
| | -- запрос списка курсов |
| | 2020-11-26 18:35:09.779 23236-23236/com.example.lm3_client D/lm3: info: GetCourseList |
| | 2020-11-26 18:35:09.779 23236-23236/com.example.lm3_client D/lm3: listen: serverSend |
| | 2020-11-26 18:35:09.786 23236-23236/com.example.lm3_client D/lm3: activity: settings: changeLocale: check: ru |
| | 2020-11-26 18:35:09.822 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate |
| | 2020-11-26 18:35:09.828 23236-23287/com.example.lm3_client D/lm3: info: setCourseList: |
| | 2020-11-26 18:35:09.828 23236-23287/com.example.lm3_client D/lm3: info: Введение в сомнологию |
| | 2020-11-26 18:35:09.828 23236-23287/com.example.lm3_client D/lm3: info: Проблемы храпа |
| | 2020-11-26 18:35:09.872 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: current locale: ru |
| | 2020-11-26 18:35:09.872 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: locale in memory: RU |
| | 2020-11-26 18:35:09.877 23236-23236/com.example.lm3_client D/lm3: activity: settings: onResume |
| | </code> |
| | |
| | |
| | **[server] LM_main.log** |
| | |
| | <code> |
| | [2020-11-27 11:39:50][INFO:LMInit][Start logic machine v3.3(Build:555) ----------------------------------] |
| | [2020-11-27 11:39:50][LUA:LMCore][Starting server] |
| | [2020-11-27 11:39:50][TRACE:LMInit][Create library object: server] |
| | [2020-11-27 11:39:50][TRACE:LMInit][Create library object: packer] |
| | [2020-11-27 11:39:50][TRACE:LMInit][Create object: clients] |
| | [2020-11-27 11:39:50][TRACE:LMInit][Create object: Auth] |
| | [2020-11-27 11:39:50][INFO:LMInit][Initialization complete.] |
| | [2020-11-27 11:39:51][LUA:LMCore][New client connected:1] |
| | [2020-11-27 11:39:51][LUA:LMCore][Start client LM...] |
| | [2020-11-27 11:39:51][LUA:LMCore][Start client LM complete.] |
| | -- авторизация клиента |
| | [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Set" |
| | "Data" = [String] "testtest" |
| | "Name" = [String] "UserName" |
| | "Object" = [String] "Auth"] |
| | [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Set" |
| | "Data" = [String] "test@test.test" |
| | "Name" = [String] "UserMail" |
| | "Object" = [String] "Auth"] |
| | [2020-11-27 11:39:51][LUA:LMCore][Auth: OnReply: tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Value" |
| | "Data" = [String] "Task" |
| | "Name" = [String] "TaskObject" |
| | "Object" = [String] "Auth"] |
| | [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Event" |
| | "Data" = [String] "RU" |
| | "Name" = [String] "DoChangeLang" |
| | "Object" = [String] "Settings"] |
| | -- запрос списка курсов |
| | [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] |
| | 1 = [Table:3] |
| | "Command" = [String] "Event" |
| | "Name" = [String] "CourceList" |
| | "Object" = [String] "Info"] |
| | [2020-11-27 11:39:51][LUA:LMCore][Auth: OnReply: tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Value" |
| | "Data" = [Array:2] |
| | 1 = [Table:3] |
| | "CourceID" = [String] "c1" |
| | "Description" = [String] "Хотите быстро засыпать, высыпаться и чувствовать себя отлично в течение дня? Узнайте все о том, как наладить правильный сон." |
| | "Name" = [String] "Введение в сомнологию" |
| | 2 = [Table:3] |
| | "CourceID" = [String] "c2" |
| | "Description" = [String] "N/A" |
| | "Name" = [String] "Проблемы храпа" |
| | "Name" = [String] "CourceList" |
| | "Object" = [String] "Info"] |
| | -- смена локализации |
| | [2020-11-27 11:40:15][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Event" |
| | "Data" = [String] "EN" |
| | "Name" = [String] "DoChangeLang" |
| | "Object" = [String] "Settings"] |
| | -- запрос списка курсов |
| | [2020-11-27 11:40:15][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] |
| | 1 = [Table:3] |
| | "Command" = [String] "Event" |
| | "Name" = [String] "CourceList" |
| | "Object" = [String] "Info"] |
| | [2020-11-27 11:40:15][LUA:LMCore][Auth: OnReply: tag: 1 : [Array:1] |
| | 1 = [Table:4] |
| | "Command" = [String] "Value" |
| | "Data" = [Array:2] |
| | 1 = [Table:3] |
| | "CourceID" = [String] "c1" |
| | "Description" = [String] "Want to fall asleep fast, get enough sleep and feel great throughout the day? Learn all about how to get good sleep." |
| | "Name" = [String] "Introduction to Somnology" |
| | 2 = [Table:3] |
| | "CourceID" = [String] "c2" |
| | "Description" = [String] "N/A" |
| | "Name" = [String] "Snoring problems" |
| | "Name" = [String] "CourceList" |
| | "Object" = [String] "Info"] |
| | </code> |
| | |
| | |
| | **[client] LM_clm_1.log** |
| | |
| | <code> |
| | [2020-11-27 11:39:51][INFO:LMInit][Start logic machine v3.3(Build:555) ----------------------------------] |
| | [2020-11-27 11:39:51][TRACE:LMInit][Create object: timer] |
| | [2020-11-27 11:39:51][TRACE:LMInit][Create object: Settings] |
| | [2020-11-27 11:39:51][TRACE:LMInit][Create object: Info] |
| | [2020-11-27 11:39:51][TRACE:LMInit][Create library object: files] |
| | [2020-11-27 11:39:51][TRACE:LMInit][Create object: lualoader] |
| | [2020-11-27 11:39:51][INFO:LMInit][Initialization complete.] |
| | -- авторизация клиента |
| | [2020-11-27 11:39:51][LUA:LMCore][Fire client event:DoChangeLang([String] "RU")] |
| | -- запрос списка курсов |
| | [2020-11-27 11:39:51][LUA:LMCore][Fire client event:CourceList([Nil])] |
| | -- смена локализации клиентом |
| | [2020-11-27 11:40:15][LUA:LMCore][Fire client event:DoChangeLang([String] "EN")] |
| | [2020-11-27 11:40:15][LUA:LMCore][Settings Event: DoChangeLang: Change to: EN] |
| | -- запрос списка курсов |
| | [2020-11-27 11:40:15][LUA:LMCore][Fire client event:CourceList([Nil])] |
| | </code> |
| |
| |