OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
FSAssetService.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Diagnostics;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.IO.Compression;
33 using System.Text;
34 using System.Threading;
35 using System.Reflection;
36 using OpenSim.Data;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Serialization.External;
39 using OpenSim.Framework.Console;
40 using OpenSim.Server.Base;
41 using OpenSim.Services.Base;
42 using OpenSim.Services.Interfaces;
43 using Nini.Config;
44 using log4net;
45 using OpenMetaverse;
46 using System.Security.Cryptography;
47 
48 namespace OpenSim.Services.FSAssetService
49 {
51  {
52  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 
54  static System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
55  static SHA256CryptoServiceProvider SHA256 = new SHA256CryptoServiceProvider();
56 
57  static byte[] ToCString(string s)
58  {
59  byte[] ret = enc.GetBytes(s);
60  Array.Resize(ref ret, ret.Length + 1);
61  ret[ret.Length - 1] = 0;
62 
63  return ret;
64  }
65 
66  protected IAssetLoader m_AssetLoader = null;
67  protected IFSAssetDataPlugin m_DataConnector = null;
70  protected Thread m_StatsThread;
71  protected string m_SpoolDirectory;
72  protected object m_readLock = new object();
73  protected object m_statsLock = new object();
74  protected int m_readCount = 0;
75  protected int m_readTicks = 0;
76  protected int m_missingAssets = 0;
77  protected int m_missingAssetsFS = 0;
78  protected string m_FSBase;
79  protected bool m_useOsgridFormat = false;
80 
81  private static bool m_Initialized;
82  private bool m_MainInstance;
83 
84  public FSAssetConnector(IConfigSource config)
85  : this(config, "AssetService")
86  {
87  }
88 
89  public FSAssetConnector(IConfigSource config, string configName) : base(config)
90  {
91  if (!m_Initialized)
92  {
93  m_Initialized = true;
94  m_MainInstance = true;
95 
96  MainConsole.Instance.Commands.AddCommand("fs", false,
97  "show assets", "show assets", "Show asset stats",
98  HandleShowAssets);
99  MainConsole.Instance.Commands.AddCommand("fs", false,
100  "show digest", "show digest <ID>", "Show asset digest",
101  HandleShowDigest);
102  MainConsole.Instance.Commands.AddCommand("fs", false,
103  "delete asset", "delete asset <ID>",
104  "Delete asset from database",
105  HandleDeleteAsset);
106  MainConsole.Instance.Commands.AddCommand("fs", false,
107  "import", "import <conn> <table> [<start> <count>]",
108  "Import legacy assets",
109  HandleImportAssets);
110  MainConsole.Instance.Commands.AddCommand("fs", false,
111  "force import", "force import <conn> <table> [<start> <count>]",
112  "Import legacy assets, overwriting current content",
113  HandleImportAssets);
114  }
115 
116  IConfig assetConfig = config.Configs[configName];
117 
118  if (assetConfig == null)
119  throw new Exception("No AssetService configuration");
120 
121  // Get Database Connector from Asset Config (If present)
122  string dllName = assetConfig.GetString("StorageProvider", string.Empty);
123  string connectionString = assetConfig.GetString("ConnectionString", string.Empty);
124  string realm = assetConfig.GetString("Realm", "fsassets");
125 
126  int SkipAccessTimeDays = assetConfig.GetInt("DaysBetweenAccessTimeUpdates", 0);
127 
128  // If not found above, fallback to Database defaults
129  IConfig dbConfig = config.Configs["DatabaseService"];
130 
131  if (dbConfig != null)
132  {
133  if (dllName == String.Empty)
134  dllName = dbConfig.GetString("StorageProvider", String.Empty);
135 
136  if (connectionString == String.Empty)
137  connectionString = dbConfig.GetString("ConnectionString", String.Empty);
138  }
139 
140  // No databse connection found in either config
141  if (dllName.Equals(String.Empty))
142  throw new Exception("No StorageProvider configured");
143 
144  if (connectionString.Equals(String.Empty))
145  throw new Exception("Missing database connection string");
146 
147  // Create Storage Provider
148  m_DataConnector = LoadPlugin<IFSAssetDataPlugin>(dllName);
149 
150  if (m_DataConnector == null)
151  throw new Exception(string.Format("Could not find a storage interface in the module {0}", dllName));
152 
153  // Initialize DB And perform any migrations required
154  m_DataConnector.Initialise(connectionString, realm, SkipAccessTimeDays);
155 
156  // Setup Fallback Service
157  string str = assetConfig.GetString("FallbackService", string.Empty);
158 
159  if (str != string.Empty)
160  {
161  object[] args = new object[] { config };
162  m_FallbackService = LoadPlugin<IAssetService>(str, args);
163  if (m_FallbackService != null)
164  {
165  m_log.Info("[FSASSETS]: Fallback service loaded");
166  }
167  else
168  {
169  m_log.Error("[FSASSETS]: Failed to load fallback service");
170  }
171  }
172 
173  // Setup directory structure including temp directory
174  m_SpoolDirectory = assetConfig.GetString("SpoolDirectory", "/tmp");
175 
176  string spoolTmp = Path.Combine(m_SpoolDirectory, "spool");
177 
178  Directory.CreateDirectory(spoolTmp);
179 
180  m_FSBase = assetConfig.GetString("BaseDirectory", String.Empty);
181  if (m_FSBase == String.Empty)
182  {
183  m_log.ErrorFormat("[FSASSETS]: BaseDirectory not specified");
184  throw new Exception("Configuration error");
185  }
186 
187  m_useOsgridFormat = assetConfig.GetBoolean("UseOsgridFormat", m_useOsgridFormat);
188 
189  if (m_MainInstance)
190  {
191  string loader = assetConfig.GetString("DefaultAssetLoader", string.Empty);
192  if (loader != string.Empty)
193  {
194  m_AssetLoader = LoadPlugin<IAssetLoader>(loader);
195  string loaderArgs = assetConfig.GetString("AssetLoaderArgs", string.Empty);
196  m_log.InfoFormat("[FSASSETS]: Loading default asset set from {0}", loaderArgs);
197  m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs,
198  delegate(AssetBase a)
199  {
200  Store(a, false);
201  });
202  }
203 
204  m_WriterThread = new Thread(Writer);
205  m_WriterThread.Start();
206  m_StatsThread = new Thread(Stats);
207  m_StatsThread.Start();
208  }
209 
210  m_log.Info("[FSASSETS]: FS asset service enabled");
211  }
212 
213  private void Stats()
214  {
215  while (true)
216  {
217  Thread.Sleep(60000);
218 
219  lock (m_statsLock)
220  {
221  if (m_readCount > 0)
222  {
223  double avg = (double)m_readTicks / (double)m_readCount;
224 // if (avg > 10000)
225 // Environment.Exit(0);
226  m_log.InfoFormat("[FSASSETS]: Read stats: {0} files, {1} ticks, avg {2:F2}, missing {3}, FS {4}", m_readCount, m_readTicks, (double)m_readTicks / (double)m_readCount, m_missingAssets, m_missingAssetsFS);
227  }
228  m_readCount = 0;
229  m_readTicks = 0;
230  m_missingAssets = 0;
231  m_missingAssetsFS = 0;
232  }
233  }
234  }
235 
236  private void Writer()
237  {
238  m_log.Info("[ASSET]: Writer started");
239 
240  while (true)
241  {
242  string[] files = Directory.GetFiles(m_SpoolDirectory);
243 
244  if (files.Length > 0)
245  {
246  int tickCount = Environment.TickCount;
247  for (int i = 0 ; i < files.Length ; i++)
248  {
249  string hash = Path.GetFileNameWithoutExtension(files[i]);
250  string s = HashToFile(hash);
251  string diskFile = Path.Combine(m_FSBase, s);
252  bool pathOk = false;
253 
254  // The cure for chicken bones!
255  while(true)
256  {
257  try
258  {
259  // Try to make the directory we need for this file
260  Directory.CreateDirectory(Path.GetDirectoryName(diskFile));
261  pathOk = true;
262  break;
263  }
264  catch (System.IO.IOException)
265  {
266  // Creating the directory failed. This can't happen unless
267  // a part of the path already exists as a file. Sadly the
268  // SRAS data contains such files.
269  string d = Path.GetDirectoryName(diskFile);
270 
271  // Test each path component in turn. If we can successfully
272  // make a directory, the level below must be the chicken bone.
273  while (d.Length > 0)
274  {
275  Console.WriteLine(d);
276  try
277  {
278  Directory.CreateDirectory(Path.GetDirectoryName(d));
279  }
280  catch (System.IO.IOException)
281  {
282  d = Path.GetDirectoryName(d);
283 
284  // We failed making the directory and need to
285  // go up a bit more
286  continue;
287  }
288 
289  // We succeeded in making the directory and (d) is
290  // the chicken bone
291  break;
292  }
293 
294  // Is the chicken alive?
295  if (d.Length > 0)
296  {
297  Console.WriteLine(d);
298 
299  FileAttributes attr = File.GetAttributes(d);
300 
301  if ((attr & FileAttributes.Directory) == 0)
302  {
303  // The chicken bone should be resolved.
304  // Return to writing the file.
305  File.Delete(d);
306  continue;
307  }
308  }
309  }
310  // Could not resolve, skipping
311  m_log.ErrorFormat("[ASSET]: Could not resolve path creation error for {0}", diskFile);
312  break;
313  }
314 
315  if (pathOk)
316  {
317  try
318  {
319  byte[] data = File.ReadAllBytes(files[i]);
320 
321  using (GZipStream gz = new GZipStream(new FileStream(diskFile + ".gz", FileMode.Create), CompressionMode.Compress))
322  {
323  gz.Write(data, 0, data.Length);
324  gz.Close();
325  }
326  File.Delete(files[i]);
327 
328  //File.Move(files[i], diskFile);
329  }
330  catch(System.IO.IOException e)
331  {
332  if (e.Message.StartsWith("Win32 IO returned ERROR_ALREADY_EXISTS"))
333  File.Delete(files[i]);
334  else
335  throw;
336  }
337  }
338  }
339 
340  int totalTicks = System.Environment.TickCount - tickCount;
341  if (totalTicks > 0) // Wrap?
342  {
343  m_log.InfoFormat("[ASSET]: Write cycle complete, {0} files, {1} ticks, avg {2:F2}", files.Length, totalTicks, (double)totalTicks / (double)files.Length);
344  }
345  }
346 
347  Thread.Sleep(1000);
348  }
349  }
350 
351  string GetSHA256Hash(byte[] data)
352  {
353  byte[] hash = SHA256.ComputeHash(data);
354 
355  return BitConverter.ToString(hash).Replace("-", String.Empty);
356  }
357 
358  public string HashToPath(string hash)
359  {
360  if (hash == null || hash.Length < 10)
361  return "junkyard";
362 
363  if (m_useOsgridFormat)
364  {
365  /*
366  * The code below is the OSGrid code.
367  */
368  return Path.Combine(hash.Substring(0, 3),
369  Path.Combine(hash.Substring(3, 3)));
370  }
371  else
372  {
373  /*
374  * The below is what core would normally use.
375  * This is modified to work in OSGrid, as seen
376  * above, because the SRAS data is structured
377  * that way.
378  */
379  return Path.Combine(hash.Substring(0, 2),
380  Path.Combine(hash.Substring(2, 2),
381  Path.Combine(hash.Substring(4, 2),
382  hash.Substring(6, 4))));
383  }
384  }
385 
386  private bool AssetExists(string hash)
387  {
388  string s = HashToFile(hash);
389  string diskFile = Path.Combine(m_FSBase, s);
390 
391  if (File.Exists(diskFile + ".gz") || File.Exists(diskFile))
392  return true;
393 
394  return false;
395  }
396 
397  public virtual bool[] AssetsExist(string[] ids)
398  {
399  UUID[] uuid = Array.ConvertAll(ids, id => UUID.Parse(id));
400  return m_DataConnector.AssetsExist(uuid);
401  }
402 
403  public string HashToFile(string hash)
404  {
405  return Path.Combine(HashToPath(hash), hash);
406  }
407 
408  public virtual AssetBase Get(string id)
409  {
410  string hash;
411 
412  return Get(id, out hash);
413  }
414 
415  private AssetBase Get(string id, out string sha)
416  {
417  string hash = string.Empty;
418 
419  int startTime = System.Environment.TickCount;
420  AssetMetadata metadata;
421 
422  lock (m_readLock)
423  {
424  metadata = m_DataConnector.Get(id, out hash);
425  }
426 
427  sha = hash;
428 
429  if (metadata == null)
430  {
431  AssetBase asset = null;
432  if (m_FallbackService != null)
433  {
434  asset = m_FallbackService.Get(id);
435  if (asset != null)
436  {
437  asset.Metadata.ContentType =
438  SLUtil.SLAssetTypeToContentType((int)asset.Type);
439  sha = GetSHA256Hash(asset.Data);
440  m_log.InfoFormat("[FSASSETS]: Added asset {0} from fallback to local store", id);
441  Store(asset);
442  }
443  }
444  if (asset == null)
445  {
446  // m_log.InfoFormat("[FSASSETS]: Asset {0} not found", id);
447  m_missingAssets++;
448  }
449  return asset;
450  }
451  AssetBase newAsset = new AssetBase();
452  newAsset.Metadata = metadata;
453  try
454  {
455  newAsset.Data = GetFsData(hash);
456  if (newAsset.Data.Length == 0)
457  {
458  AssetBase asset = null;
459  if (m_FallbackService != null)
460  {
461  asset = m_FallbackService.Get(id);
462  if (asset != null)
463  {
464  asset.Metadata.ContentType =
465  SLUtil.SLAssetTypeToContentType((int)asset.Type);
466  sha = GetSHA256Hash(asset.Data);
467  m_log.InfoFormat("[FSASSETS]: Added asset {0} from fallback to local store", id);
468  Store(asset);
469  }
470  }
471  if (asset == null)
472  m_missingAssetsFS++;
473  // m_log.InfoFormat("[FSASSETS]: Asset {0}, hash {1} not found in FS", id, hash);
474  else
475  {
476  // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
477  // Fix bad assets before sending them elsewhere
478  if (asset.Type == (int)AssetType.Object && asset.Data != null)
479  {
480  string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data));
481  asset.Data = Utils.StringToBytes(xml);
482  }
483  return asset;
484  }
485  }
486 
487  lock (m_statsLock)
488  {
489  m_readTicks += Environment.TickCount - startTime;
490  m_readCount++;
491  }
492 
493  // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
494  // Fix bad assets before sending them elsewhere
495  if (newAsset.Type == (int)AssetType.Object && newAsset.Data != null)
496  {
497  string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(newAsset.Data));
498  newAsset.Data = Utils.StringToBytes(xml);
499  }
500 
501  return newAsset;
502  }
503  catch (Exception exception)
504  {
505  m_log.Error(exception.ToString());
506  Thread.Sleep(5000);
507  Environment.Exit(1);
508  return null;
509  }
510  }
511 
512  public virtual AssetMetadata GetMetadata(string id)
513  {
514  string hash;
515  return m_DataConnector.Get(id, out hash);
516  }
517 
518  public virtual byte[] GetData(string id)
519  {
520  string hash;
521  if (m_DataConnector.Get(id, out hash) == null)
522  return null;
523 
524  return GetFsData(hash);
525  }
526 
527  public bool Get(string id, Object sender, AssetRetrieved handler)
528  {
529  AssetBase asset = Get(id);
530 
531  handler(id, sender, asset);
532 
533  return true;
534  }
535 
536  public byte[] GetFsData(string hash)
537  {
538  string spoolFile = Path.Combine(m_SpoolDirectory, hash + ".asset");
539 
540  if (File.Exists(spoolFile))
541  {
542  try
543  {
544  byte[] content = File.ReadAllBytes(spoolFile);
545 
546  return content;
547  }
548  catch
549  {
550  }
551  }
552 
553  string file = HashToFile(hash);
554  string diskFile = Path.Combine(m_FSBase, file);
555 
556  if (File.Exists(diskFile + ".gz"))
557  {
558  try
559  {
560  using (GZipStream gz = new GZipStream(new FileStream(diskFile + ".gz", FileMode.Open, FileAccess.Read), CompressionMode.Decompress))
561  {
562  using (MemoryStream ms = new MemoryStream())
563  {
564  byte[] data = new byte[32768];
565  int bytesRead;
566 
567  do
568  {
569  bytesRead = gz.Read(data, 0, 32768);
570  if (bytesRead > 0)
571  ms.Write(data, 0, bytesRead);
572  } while (bytesRead > 0);
573 
574  return ms.ToArray();
575  }
576  }
577  }
578  catch (Exception)
579  {
580  return new Byte[0];
581  }
582  }
583  else if (File.Exists(diskFile))
584  {
585  try
586  {
587  byte[] content = File.ReadAllBytes(diskFile);
588 
589  return content;
590  }
591  catch
592  {
593  }
594  }
595  return new Byte[0];
596 
597  }
598 
599  public virtual string Store(AssetBase asset)
600  {
601  return Store(asset, false);
602  }
603 
604  private string Store(AssetBase asset, bool force)
605  {
606  int tickCount = Environment.TickCount;
607  string hash = GetSHA256Hash(asset.Data);
608 
609  if (!AssetExists(hash))
610  {
611  string tempFile = Path.Combine(Path.Combine(m_SpoolDirectory, "spool"), hash + ".asset");
612  string finalFile = Path.Combine(m_SpoolDirectory, hash + ".asset");
613 
614  if (!File.Exists(finalFile))
615  {
616  // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
617  // Fix bad assets before storing on this server
618  if (asset.Type == (int)AssetType.Object && asset.Data != null)
619  {
620  string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data));
621  asset.Data = Utils.StringToBytes(xml);
622  }
623 
624  FileStream fs = File.Create(tempFile);
625 
626  fs.Write(asset.Data, 0, asset.Data.Length);
627 
628  fs.Close();
629 
630  File.Move(tempFile, finalFile);
631  }
632  }
633 
634  if (asset.ID == string.Empty)
635  {
636  if (asset.FullID == UUID.Zero)
637  {
638  asset.FullID = UUID.Random();
639  }
640  asset.ID = asset.FullID.ToString();
641  }
642  else if (asset.FullID == UUID.Zero)
643  {
644  UUID uuid = UUID.Zero;
645  if (UUID.TryParse(asset.ID, out uuid))
646  {
647  asset.FullID = uuid;
648  }
649  else
650  {
651  asset.FullID = UUID.Random();
652  }
653  }
654 
655  if (!m_DataConnector.Store(asset.Metadata, hash))
656  {
657  return UUID.Zero.ToString();
658  }
659  else
660  {
661  return asset.ID;
662  }
663  }
664 
665  public bool UpdateContent(string id, byte[] data)
666  {
667  return false;
668 
669 // string oldhash;
670 // AssetMetadata meta = m_DataConnector.Get(id, out oldhash);
671 //
672 // if (meta == null)
673 // return false;
674 //
675 // AssetBase asset = new AssetBase();
676 // asset.Metadata = meta;
677 // asset.Data = data;
678 //
679 // Store(asset);
680 //
681 // return true;
682  }
683 
684  public virtual bool Delete(string id)
685  {
686  m_DataConnector.Delete(id);
687 
688  return true;
689  }
690 
691  private void HandleShowAssets(string module, string[] args)
692  {
693  int num = m_DataConnector.Count();
694  MainConsole.Instance.Output(string.Format("Total asset count: {0}", num));
695  }
696 
697  private void HandleShowDigest(string module, string[] args)
698  {
699  if (args.Length < 3)
700  {
701  MainConsole.Instance.Output("Syntax: show digest <ID>");
702  return;
703  }
704 
705  string hash;
706  AssetBase asset = Get(args[2], out hash);
707 
708  if (asset == null || asset.Data.Length == 0)
709  {
710  MainConsole.Instance.Output("Asset not found");
711  return;
712  }
713 
714  int i;
715 
716  MainConsole.Instance.Output(String.Format("Name: {0}", asset.Name));
717  MainConsole.Instance.Output(String.Format("Description: {0}", asset.Description));
718  MainConsole.Instance.Output(String.Format("Type: {0}", asset.Type));
719  MainConsole.Instance.Output(String.Format("Content-type: {0}", asset.Metadata.ContentType));
720  MainConsole.Instance.Output(String.Format("Flags: {0}", asset.Metadata.Flags.ToString()));
721  MainConsole.Instance.Output(String.Format("FS file: {0}", HashToFile(hash)));
722 
723  for (i = 0 ; i < 5 ; i++)
724  {
725  int off = i * 16;
726  if (asset.Data.Length <= off)
727  break;
728  int len = 16;
729  if (asset.Data.Length < off + len)
730  len = asset.Data.Length - off;
731 
732  byte[] line = new byte[len];
733  Array.Copy(asset.Data, off, line, 0, len);
734 
735  string text = BitConverter.ToString(line);
736  MainConsole.Instance.Output(String.Format("{0:x4}: {1}", off, text));
737  }
738  }
739 
740  private void HandleDeleteAsset(string module, string[] args)
741  {
742  if (args.Length < 3)
743  {
744  MainConsole.Instance.Output("Syntax: delete asset <ID>");
745  return;
746  }
747 
748  AssetBase asset = Get(args[2]);
749 
750  if (asset == null || asset.Data.Length == 0)
751  {
752  MainConsole.Instance.Output("Asset not found");
753  return;
754  }
755 
756  m_DataConnector.Delete(args[2]);
757 
758  MainConsole.Instance.Output("Asset deleted");
759  }
760 
761  private void HandleImportAssets(string module, string[] args)
762  {
763  bool force = false;
764  if (args[0] == "force")
765  {
766  force = true;
767  List<string> list = new List<string>(args);
768  list.RemoveAt(0);
769  args = list.ToArray();
770  }
771  if (args.Length < 3)
772  {
773  MainConsole.Instance.Output("Syntax: import <conn> <table> [<start> <count>]");
774  }
775  else
776  {
777  string conn = args[1];
778  string table = args[2];
779  int start = 0;
780  int count = -1;
781  if (args.Length > 3)
782  {
783  start = Convert.ToInt32(args[3]);
784  }
785  if (args.Length > 4)
786  {
787  count = Convert.ToInt32(args[4]);
788  }
789  m_DataConnector.Import(conn, table, start, count, force, new FSStoreDelegate(Store));
790  }
791  }
792 
793  public AssetBase GetCached(string id)
794  {
795  return Get(id);
796  }
797  }
798 }
virtual bool Delete(string id)
Delete an asset
delegate string FSStoreDelegate(AssetBase asset, bool force)
virtual string Store(AssetBase asset)
Creates a new asset
bool UpdateContent(string id, byte[] data)
Update an asset's content
virtual byte[] GetData(string id)
Get an asset's data, ignoring the metadata.
AssetBase GetCached(string id)
Synchronously fetches an asset from the local cache only.
virtual AssetMetadata GetMetadata(string id)
Get an asset's metadata
virtual AssetBase Get(string id)
Get an asset synchronously.
sbyte Type
(sbyte) AssetType enum
Definition: AssetBase.cs:198
Ionic.Zlib.GZipStream GZipStream
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
FSAssetConnector(IConfigSource config, string configName)
bool Get(string id, Object sender, AssetRetrieved handler)
Get an asset synchronously or asynchronously (depending on whether it is locally cached) and fire a c...
virtual bool[] AssetsExist(string[] ids)
Check if assets exist in the database.
Interactive OpenSim region server
Definition: OpenSim.cs:55
Ionic.Zlib.CompressionMode CompressionMode
UUID FullID
Asset UUID
Definition: AssetBase.cs:168
delegate void AssetRetrieved(string id, Object sender, AssetBase asset)
string ID
Asset MetaData ID (transferring from UUID to string ID)
Definition: AssetBase.cs:177