Compare commits

...

7 Commits

Author SHA1 Message Date
Anton Franzluebbers 1b2aaaeeda bump version to v5 to prevent touching live version (probably would be fine), upgrade pb 2024-03-21 16:07:13 -04:00
Anton Franzluebbers 7e27468e4c move migrations to correct folder 2024-03-21 15:51:05 -04:00
Anton Franzluebbers d57501dbad bump go version in dockerfile 2024-03-21 15:29:11 -04:00
Anton Franzluebbers 48e55550c3 clean up old code, bump version 2024-03-21 14:48:04 -04:00
Anton Franzluebbers ad778a616b working on persistence for spawned objects 2024-03-20 16:51:30 -04:00
Anton Franzluebbers a68d12aab5 reworking persistence to be per-object, working on system to persist spawned objects 2024-03-08 16:15:17 -05:00
Anton Franzluebbers b16de5434d
Merge pull request #1 from velaboratory/main
Update dev with main
2024-03-08 16:13:52 -05:00
18 changed files with 809 additions and 3254 deletions

View File

@ -15,7 +15,7 @@ jobs:
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
- name: connect and pull
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd /home/ubuntu/VEL-Connect-v4/velconnect && git pull && docker compose -p velconnect-v4 up -d --build && exit"
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd /home/ubuntu/VEL-Connect-v5/velconnect && git pull && docker compose -p velconnect-v5 up -d --build && exit"
- name: cleanup
run: rm -rf ~/.ssh

21
.github/workflows/deploy_oracle_dev.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Deploy to VelNet Oracle server (DEV)
on:
push:
branches: ["dev"]
paths: ["velconnect/**"]
jobs:
run_pull:
name: Pull new version on Oracle
runs-on: ubuntu-latest
steps:
- name: install ssh keys
run: |
install -m 600 -D /dev/null ~/.ssh/id_rsa
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
- name: connect and pull
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd /home/ubuntu/VEL-Connect-dev/velconnect && git pull && docker compose -p velconnect-dev up -d --build && exit"
- name: cleanup
run: rm -rf ~/.ssh

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -7,7 +7,7 @@ title: Quick Start
1. [Install the package](/)
2. Add the VelConnectManager script to an object in your scene. If you transition between scenes in your application, mark the object as `DontDestroyOnLoad`
3. Set the `Vel Connect Url` field on the component to a valid velconnect server. `https://velconnect-v4.ugavel.com` is useful for VEL projects.
3. Set the `Vel Connect Url` field on the component to a valid velconnect server. `https://velconnect-v5.ugavel.com` is useful for VEL projects.
## Usage

View File

