protected SpeckleObject ToSpeckle(IBHoMObject bhomObject, SpecklePushConfig config) { // Assign SpeckleStreamId to the Fragments of the IBHoMObjects SetAdapterId(bhomObject, SpeckleClient.Stream.StreamId); // SpeckleObject "container". Top level has geometry representation of BHoM Object, so it can be visualised in the SpeckleViewer. SpeckleObject speckleObject = SpeckleRepresentation(bhomObject, config.RendermeshOptions); // If no Speckle representation is found, it will be sent as an "Abstract" SpeckleObject (no visualisation). if (speckleObject == null) { speckleObject = (SpeckleObject)SpeckleCore.Converter.Serialise(bhomObject); } // Save BHoMObject data inside the speckleObject. Modify.SetBHoMData(speckleObject, bhomObject, config.UseSpeckleSerialiser); speckleObject.SetDiffingHash(bhomObject, config); // If the BHoMObject has a "RevisionName" string field in the Customdata, // use that value to create a Layer for it, and set the SpeckleObject's layer. //object revisionValue = null; //string revisionName = ""; //if (bhomObject.CustomData.TryGetValue("RevisionName", out revisionValue)) //{ // revisionName = revisionValue as string; // if (!string.IsNullOrWhiteSpace(revisionName)) // speckleObject.Properties["revisionName"] = revisionName; //} return(speckleObject); }
public override List <object> Push(IEnumerable <object> objects, string tag = "", PushType pushType = PushType.AdapterDefault, ActionConfig actionConfig = null) { // Clone objects for immutability in the UI List <object> objectsToPush = objects.Select(x => x.DeepClone()).ToList(); // Initialize the SpeckleStream SpeckleClient.Stream.Objects = new List <SpeckleObject>(); // stream is immutable // //- Read config SpecklePushConfig pushConfig = (actionConfig as SpecklePushConfig) ?? new SpecklePushConfig(); // //- Use "Speckle" history: produces a new stream at every push that corresponds to the old version. Enabled by default. if (pushConfig.EnableHistory) { SetupHistory(); } // Actual creation and add to the stream for (int i = 0; i < objectsToPush.Count(); i++) { SpeckleObject speckleObject = ToSpeckle(objectsToPush[i] as dynamic, pushConfig); // Dynamic dispatch to most appropriate method // Add objects to the stream SpeckleClient.Stream.Objects.Add(speckleObject); } // // - Send the objects try { // Try the batch upload BatchUpdateStream(pushConfig); } catch (Exception e) { try { // If the batch upload fails, try the standard SpeckleCore Update as a last resort. //// - Issue: with `StreamUpdateAsync` Speckle doesn't seem to send anything if the Stream is initially empty. //// - You need to Push twice if the Stream is initially empty. var updateResponse = SpeckleClient.StreamUpdateAsync(SpeckleClient.Stream.StreamId, SpeckleClient.Stream).Result; SpeckleClient.BroadcastMessage("stream", SpeckleClient.Stream.StreamId, new { eventType = "update-global" }); } catch { // If all has failed, return the first error. BH.Engine.Reflection.Compute.RecordError($"Upload to Speckle failed. Message returned:\n{e.InnerException.Message}"); return(new List <object>()); } } return(objectsToPush); }
protected SpeckleObject ToSpeckle(IObject iObject, SpecklePushConfig config) { // Convert the objects into the appropriate SpeckleObject using the available converters. SpeckleObject speckleObject = null; if (typeof(IGeometry).IsAssignableFrom(iObject.GetType())) { speckleObject = Speckle.Convert.IToSpeckle((IGeometry)iObject); } if (speckleObject == null) { BH.oM.Graphics.RenderMesh rm = null; try { rm = BH.Engine.Representation.Compute.IRenderMesh(iObject); } catch { BH.Engine.Reflection.Compute.RecordNote($"Could not compute the representation for an object of type {iObject.GetType().Name}.\n" + $"This simply means that the object will not be viewable in the browser (SpeckleViewer)."); } if (rm != null) { speckleObject = Speckle.Convert.ToSpeckle(rm); } else { speckleObject = (SpeckleObject)SpeckleCore.Converter.Serialise(iObject); // These will be exported as `Abstract` Speckle Objects. } } // Save BHoMObject data inside the speckleObject. Modify.SetBHoMData(speckleObject, iObject, config.UseSpeckleSerialiser); speckleObject.SetDiffingHash(iObject, config); return(speckleObject); }
public static void SetDiffingHash(this SpeckleObject speckleObject, IObject sourceObj, SpecklePushConfig config) { // SETTING THE HASH(ES) // SpeckleObjects have 2 hash properties: `Hash` and `GeometryHash`. // `Hash` is the "main" one, on which Speckle bases its diffing. // Therefore, what we want is that `Hash` should be set based only on the BHoM class properties - // not on any Speckle Object property, because we use the SpeckleObject only as a Representational container for our BHoMObject. // This way objects from BHoM can be diffed by the Speckle Server the same way we would diff them on the client side. // HOWEVER // This poses an issue with the fact tha speckle will not update the view in SpeckleViewer if only changes to the object REPRESENTATION are made. // E.g. If at some point I change how I want to see the bars, from 'extruded' to 'simple line', // then SpeckleViewer will not update the view (bars will stay extruded); // only newly pushed bars will be simple lines. // This is because Speckle really does not make any use of the `GeometryHash`: speckleObject.GeometryHash = speckleObject.Hash; // this is unfortunately useless; Speckle doesn't use it. // Set the "main" speckle hash equal to the diffing hash, so Speckle can do the diffing as we expect. string diffingHash = BH.Engine.Diffing.Compute.DiffingHash(sourceObj, config.DiffConfig); speckleObject.Hash = diffingHash; // FOR DEVELOPMENT ONLY: if (config.UniqueRandomHash) { speckleObject.Hash += speckleObject.GeometryHash + System.DateTime.Now.Ticks; } }
public void BatchUpdateStream(SpecklePushConfig pushConfig) { List <SpeckleObject> convertedObjects = SpeckleClient.Stream.Objects; SpeckleCore.SpeckleInitializer.Initialize(); SpeckleCore.LocalContext.Init(); LocalContext.PruneExistingObjects(convertedObjects, SpeckleClient.BaseUrl); List <SpeckleObject> persistedObjects = new List <SpeckleObject>(); OrderedDictionary JobQueue = new OrderedDictionary(); if (convertedObjects.Count(obj => obj.Type == "Placeholder") != convertedObjects.Count) { // create the update payloads int count = 0; var objectUpdatePayloads = new List <List <SpeckleObject> >(); long totalBucketSize = 0; long currentBucketSize = 0; var currentBucketObjects = new List <SpeckleObject>(); var allObjects = new List <SpeckleObject>(); foreach (SpeckleObject convertedObject in convertedObjects) { if (count++ % 100 == 0) { //Message = "Converted " + count + " objects out of " + convertedObjects.Count() + "."; } // size checking & bulk object creation payloads creation long size = Converter.getBytes(convertedObject).Length; currentBucketSize += size; totalBucketSize += size; currentBucketObjects.Add(convertedObject); // Object is too big? if (size > 2e6) { BH.Engine.Reflection.Compute.RecordWarning("An object is too big for the current Speckle limitations."); currentBucketObjects.Remove(convertedObject); } if (currentBucketSize > 3e5) // restrict max to ~300kb; { //BH.Engine.Reflection.Compute.RecordNote("Reached payload limit. Making a new one, current #: " + objectUpdatePayloads.Count); objectUpdatePayloads.Add(currentBucketObjects); currentBucketObjects = new List <SpeckleObject>(); currentBucketSize = 0; } } // add in the last bucket if (currentBucketObjects.Count > 0) { objectUpdatePayloads.Add(currentBucketObjects); } if (objectUpdatePayloads.Count > 1) { BH.Engine.Reflection.Compute.RecordNote($"Payload has been split in { objectUpdatePayloads.Count } batches. Total size is {totalBucketSize / 1024} kB."); } // create bulk object creation tasks List <ResponseObject> responses = new List <ResponseObject>(); foreach (var payload in objectUpdatePayloads) { //Message = String.Format("{0}/{1}", k++, objectUpdatePayloads.Count); try { var objResponse = SpeckleClient.ObjectCreateAsync(payload).Result; responses.Add(objResponse); persistedObjects.AddRange(objResponse.Resources); int m = 0; foreach (var oL in payload) { oL._id = objResponse.Resources[m++]._id; } // push sent objects in the cache non-blocking Task.Run(() => { foreach (var oL in payload) { if (oL.Type != "Placeholder") { LocalContext.AddSentObject(oL, SpeckleClient.BaseUrl); } } }); } catch (Exception err) { BH.Engine.Reflection.Compute.RecordWarning(err.Message); continue; } } } else { persistedObjects = convertedObjects; } // create placeholders for stream update payload List <SpeckleObject> placeholders = new List <SpeckleObject>(); //foreach ( var myResponse in responses ) foreach (var obj in persistedObjects) { placeholders.Add(new SpecklePlaceholder() { _id = obj._id }); } SpeckleClient.Stream.Objects = placeholders; // set some base properties (will be overwritten) var baseProps = new Dictionary <string, object>(); baseProps["units"] = "m"; baseProps["tolerance"] = "0.001"; baseProps["angleTolerance"] = "0.01"; SpeckleClient.Stream.BaseProperties = baseProps; var response = SpeckleClient.StreamUpdateAsync(SpeckleClient.StreamId, SpeckleClient.Stream).Result; SpeckleClient.BroadcastMessage("stream", SpeckleClient.StreamId, new { eventType = "update-global" }); }
protected SpeckleObject ToSpeckle(object obj, SpecklePushConfig config) { // Convert the objects into "Abstract" SpeckleObjects return(SpeckleCore.Converter.Serialise(obj) as SpeckleObject); }