velconnect v2 wow
parent
4502662a53
commit
5762013f03
|
|
@ -11,4 +11,5 @@ discord_bot/graph.png
|
|||
discord_bot/config.py
|
||||
env_win/
|
||||
velconnect.db
|
||||
velconnect*.db
|
||||
.idea/
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace VELConnect
|
|||
public class VELConnectManager : MonoBehaviour
|
||||
{
|
||||
public string velConnectUrl = "http://localhost";
|
||||
public static VELConnectManager instance;
|
||||
private static VELConnectManager instance;
|
||||
|
||||
public class State
|
||||
{
|
||||
|
|
@ -36,7 +36,8 @@ namespace VELConnect
|
|||
/// </summary>
|
||||
public string TryGetData(string key)
|
||||
{
|
||||
return data?.TryGetValue(key, out string val) == true ? val : null;
|
||||
string val = null;
|
||||
return data?.TryGetValue(key, out val) == true ? val : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +51,15 @@ namespace VELConnect
|
|||
public string last_modified;
|
||||
public string last_accessed;
|
||||
public Dictionary<string, string> data;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value if it exists, otherwise null
|
||||
/// </summary>
|
||||
public string TryGetData(string key)
|
||||
{
|
||||
string val = null;
|
||||
return data?.TryGetValue(key, out val) == true ? val : null;
|
||||
}
|
||||
}
|
||||
|
||||
public Device device;
|
||||
|
|
@ -63,6 +73,25 @@ namespace VELConnect
|
|||
public static Action<string, string> OnDeviceDataChanged;
|
||||
public static Action<string, string> OnRoomDataChanged;
|
||||
|
||||
private static readonly Dictionary<string, List<CallbackListener>> deviceFieldCallbacks = new Dictionary<string, List<CallbackListener>>();
|
||||
private static readonly Dictionary<string, List<CallbackListener>> deviceDataCallbacks = new Dictionary<string, List<CallbackListener>>();
|
||||
private static readonly Dictionary<string, List<CallbackListener>> roomDataCallbacks = new Dictionary<string, List<CallbackListener>>();
|
||||
|
||||
private struct CallbackListener
|
||||
{
|
||||
/// <summary>
|
||||
/// Used so that other objects don't have to remove listeners themselves
|
||||
/// </summary>
|
||||
public MonoBehaviour keepAliveObject;
|
||||
|
||||
public Action<string> callback;
|
||||
|
||||
/// <summary>
|
||||
/// Sends the first state received from the network or the state at binding time
|
||||
/// </summary>
|
||||
public bool sendInitialState;
|
||||
}
|
||||
|
||||
public static int PairingCode
|
||||
{
|
||||
get
|
||||
|
|
@ -80,10 +109,10 @@ namespace VELConnect
|
|||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR
|
||||
// allows running multiple builds on the same computer
|
||||
// return SystemInfo.deviceUniqueIdentifier + Hash128.Compute(Application.dataPath);
|
||||
return SystemInfo.deviceUniqueIdentifier + "_BUILD";
|
||||
#if UNITY_EDITOR
|
||||
// allows running multiple builds on the same computer
|
||||
// return SystemInfo.deviceUniqueIdentifier + Hash128.Compute(Application.dataPath);
|
||||
return SystemInfo.deviceUniqueIdentifier + "_EDITOR";
|
||||
#else
|
||||
return SystemInfo.deviceUniqueIdentifier;
|
||||
#endif
|
||||
|
|
@ -137,7 +166,7 @@ namespace VELConnect
|
|||
{ "version", Application.version },
|
||||
{ "platform", SystemInfo.operatingSystem },
|
||||
};
|
||||
PostRequestCallback(velConnectUrl + "/api/v2/update_user_count", JsonConvert.SerializeObject(postData));
|
||||
PostRequestCallback(velConnectUrl + "/api/update_user_count", JsonConvert.SerializeObject(postData));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -147,11 +176,13 @@ namespace VELConnect
|
|||
{
|
||||
try
|
||||
{
|
||||
GetRequestCallback(velConnectUrl + "/api/v2/get_state/" + DeviceId, json =>
|
||||
GetRequestCallback(velConnectUrl + "/api/v2/device/get_data/" + DeviceId, json =>
|
||||
{
|
||||
State state = JsonConvert.DeserializeObject<State>(json);
|
||||
if (state == null) return;
|
||||
|
||||
bool isInitialState = false;
|
||||
|
||||
// first load stuff
|
||||
if (lastState == null)
|
||||
{
|
||||
|
|
@ -164,8 +195,9 @@ namespace VELConnect
|
|||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
lastState = state;
|
||||
return;
|
||||
isInitialState = true;
|
||||
// lastState = state;
|
||||
// return;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -176,52 +208,126 @@ namespace VELConnect
|
|||
foreach (FieldInfo fieldInfo in fields)
|
||||
{
|
||||
string newValue = fieldInfo.GetValue(state.device) as string;
|
||||
string oldValue = fieldInfo.GetValue(lastState.device) as string;
|
||||
string oldValue = lastState != null ? fieldInfo.GetValue(lastState.device) as string : null;
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnDeviceFieldChanged?.Invoke(fieldInfo.Name, newValue);
|
||||
if (!isInitialState) OnDeviceFieldChanged?.Invoke(fieldInfo.Name, newValue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
// send specific listeners data
|
||||
if (deviceFieldCallbacks.ContainsKey(fieldInfo.Name))
|
||||
{
|
||||
// clear the list of old listeners
|
||||
deviceFieldCallbacks[fieldInfo.Name].RemoveAll(e => e.keepAliveObject == null);
|
||||
|
||||
// send the callbacks
|
||||
deviceFieldCallbacks[fieldInfo.Name].ForEach(e =>
|
||||
{
|
||||
if (!isInitialState || e.sendInitialState)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.callback(newValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> elem in state.device.data)
|
||||
if (state.device.data != null)
|
||||
{
|
||||
lastState.device.data.TryGetValue(elem.Key, out string oldValue);
|
||||
if (elem.Value != oldValue)
|
||||
foreach (KeyValuePair<string, string> elem in state.device.data)
|
||||
{
|
||||
try
|
||||
string oldValue = null;
|
||||
lastState?.device.data.TryGetValue(elem.Key, out oldValue);
|
||||
if (elem.Value != oldValue)
|
||||
{
|
||||
OnDeviceDataChanged?.Invoke(elem.Key, elem.Value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
try
|
||||
{
|
||||
if (!isInitialState) OnDeviceDataChanged?.Invoke(elem.Key, elem.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
|
||||
// send specific listeners data
|
||||
if (deviceDataCallbacks.ContainsKey(elem.Key))
|
||||
{
|
||||
// clear the list of old listeners
|
||||
deviceDataCallbacks[elem.Key].RemoveAll(e => e.keepAliveObject == null);
|
||||
|
||||
// send the callbacks
|
||||
deviceDataCallbacks[elem.Key].ForEach(e =>
|
||||
{
|
||||
if (!isInitialState || e.sendInitialState)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.callback(elem.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.room.modified_by != DeviceId)
|
||||
if (state.room.modified_by != DeviceId && state.room.data != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> elem in state.room.data)
|
||||
{
|
||||
lastState.room.data.TryGetValue(elem.Key, out string oldValue);
|
||||
string oldValue = null;
|
||||
lastState?.room.data.TryGetValue(elem.Key, out oldValue);
|
||||
if (elem.Value != oldValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnRoomDataChanged?.Invoke(elem.Key, elem.Value);
|
||||
if (!isInitialState) OnRoomDataChanged?.Invoke(elem.Key, elem.Value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
// send specific listeners data
|
||||
if (roomDataCallbacks.ContainsKey(elem.Key))
|
||||
{
|
||||
// clear the list of old listeners
|
||||
roomDataCallbacks[elem.Key].RemoveAll(e => e.keepAliveObject == null);
|
||||
|
||||
// send the callbacks
|
||||
roomDataCallbacks[elem.Key].ForEach(e =>
|
||||
{
|
||||
if (!isInitialState || e.sendInitialState)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.callback(elem.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -239,16 +345,130 @@ namespace VELConnect
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a change listener callback to a particular field name within the Device main fields.
|
||||
/// </summary>
|
||||
public static void AddDeviceFieldListener(string key, MonoBehaviour keepAliveObject, Action<string> callback, bool sendInitialState = false)
|
||||
{
|
||||
if (!deviceFieldCallbacks.ContainsKey(key))
|
||||
{
|
||||
deviceFieldCallbacks[key] = new List<CallbackListener>();
|
||||
}
|
||||
|
||||
deviceFieldCallbacks[key].Add(new CallbackListener()
|
||||
{
|
||||
keepAliveObject = keepAliveObject,
|
||||
callback = callback,
|
||||
sendInitialState = sendInitialState
|
||||
});
|
||||
|
||||
if (sendInitialState)
|
||||
{
|
||||
if (instance != null && instance.lastState?.device != null)
|
||||
{
|
||||
if (instance.lastState.device.GetType().GetField(key)?.GetValue(instance.lastState.device) is string val)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(val);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a change listener callback to a particular field name within the Device data JSON.
|
||||
/// </summary>
|
||||
public static void AddDeviceDataListener(string key, MonoBehaviour keepAliveObject, Action<string> callback, bool sendInitialState = false)
|
||||
{
|
||||
if (!deviceDataCallbacks.ContainsKey(key))
|
||||
{
|
||||
deviceDataCallbacks[key] = new List<CallbackListener>();
|
||||
}
|
||||
|
||||
deviceDataCallbacks[key].Add(new CallbackListener()
|
||||
{
|
||||
keepAliveObject = keepAliveObject,
|
||||
callback = callback,
|
||||
sendInitialState = sendInitialState
|
||||
});
|
||||
|
||||
if (sendInitialState)
|
||||
{
|
||||
string val = GetDeviceData(key);
|
||||
if (val != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(val);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a change listener callback to a particular field name within the Room data JSON.
|
||||
/// </summary>
|
||||
public static void AddRoomDataListener(string key, MonoBehaviour keepAliveObject, Action<string> callback, bool sendInitialState = false)
|
||||
{
|
||||
if (!roomDataCallbacks.ContainsKey(key))
|
||||
{
|
||||
roomDataCallbacks[key] = new List<CallbackListener>();
|
||||
}
|
||||
|
||||
roomDataCallbacks[key].Add(new CallbackListener()
|
||||
{
|
||||
keepAliveObject = keepAliveObject,
|
||||
callback = callback,
|
||||
sendInitialState = sendInitialState
|
||||
});
|
||||
|
||||
if (sendInitialState)
|
||||
{
|
||||
string val = GetRoomData(key);
|
||||
if (val != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(val);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetDeviceData(string key)
|
||||
{
|
||||
return instance != null ? instance.lastState?.device?.TryGetData(key) : null;
|
||||
}
|
||||
|
||||
public static string GetRoomData(string key)
|
||||
{
|
||||
return instance != null ? instance.lastState?.room?.TryGetData(key) : null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets data on the device keys themselves
|
||||
/// </summary>
|
||||
public static void SetDeviceBaseData(Dictionary<string, object> data)
|
||||
{
|
||||
data["modified_by"] = DeviceId;
|
||||
instance.PostRequestCallback(
|
||||
instance.velConnectUrl + "/api/v2/device/set_data/" + DeviceId,
|
||||
JsonConvert.SerializeObject(data)
|
||||
JsonConvert.SerializeObject(data),
|
||||
new Dictionary<string, string> { { "modified_by", DeviceId } }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -259,11 +479,8 @@ namespace VELConnect
|
|||
{
|
||||
instance.PostRequestCallback(
|
||||
instance.velConnectUrl + "/api/v2/device/set_data/" + DeviceId,
|
||||
JsonConvert.SerializeObject(new Dictionary<string, object>
|
||||
{
|
||||
{ "modified_by", DeviceId },
|
||||
{ "data", data }
|
||||
})
|
||||
JsonConvert.SerializeObject(new Dictionary<string, object> { { "data", data } }),
|
||||
new Dictionary<string, string> { { "modified_by", DeviceId } }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -275,10 +492,10 @@ namespace VELConnect
|
|||
return;
|
||||
}
|
||||
|
||||
data["modified_by"] = DeviceId;
|
||||
instance.PostRequestCallback(
|
||||
instance.velConnectUrl + "/api/v2/set_data/" + Application.productName + "_" + VelNetManager.Room,
|
||||
JsonConvert.SerializeObject(data)
|
||||
JsonConvert.SerializeObject(data),
|
||||
new Dictionary<string, string> { { "modified_by", DeviceId } }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -308,13 +525,13 @@ namespace VELConnect
|
|||
}
|
||||
}
|
||||
|
||||
public void PostRequestCallback(string url, string postData, Action<string> successCallback = null,
|
||||
public void PostRequestCallback(string url, string postData, Dictionary<string, string> headers = null, Action<string> successCallback = null,
|
||||
Action<string> failureCallback = null)
|
||||
{
|
||||
StartCoroutine(PostRequestCallbackCo(url, postData, successCallback, failureCallback));
|
||||
StartCoroutine(PostRequestCallbackCo(url, postData, headers, successCallback, failureCallback));
|
||||
}
|
||||
|
||||
private static IEnumerator PostRequestCallbackCo(string url, string postData, Action<string> successCallback = null,
|
||||
private static IEnumerator PostRequestCallbackCo(string url, string postData, Dictionary<string, string> headers = null, Action<string> successCallback = null,
|
||||
Action<string> failureCallback = null)
|
||||
{
|
||||
UnityWebRequest webRequest = new UnityWebRequest(url, "POST");
|
||||
|
|
@ -322,6 +539,14 @@ namespace VELConnect
|
|||
UploadHandlerRaw uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
webRequest.uploadHandler = uploadHandler;
|
||||
webRequest.SetRequestHeader("Content-Type", "application/json");
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> keyValuePair in headers)
|
||||
{
|
||||
webRequest.SetRequestHeader(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
yield return webRequest.SendWebRequest();
|
||||
|
||||
switch (webRequest.result)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class DB:
|
|||
return conn, curr
|
||||
|
||||
def query(self, query_string: str, data: dict = None) -> list:
|
||||
conn = None
|
||||
try:
|
||||
conn, curr = self.create_or_connect()
|
||||
if data is not None:
|
||||
|
|
@ -35,7 +36,8 @@ class DB:
|
|||
return values
|
||||
except:
|
||||
print(traceback.print_exc())
|
||||
conn.close()
|
||||
if conn is not None:
|
||||
conn.close()
|
||||
raise
|
||||
|
||||
def insert(self, query_string: str, data: dict = None) -> bool:
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ def get_device_by_pairing_code(pairing_code: str):
|
|||
|
||||
def create_device(hw_id: str):
|
||||
db.insert("""
|
||||
INSERT IGNORE INTO `Device`(hw_id) VALUES (:hw_id);
|
||||
INSERT OR IGNORE INTO `Device`(hw_id) VALUES (:hw_id);
|
||||
""", {'hw_id': hw_id})
|
||||
|
||||
|
||||
@router.get('/device/get_data/{hw_id}')
|
||||
def get_state(hw_id: str):
|
||||
def get_state(request: fastapi.Request, hw_id: str):
|
||||
"""Gets the device state"""
|
||||
|
||||
devices = db.query("""
|
||||
|
|
@ -77,26 +77,35 @@ def get_state(hw_id: str):
|
|||
""", {'hw_id': hw_id})
|
||||
if len(devices) == 0:
|
||||
return {'error': "Can't find device with that id."}
|
||||
block = dict(devices[0])
|
||||
if 'data' in block and block['data'] is not None:
|
||||
block['data'] = json.loads(block['data'])
|
||||
|
||||
room_data = get_data(f"{devices[0]['current_app']}_{devices[0]['current_room']}")
|
||||
room_key: str = f"{devices[0]['current_app']}_{devices[0]['current_room']}"
|
||||
room_data = get_data(room_key)
|
||||
|
||||
return {'device': devices[0], 'room': room_data}
|
||||
if "error" in room_data:
|
||||
set_data(request, data={}, key=room_key, modified_by=None, category="room")
|
||||
room_data = get_data(room_key)
|
||||
|
||||
return {'device': block, 'room': room_data}
|
||||
|
||||
|
||||
@router.post('/device/set_data/{hw_id}')
|
||||
def set_state(hw_id: str, data: dict, request: fastapi.Request):
|
||||
def set_state(request: fastapi.Request, hw_id: str, data: dict, modified_by: str = None):
|
||||
"""Sets the device state"""
|
||||
|
||||
create_device(hw_id)
|
||||
|
||||
# add the client's IP address if no sender specified
|
||||
if 'modified_by' not in data:
|
||||
data['modified_by'] = str(request.client) + "_" + str(request.headers)
|
||||
if 'modified_by' in data:
|
||||
modified_by = data['modified_by']
|
||||
if modified_by is None:
|
||||
modified_by: str = str(request.client) + "_" + str(request.headers)
|
||||
|
||||
allowed_keys: list[str] = [
|
||||
'os_info',
|
||||
'friendly_name',
|
||||
'modified_by',
|
||||
'current_app',
|
||||
'current_room',
|
||||
'pairing_code',
|
||||
|
|
@ -107,15 +116,17 @@ def set_state(hw_id: str, data: dict, request: fastapi.Request):
|
|||
db.insert(f"""
|
||||
UPDATE `Device`
|
||||
SET {key}=:value,
|
||||
last_modified=CURRENT_TIMESTAMP
|
||||
last_modified=CURRENT_TIMESTAMP,
|
||||
modified_by=:modified_by
|
||||
WHERE `hw_id`=:hw_id;
|
||||
""",
|
||||
{
|
||||
'value': data[key],
|
||||
'hw_id': hw_id,
|
||||
'sender_id': data['sender_id']
|
||||
'modified_by': modified_by
|
||||
})
|
||||
if key == "data":
|
||||
new_data = data['data']
|
||||
# get the old json values and merge the data
|
||||
old_data_query = db.query("""
|
||||
SELECT data
|
||||
|
|
@ -124,8 +135,10 @@ def set_state(hw_id: str, data: dict, request: fastapi.Request):
|
|||
""", {"hw_id": hw_id})
|
||||
|
||||
if len(old_data_query) == 1:
|
||||
old_data: dict = json.loads(old_data_query[0]["data"])
|
||||
data = {**old_data, **data}
|
||||
old_data: dict = {}
|
||||
if old_data_query[0]['data'] is not None:
|
||||
old_data = json.loads(old_data_query[0]["data"])
|
||||
new_data = {**old_data, **new_data}
|
||||
|
||||
# add the data to the db
|
||||
db.insert("""
|
||||
|
|
@ -133,7 +146,7 @@ def set_state(hw_id: str, data: dict, request: fastapi.Request):
|
|||
SET data=:data,
|
||||
last_modified=CURRENT_TIMESTAMP
|
||||
WHERE hw_id=:hw_id;
|
||||
""", {"hw_id": hw_id, "data": json.dumps(data)})
|
||||
""", {"hw_id": hw_id, "data": json.dumps(new_data)})
|
||||
return {'success': True}
|
||||
|
||||
|
||||
|
|
@ -143,18 +156,22 @@ def generate_id(length: int = 4) -> str:
|
|||
|
||||
|
||||
@router.post('/set_data')
|
||||
def store_data_with_random_key(request: fastapi.Request, data: dict, category: str = None) -> dict:
|
||||
def set_data_with_random_key(request: fastapi.Request, data: dict, modified_by: str = None,
|
||||
category: str = None) -> dict:
|
||||
"""Creates a little storage bucket for arbitrary data with a random key"""
|
||||
return store_data(request, data, None, category)
|
||||
return set_data(request, data, None, modified_by, category)
|
||||
|
||||
|
||||
@router.post('/set_data/{key}')
|
||||
def store_data(request: fastapi.Request, data: dict, key: str = None, modified_by: str = None, category: str = None) -> dict:
|
||||
def set_data(request: fastapi.Request, data: dict, key: str = None, modified_by: str = None,
|
||||
category: str = None) -> dict:
|
||||
"""Creates a little storage bucket for arbitrary data"""
|
||||
|
||||
# add the client's IP address if no sender specified
|
||||
if 'modified_by' in data:
|
||||
modified_by = data['modified_by']
|
||||
if modified_by is None:
|
||||
modified_by = str(request.client) + "_" + str(request.headers)
|
||||
modified_by: str = str(request.client) + "_" + str(request.headers)
|
||||
|
||||
# generates a key if none was supplied
|
||||
if key is None:
|
||||
|
|
@ -189,7 +206,7 @@ def get_data(key: str) -> dict:
|
|||
"""Gets data from a storage bucket for arbitrary data"""
|
||||
|
||||
data = db.query("""
|
||||
SELECT data
|
||||
SELECT *
|
||||
FROM `DataBlock`
|
||||
WHERE id=:id
|
||||
""", {"id": key})
|
||||
|
|
@ -202,7 +219,11 @@ def get_data(key: str) -> dict:
|
|||
|
||||
try:
|
||||
if len(data) == 1:
|
||||
return json.loads(data[0])
|
||||
block = dict(data[0])
|
||||
if 'data' in block and block['data'] is not None:
|
||||
block['data'] = json.loads(block['data'])
|
||||
return block
|
||||
return {'error': 'Not found'}
|
||||
except:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return {'error': 'Unknown. Maybe no data at this key.'}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ function httpGetAsync(theUrl, callback, failCallback) {
|
|||
function httpPostAsync(theUrl, data, callback, failCallback) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function () {
|
||||
if (xmlHttp.readyState == 4) {
|
||||
if (xmlHttp.status == 200) {
|
||||
if (xmlHttp.readyState === 4) {
|
||||
if (xmlHttp.status === 200) {
|
||||
callback(xmlHttp.responseText);
|
||||
} else {
|
||||
failCallback(xmlHttp.status);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
<div class="tile tile-centered col-6">
|
||||
<div class="tile-content">
|
||||
<div class="tile-title text-bold">Last Login</div>
|
||||
<div class="tile-subtitle last_used">---</div>
|
||||
<div class="tile-subtitle last_modified">---</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -167,6 +167,8 @@
|
|||
<div class="tile-content">
|
||||
<div class="tile-title text-bold">Current Room</div>
|
||||
<input class="btn current_room" type="text" id="current_room" placeholder="----">
|
||||
<input style="display: none;" class="btn current_app" type="text" id="current_app"
|
||||
placeholder="----">
|
||||
<button class="btn btn-primary btn-lg tooltip tooltip-right" id="set_room_id"
|
||||
data-tooltip="Set Room ID">Set
|
||||
</button>
|
||||
|
|
@ -185,14 +187,36 @@
|
|||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="divider text-center" data-content="Screen Sharing"></div>
|
||||
|
||||
<div>
|
||||
<p>To share your screen, download <a href="https://github.com/velaboratory/VEL-Share/releases/latest" target="_blank">VEL-Share
|
||||
<div>
|
||||
<div class="flex flex-col h-screen relative">
|
||||
<header class="flex h-16 justify-center items-center text-xl bg-black text-white">
|
||||
<div class="columns">
|
||||
<button id="bnt_pubcam" class="btn btn-secondary btn-lg col-6"
|
||||
onclick="start(true)">Publish Camera
|
||||
</button>
|
||||
<button id="bnt_pubscreen" class="btn btn-secondary btn-lg col-6"
|
||||
onclick="start(false)">Publish Screen
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<video style="width: 100%;" id="pub_video" class="bg-black" controls></video>
|
||||
</div>
|
||||
<script src="https://unpkg.com/ion-sdk-js@1.5.5/dist/ion-sdk.min.js"></script>
|
||||
<script src="https://unpkg.com/ion-sdk-js@1.5.5/dist/json-rpc.min.js"></script>
|
||||
</div>
|
||||
<p>For more screen-sharing options and remote control, download <a
|
||||
href="https://github.com/velaboratory/VEL-Share/releases/latest" target="_blank">VEL-Share
|
||||
<svg style="width:1em;height:1em" viewBox="0 0 24 24">
|
||||
<path fill="currentColor"
|
||||
d="M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z"/>
|
||||
</svg>
|
||||
</a></p>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -208,6 +232,7 @@
|
|||
let headset_details = document.getElementById('headset_details');
|
||||
let hw_id_field = document.getElementById('hw_id');
|
||||
let failure = document.getElementById('failure');
|
||||
let current_app = document.getElementById('current_app');
|
||||
let current_room = document.getElementById('current_room');
|
||||
let set_room_id = document.getElementById('set_room_id');
|
||||
let set_user_color = document.getElementById('set_user_color');
|
||||
|
|
@ -221,9 +246,10 @@
|
|||
|
||||
// check cookie
|
||||
let hw_id = getCookie('hw_id');
|
||||
|
||||
if (hw_id !== "" && hw_id !== undefined && hw_id !== "undefined") {
|
||||
|
||||
httpGetAsync('/api/get_state/' + hw_id, (resp) => {
|
||||
httpGetAsync('/api/v2/device/get_data/' + hw_id, (resp) => {
|
||||
console.log(resp);
|
||||
let respData = JSON.parse(resp);
|
||||
|
||||
|
|
@ -231,20 +257,17 @@
|
|||
window.location.href = "/pair";
|
||||
}
|
||||
|
||||
writeClass('hw_id', respData['user']['hw_id']);
|
||||
writeClass('pairing_code', respData['user']['pairing_code']);
|
||||
writeValue('current_room', respData['user']['current_room']);
|
||||
writeClass('date_created', respData['user']['date_created'] + "<br>" + timeSinceString(respData['user']['date_created']) + " ago");
|
||||
writeClass('last_used', respData['user']['last_used'] + "<br>" + timeSinceString(respData['user']['last_used']) + " ago");
|
||||
writeValue('user_color', respData['user']['user_color']);
|
||||
if (user_color) user_color.parentElement.style.color = "" + respData['user']['user_color'];
|
||||
writeValue('user_name', respData['user']['user_name']);
|
||||
writeValue('avatar_url', respData['user']['avatar_url']);
|
||||
if (respData['room']) {
|
||||
writeValue('tv_url', respData['room']['tv_url']);
|
||||
writeValue('carpet_color', respData['room']['carpet_color']);
|
||||
if (carpet_color) carpet_color.parentElement.style.color = "" + respData['room']['carpet_color'];
|
||||
}
|
||||
writeClass('hw_id', respData['device']['hw_id']);
|
||||
writeClass('pairing_code', respData['device']['pairing_code']);
|
||||
writeValue('current_app', respData['device']['current_app']);
|
||||
writeValue('current_room', respData['device']['current_room']);
|
||||
writeClass('date_created', respData['device']['date_created'] + "<br>" + timeSinceString(respData['device']['date_created']) + " ago");
|
||||
writeClass('last_modified', respData['device']['last_modified'] + "<br>" + timeSinceString(respData['device']['last_modified']) + " ago");
|
||||
writeValue('user_name', respData['device']['friendly_name']);
|
||||
writeValue('avatar_url', respData['device']['data']?.['avatar_url']);
|
||||
writeValue('tv_url', respData['room']?.['data']?.['tv_url']);
|
||||
writeValue('carpet_color', respData['room']?.['data']?.['carpet_color']);
|
||||
if (carpet_color) carpet_color.parentElement.style.color = "" + respData['room']?.['data']?.['carpet_color'];
|
||||
|
||||
|
||||
Coloris({
|
||||
|
|
@ -271,45 +294,61 @@
|
|||
failure.style.display = "block";
|
||||
});
|
||||
|
||||
function setUserData(data) {
|
||||
data["sender_id"] = "web";
|
||||
httpPostAsync('/api/set_headset_details/' + hw_id,
|
||||
data,
|
||||
(resp) => {
|
||||
console.log('success');
|
||||
|
||||
function setDeviceField(data) {
|
||||
fetch('/api/v2/device/set_data/' + hw_id, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
(status) => {
|
||||
console.log('fail');
|
||||
}
|
||||
);
|
||||
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(_ => console.log('success'))
|
||||
.catch(_ => console.log('fail'));
|
||||
}
|
||||
|
||||
function setDeviceData(data) {
|
||||
fetch('/api/v2/device/set_data/' + hw_id, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
|
||||
body: JSON.stringify({"data": data})
|
||||
})
|
||||
.then(_ => console.log('success'))
|
||||
.catch(_ => console.log('fail'));
|
||||
}
|
||||
|
||||
function setRoomData(data) {
|
||||
data["sender_id"] = "web";
|
||||
httpPostAsync('/api/set_room_details/' + current_room.value,
|
||||
data,
|
||||
(resp) => {
|
||||
console.log('success');
|
||||
fetch('/api/v2/set_data/' + current_app.value + "_" + current_room.value, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
(status) => {
|
||||
console.log('fail');
|
||||
}
|
||||
);
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(_ => console.log('success'))
|
||||
.catch(_ => console.log('fail'));
|
||||
}
|
||||
|
||||
if (set_room_id) {
|
||||
set_room_id.addEventListener('click', () => {
|
||||
setUserData({"current_room": current_room.value});
|
||||
setDeviceField({"current_room": current_room.value});
|
||||
});
|
||||
}
|
||||
if (set_user_color) {
|
||||
set_user_color.addEventListener('click', () => {
|
||||
setUserData({"user_color": document.getElementById('user_color').value});
|
||||
setDeviceData({"user_color": document.getElementById('user_color').value});
|
||||
});
|
||||
}
|
||||
if (set_user_name) {
|
||||
set_user_name.addEventListener('click', () => {
|
||||
setUserData({"user_name": document.getElementById('user_name').value});
|
||||
setDeviceField({"friendly_name": document.getElementById('user_name').value});
|
||||
});
|
||||
}
|
||||
if (set_tv_url) {
|
||||
|
|
@ -324,7 +363,7 @@
|
|||
}
|
||||
if (set_avatar_url) {
|
||||
set_avatar_url.addEventListener('click', () => {
|
||||
setUserData({"avatar_url": document.getElementById('avatar_url').value});
|
||||
setDeviceData({"avatar_url": document.getElementById('avatar_url').value});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -351,6 +390,84 @@
|
|||
});
|
||||
|
||||
|
||||
const roomName = (Math.random() + 1).toString(36).substring(7);
|
||||
const pubVideo = document.getElementById("pub_video");
|
||||
const subVideo = document.getElementById("sub_video");
|
||||
const bntPubCam = document.getElementById("bnt_pubcam");
|
||||
const bntPubScreen = document.getElementById("bnt_pubscreen");
|
||||
|
||||
setDeviceData({"streamer_stream_id": roomName});
|
||||
|
||||
const serverURL = "wss://velnet.ugavel.com/ws";
|
||||
|
||||
const config = {
|
||||
iceServers: [
|
||||
{
|
||||
urls: "stun:stun.l.google.com:19302",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const signalLocal = new Signal.IonSFUJSONRPCSignal(serverURL);
|
||||
const clientLocal = new IonSDK.Client(signalLocal, config);
|
||||
|
||||
signalLocal.onopen = () => clientLocal.join(roomName);
|
||||
|
||||
const start = (type) => {
|
||||
if (type) {
|
||||
IonSDK.LocalStream.getUserMedia({
|
||||
resolution: "vga",
|
||||
audio: true,
|
||||
video: true,
|
||||
codec: "vp8",
|
||||
}).then((media) => {
|
||||
pubVideo.srcObject = media;
|
||||
pubVideo.autoplay = true;
|
||||
pubVideo.controls = true;
|
||||
pubVideo.muted = true;
|
||||
bntPubCam.disabled = true;
|
||||
bntPubScreen.disabled = true;
|
||||
clientLocal.publish(media);
|
||||
}).catch(console.error);
|
||||
} else {
|
||||
IonSDK.LocalStream.getDisplayMedia({
|
||||
audio: true,
|
||||
video: true,
|
||||
codec: "vp8",
|
||||
}).then((media) => {
|
||||
pubVideo.srcObject = media;
|
||||
pubVideo.autoplay = true;
|
||||
pubVideo.controls = true;
|
||||
pubVideo.muted = true;
|
||||
bntPubCam.disabled = true;
|
||||
bntPubScreen.disabled = true;
|
||||
clientLocal.publish(media);
|
||||
}).catch(console.error);
|
||||
}
|
||||
}
|
||||
|
||||
clientLocal.ontrack = (track, stream) => {
|
||||
console.log("got track: ", track.id, "for stream: ", stream.id);
|
||||
stream.mute();
|
||||
stream.unmute();
|
||||
if (track.kind === "video") {
|
||||
subVideo.srcObject = stream;
|
||||
subVideo.play();
|
||||
}
|
||||
//track.onunmute = () => {
|
||||
//subVideo.srcObject = stream;
|
||||
//subVideo.autoplay = true;
|
||||
//subVideo.muted = true;
|
||||
|
||||
//subVideo.play();
|
||||
|
||||
//stream.onremovetrack = () => {
|
||||
//subVideo.srcObject = null;
|
||||
//}
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -45,48 +45,48 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- <div class="hero bg-gray">
|
||||
<div class="hero-body">
|
||||
<h1>Pair your headset.</h1>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="container">
|
||||
<!-- <div class="hero bg-gray">
|
||||
<div class="hero-body">
|
||||
<h1>Pair your headset.</h1>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-image">
|
||||
<img src="/static/img/pair_code_screenshot.png" class="img-responsive">
|
||||
</div>
|
||||
<div class="card-header">
|
||||
<div class="card-title h5">Enter Pairing Code</div>
|
||||
<div class="card-subtitle text-gray"></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
You can find the code in the bottom left of your menu tablet in conVRged.
|
||||
</div>
|
||||
<div class="card-footer centered">
|
||||
<input class="btn" type="text" id="pair_code" placeholder="0000">
|
||||
<button class="btn btn-primary" id="submit_pairing_code">Submit</button>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-image">
|
||||
<img src="/static/img/pair_code_screenshot.png" class="img-responsive">
|
||||
</div>
|
||||
<div class="card-header">
|
||||
<div class="card-title h5">Enter Pairing Code</div>
|
||||
<div class="card-subtitle text-gray"></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
You can find the code in the bottom left of your menu tablet in conVRged.
|
||||
</div>
|
||||
<div class="card-footer centered">
|
||||
<input class="btn" type="text" id="pair_code" placeholder="0000">
|
||||
<button class="btn btn-primary" id="submit_pairing_code">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
|
||||
let submit_button = document.getElementById('submit_pairing_code');
|
||||
let pair_code_input = document.getElementById('pair_code');
|
||||
submit_button.addEventListener('click', () => {
|
||||
httpGetAsync('/api/pair_headset/' + pair_code_input.value, (resp) => {
|
||||
console.log(resp);
|
||||
let respData = JSON.parse(resp);
|
||||
if (respData['hw_id'] != '') {
|
||||
setCookie('hw_id', respData['hw_id'], 60);
|
||||
window.location.href = "/";
|
||||
}
|
||||
}, (status) => {
|
||||
window.location.href = "/failure";
|
||||
});
|
||||
let submit_button = document.getElementById('submit_pairing_code');
|
||||
let pair_code_input = document.getElementById('pair_code');
|
||||
submit_button.addEventListener('click', () => {
|
||||
httpGetAsync('/api/v2/get_device_by_pairing_code/' + pair_code_input.value, (resp) => {
|
||||
console.log(resp);
|
||||
let respData = JSON.parse(resp);
|
||||
if (respData['hw_id'] !== '') {
|
||||
setCookie('hw_id', respData['hw_id'], 60);
|
||||
window.location.href = "/";
|
||||
}
|
||||
}, (status) => {
|
||||
window.location.href = "/failure";
|
||||
});
|
||||
</script>
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Reference in New Issue