@ -71,7 +71,7 @@ namespace VELConnect
public class DataBlock
{
public readonly string id;
public string id;
public readonly DateTime created;
public readonly DateTime updated;
public string block_id;
@ -91,6 +91,34 @@ namespace VELConnect
}
}
public class PersistObject
{
public string id;
public readonly DateTime created;
public readonly DateTime updated;
public string app;
public string room;
public string network_id;
public bool spawned;
public string name;
public string data;
}
public class RecordList<T>
{
public int page;
public int perPage;
public int totalPages;
public int totalItems;
public List<T> items;
}
public class ComponentState
{
public int componentIdx;
public string state;
}
public class UserCount
{
[CanBeNull] public readonly string id;
@ -884,19 +912,24 @@ namespace VELConnect
}
}
public static void PostRequestCallback(string url, string postData, Dictionary<string, string> headers = null,
public static void PostRequestCallback(
string url,
string postData,
Dictionary<string, string> headers = null,
Action<string> successCallback = null,
Action<string> failureCallback = null)
Action<string> failureCallback = null,
string method = "POST"
)
{
instance.StartCoroutine(PostRequestCallbackCo(url, postData, headers, successCallback, failureCallback));
instance.StartCoroutine(PostRequestCallbackCo(url, postData, headers, successCallback, failureCallback, method));
}
private static IEnumerator PostRequestCallbackCo(string url, string postData,
Dictionary<string, string> headers = null, Action<string> successCallback = null,
Action<string> failureCallback = null)
Action<string> failureCallback = null, string method="POST")
{
UnityWebRequest webRequest = new UnityWebRequest(url, "POST");
UnityWebRequest webRequest = new UnityWebRequest(url, method);
byte[] bodyRaw = Encoding.UTF8.GetBytes(postData);
UploadHandlerRaw uploadHandler = new UploadHandlerRaw(bodyRaw);
webRequest.uploadHandler = uploadHandler;
@ -929,12 +962,41 @@ namespace VELConnect
webRequest.Dispose();
}
public static void SetDataBlock(string blockId, State.DataBlock dataBlock)
public static void SetDataBlock(State.DataBlock dataBlock, Action<State.DataBlock> successCallback = null)
{
PostRequestCallback(instance.velConnectUrl + "/api/collections/DataBlock/records", JsonConvert.SerializeObject(dataBlock, Formatting.None,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}), null, s =>
{
if (successCallback != null)
{
State.DataBlock resp = JsonConvert.DeserializeObject<State.DataBlock>(s);
successCallback?.Invoke(resp);
}
});
}
/// <summary>
/// Setting with a block ID will update the existing block, otherwise it will create a new one
/// </summary>
/// <param name="blockId"></param>
/// <param name="dataBlock"></param>
/// <param name="successCallback"></param>
public static void SetDataBlock([CanBeNull] string blockId, State.DataBlock dataBlock, Action<State.DataBlock> successCallback = null)
{
PostRequestCallback(instance.velConnectUrl + "/data_block/" + blockId, JsonConvert.SerializeObject(dataBlock, Formatting.None, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
}), null, s =>
{
if (successCallback != null)
{
State.DataBlock resp = JsonConvert.DeserializeObject<State.DataBlock>(s);
successCallback?.Invoke(resp);
}
});
}
public static void GetDataBlock(string blockId, Action<State.DataBlock> successCallback = null, Action<string> failureCallback = null)

View File

@ -0,0 +1,76 @@
using System;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;
using VelNet;
namespace VELConnect
{
public class VelConnectPersistenceManager : MonoBehaviour
{
public static VelConnectPersistenceManager instance;
private void Awake()
{
instance = this;
}
private void OnEnable()
{
VelNetManager.OnJoinedRoom += OnJoinedRoom;
}
private void OnDisable()
{
VelNetManager.OnJoinedRoom -= OnJoinedRoom;
}
private void OnJoinedRoom(string roomName)
{
// if we're the first to join this room
if (VelNetManager.Players.Count == 1)
{
VELConnectManager.GetRequestCallback(
VELConnectManager.VelConnectUrl +
$"/api/collections/PersistObject/records?filter=(app='{Application.productName}')",
s =>
{
VELConnectManager.RecordList<VELConnectManager.PersistObject> obj =
JsonConvert.DeserializeObject<VELConnectManager.RecordList<VELConnectManager.PersistObject>>(s);
obj.items = obj.items.Where(i => i.spawned && i.room == VelNetManager.Room).ToList();
foreach (VELConnectManager.PersistObject persistObject in obj.items)
{
if (string.IsNullOrEmpty(persistObject.data))
{
Debug.LogError("Persisted object has no data");
continue;
}
NetworkObject spawnedObj = VelNetManager.NetworkInstantiate(persistObject.name, Convert.FromBase64String(persistObject.data));
VelNetPersist persist = spawnedObj.GetComponent<VelNetPersist>();
persist.persistId = persistObject.id;
persist.LoadData(persistObject);
}
}, s => { Debug.LogError("Failed to get persisted spawned objects", this); });
}
}
// We don't need to register objects, because they will do that automatically when they spawn if they have the VelNetPersist component
// We need to unregister objects when they are destroyed because destroying could happen because we left the scene
public static void UnregisterObject(NetworkObject obj)
{
VelNetPersist[] persistedComponents = obj.GetComponents<VelNetPersist>();
if (persistedComponents.Length > 1)
{
Debug.LogError("NetworkObject has more than one VelNetPersist component");
}
foreach (VelNetPersist velNetPersist in persistedComponents)
{
velNetPersist.Delete();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 85006f287450ecc4caedd7925e1198e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,25 +1,27 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;
using VelNet;
namespace VELConnect
{
public class VelNetPersist : MonoBehaviour
public class VelNetPersist : NetworkComponent
{
public SyncState syncState;
private string Id => $"{Application.productName}_{VelNetManager.Room}_{syncState.networkObject.sceneNetworkId}_{syncState.networkObject.syncedComponents.IndexOf(syncState)}";
private const float interval = 5f;
private double nextUpdate;
private bool loading;
private const bool debugLogs = false;
public string persistId;
private void Update()
{
if (Time.timeAsDouble > nextUpdate && VelNetManager.InRoom && !loading)
{
nextUpdate = Time.timeAsDouble + interval + UnityEngine.Random.Range(0, interval);
if (syncState.networkObject.IsMine)
if (networkObject.IsMine)
{
Save();
}
@ -44,61 +46,140 @@ namespace VELConnect
private void Load()
{
loading = true;
if (debugLogs) Debug.Log($"[VelNetPersist] Loading {Id}");
if (syncState == null)
{
Debug.LogError("SyncState is null for Persist", this);
return;
}
if (syncState.networkObject == null)
{
Debug.LogError("Network Object is null for SyncState", syncState);
return;
}
VELConnectManager.GetDataBlock(Id, data =>
{
if (!data.data.TryGetValue("state", out string d))
{
Debug.LogError($"[VelNetPersist] Failed to parse {Id}");
return;
}
if (debugLogs) Debug.Log($"[VelNetPersist] Loading {name}");
if (syncState == null)
{
Debug.LogError("[VelNetPersist] Object doesn't exist anymore");
}
syncState.UnpackState(Convert.FromBase64String(d));
if (debugLogs) Debug.Log($"[VelNetPersist] Loaded {Id}");
loading = false;
}, s =>
if (networkObject.isSceneObject)
{
loading = false;
});
// It looks like a PocketBase bug is preventing full filtering from happening:
// $"/api/collections/PersistObject/records?filter=(app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}')",
VELConnectManager.GetRequestCallback(
VELConnectManager.VelConnectUrl +
$"/api/collections/PersistObject/records?filter=(app='{Application.productName}')",
s =>
{
VELConnectManager.RecordList<VELConnectManager.PersistObject> obj =
JsonConvert.DeserializeObject<VELConnectManager.RecordList<VELConnectManager.PersistObject>>(s);
obj.items = obj.items.Where(i => i.network_id == networkObject.sceneNetworkId.ToString() && i.room == VelNetManager.Room).ToList();
if (obj.items.Count < 1)
{
Debug.LogError("[VelNetPersist] No data found for " + name);
loading = false;
return;
}
else if (obj.items.Count > 1)
{
Debug.LogError(
$"[VelNetPersist] Multiple records found for app='{Application.productName}' && room='{VelNetManager.Room}' && network_id='{networkObject.sceneNetworkId}'. Using the first one.");
}
LoadData(obj.items.FirstOrDefault());
}, s => { loading = false; });
}
else
{
VELConnectManager.GetRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, s =>
{
VELConnectManager.PersistObject obj = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
LoadData(obj);
},
s => { loading = false; });
}
}
private void Save()
public void LoadData(VELConnectManager.PersistObject obj)
{
if (debugLogs) Debug.Log($"[VelNetPersist] Saving {Id}");
if (syncState == null)
if (string.IsNullOrEmpty(obj.data))
{
Debug.LogError("SyncState is null for Persist", this);
Debug.LogError($"[VelNetPersist] No data found for {name}");
loading = false;
return;
}
if (syncState.networkObject == null)
persistId = obj.id;
using BinaryReader reader = new BinaryReader(new MemoryStream(Convert.FromBase64String(obj.data)));
networkObject.UnpackState(reader);
if (debugLogs) Debug.Log($"[VelNetPersist] Loaded {name}");
loading = false;
}
public void Save(Action<VELConnectManager.PersistObject> successCallback = null)
{
if (debugLogs) Debug.Log($"[VelNetPersist] Saving {name}");
List<SyncState> syncStateComponents = networkObject.syncedComponents.OfType<SyncState>().ToList();
if (networkObject == null)
{
Debug.LogError("Network Object is null for SyncState", syncState);
Debug.LogError("NetworkObject is null on SyncState", this);
return;
}
VELConnectManager.SetDataBlock(Id, new VELConnectManager.State.DataBlock()
using BinaryWriter writer = new BinaryWriter(new MemoryStream());
networkObject.PackState(writer);
string data = Convert.ToBase64String(((MemoryStream)writer.BaseStream).ToArray());
// if we have a persistId, update the record, otherwise create a new one
if (string.IsNullOrEmpty(persistId))
{
category = "object_persist",
data = new Dictionary<string, string>
Debug.LogWarning($"We don't have an existing persistId, so we are creating a new record for {networkObject.name}");
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records", JsonConvert.SerializeObject(
new VELConnectManager.PersistObject()
{
app = Application.productName,
room = VelNetManager.Room,
network_id = networkObject.sceneNetworkId.ToString(),
spawned = !networkObject.isSceneObject,
name = networkObject.isSceneObject ? networkObject.name : networkObject.prefabName,
data = data,
}), null, s =>
{
{ "name", syncState.networkObject.name },
{ "state", Convert.ToBase64String(syncState.PackState()) }
}
});
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
persistId = resp.id;
successCallback?.Invoke(resp);
});
}
else
{
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, JsonConvert.SerializeObject(
new VELConnectManager.PersistObject()
{
app = Application.productName,
room = VelNetManager.Room,
network_id = networkObject.sceneNetworkId.ToString(),
spawned = !networkObject.isSceneObject,
name = networkObject.prefabName,
data = data,
}), null, s =>
{
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
successCallback?.Invoke(resp);
}, method: "PATCH");
}
}
public void Delete(Action<VELConnectManager.PersistObject> successCallback = null)
{
if (string.IsNullOrEmpty(persistId))
{
Debug.LogError("We can't delete an object that doesn't have a persistId");
return;
}
VELConnectManager.PostRequestCallback(VELConnectManager.VelConnectUrl + "/api/collections/PersistObject/records/" + persistId, null, null,
s =>
{
VELConnectManager.PersistObject resp = JsonConvert.DeserializeObject<VELConnectManager.PersistObject>(s);
successCallback?.Invoke(resp);
}, Debug.LogError,
method: "DELETE");
}
public override void ReceiveBytes(byte[] message)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,14 +1,14 @@
{
"name": "edu.uga.engr.vel.vel-connect",
"displayName": "VEL-Connect",
"version": "4.0.7",
"version": "5.0.0",
"unity": "2019.1",
"description": "Web-based configuration for VR applications",
"keywords": [],
"author": {
"name": "Virtual Experiences Laboratory",
"email": "velaboratory@gmail.com",
"url": "https://vel.engr.uga.edu/"
"url": "https://velaboratory.com/"
},
"samples": [],
"dependencies": {

View File

@ -7,7 +7,7 @@ type VelConnectOptions = {
};
export let pb: TypedPocketBase = new PocketBase(
"https://velconnect-v4.ugavel.com"
"https://velconnect-v5.ugavel.com"
) as TypedPocketBase;
let debugLog = false;
let initialized = false;
@ -19,7 +19,7 @@ export async function initVelConnect(options: VelConnectOptions = {}) {
if (!initialized) {
pb = new PocketBase(
options.url ? options.url : "https://velconnect-v4.ugavel.com"
options.url ? options.url : "https://velconnect-v5.ugavel.com"
) as TypedPocketBase;
log(`Initialized velconnect on ${pb.baseUrl}`);
}

View File

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM golang:1.21 as build
FROM golang:1.22 as build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download

View File

@ -1,88 +1,87 @@
module velaboratory/velconnect
go 1.18
go 1.22.1
require (
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
github.com/pocketbase/dbx v1.10.0
github.com/pocketbase/pocketbase v0.16.7
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
github.com/pocketbase/dbx v1.10.1
github.com/pocketbase/pocketbase v0.22.5
)
require (
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.44.289 // indirect
github.com/aws/aws-sdk-go-v2 v1.18.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.27 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.26 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.70 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.29 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/aws/aws-sdk-go v1.51.5 // indirect
github.com/aws/aws-sdk-go-v2 v1.26.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.9 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.9 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.6.0 // indirect
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/ganigeorgiev/fexpr v0.3.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/ganigeorgiev/fexpr v0.4.0 // indirect
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.5.0 // indirect
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.6.0 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect
gocloud.dev v0.30.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/image v0.8.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/oauth2 v0.9.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.10.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.128.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.56.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/ccgo/v3 v3.16.14 // indirect
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.6.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.23.1 // indirect
modernc.org/strutil v1.1.3 // indirect
gocloud.dev v0.37.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/image v0.15.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.170.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
google.golang.org/grpc v1.62.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
modernc.org/libc v1.47.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/sqlite v1.29.5 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@ import (
"encoding/json"
"log"
"net/http"
"os"
"strings"
_ "velaboratory/velconnect/pb_migrations"
@ -19,16 +21,18 @@ func main() {
app := pocketbase.New()
// loosely check if it was executed using "go run"
// isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
migratecmd.MustRegister(app, app.RootCmd, &migratecmd.Options{
// enable auto creation of migration files when making collection changes
migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{
// enable auto creation of migration files when making collection changes in the Admin UI
// (the isGoRun check is to enable it only during development)
Automigrate: true,
Automigrate: isGoRun,
})
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// or you can also use the shorter e.Router.GET("/articles/:slug", handler, middlewares...)
e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
e.Router.POST("/data_block/:block_id", func(c echo.Context) error {
dao := app.Dao()
@ -260,7 +264,7 @@ func main() {
}
}
func mergeDataBlock(requestData *models.RequestData, record *models.Record) {
func mergeDataBlock(requestData *models.RequestInfo, record *models.Record) {
// get the new data
newData, hasNewData := requestData.Data["data"]

View File

@ -0,0 +1,126 @@
package migrations
import (
"encoding/json"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/models"
)
func init() {
m.Register(func(db dbx.Builder) error {
jsonData := `{
"id": "zo5oymw0d6evw80",
"created": "2024-03-14 20:19:38.622Z",
"updated": "2024-03-14 20:19:38.622Z",
"name": "PersistObject",
"type": "base",
"system": false,
"schema": [
{
"system": false,
"id": "tvwuy2xt",
"name": "app",
"type": "text",
"required": true,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"system": false,
"id": "mj06ihfs",
"name": "room",
"type": "text",
"required": true,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"system": false,
"id": "mqw640xp",
"name": "network_id",
"type": "text",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"system": false,
"id": "f0wynbda",
"name": "data",
"type": "json",
"required": true,
"presentable": false,
"unique": false,
"options": {
"maxSize": 2000000
}
},
{
"system": false,
"id": "tqei9ccu",
"name": "spawned",
"type": "bool",
"required": false,
"presentable": false,
"unique": false,
"options": {}
},
{
"system": false,
"id": "sgkbflei",
"name": "name",
"type": "text",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
}
],
"indexes": [],
"listRule": "",
"viewRule": "",
"createRule": "",
"updateRule": "",
"deleteRule": null,
"options": {}
}`
collection := &models.Collection{}
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
return err
}
return daos.New(db).SaveCollection(collection)
}, func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("zo5oymw0d6evw80")
if err != nil {
return err
}
return dao.DeleteCollection(collection)
})
}

View File

@ -0,0 +1,76 @@
package migrations
import (
"encoding/json"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/models/schema"
)
func init() {
m.Register(func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("zo5oymw0d6evw80")
if err != nil {
return err
}
// remove
collection.Schema.RemoveField("f0wynbda")
// add
new_data := &schema.SchemaField{}
if err := json.Unmarshal([]byte(`{
"system": false,
"id": "9bremliu",
"name": "data",
"type": "text",
"required": true,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
}`), new_data); err != nil {
return err
}
collection.Schema.AddField(new_data)
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("zo5oymw0d6evw80")
if err != nil {
return err
}
// add
del_data := &schema.SchemaField{}
if err := json.Unmarshal([]byte(`{
"system": false,
"id": "f0wynbda",
"name": "data",
"type": "json",
"required": true,
"presentable": false,
"unique": false,
"options": {
"maxSize": 2000000
}
}`), del_data); err != nil {
return err
}
collection.Schema.AddField(del_data)
// remove
collection.Schema.RemoveField("9bremliu")
return dao.SaveCollection(collection)
})
}